[데이터분석] 부트캠프 TIL

20260114 TIL

myun0506 2026. 1. 14. 18:16

Today I Learn

: SQL 코드카타, 수업날 강의, 복습, 아티클 스터디

 

- SQL 코드카타

 

- 문제 1

1. 문제 링크: https://leetcode.com/problems/patients-with-a-condition/

2. 정답 코드:

select patient_id, patient_name, conditions
from Patients
where conditions like '%DIAB1%'
select patient_id, patient_name, conditions
from Patients
where conditions regexp '^DIAB1| DIAB1'
  • %DIAB1%만 사용하면 명확한 DIAB1을 찾지 못하고 다른 문자에 연결된 PEDIAB1과 같은 경우도 함께 조회함
    • 더 명확성 강화를 위해 DIAB1이 맨 처음 나오는 경우나 공백 다음에 나오는 경우로 한정해야함!
    • like or을 사용할 경우 더 경우의 수가 많아지면 쿼리가 과하게 길어질 수 있음
    • → regexp 사용!
      • ^ : 문자열 맨 처음에 위치
      • | : or 의미

- 문제 2

1. 문제 링크: https://www.hackerrank.com/challenges/revising-the-select-query/problem

2. 정답 코드:

select *
from CITY
where population > 100000 and countrycode = 'USA'

 

- 문제 3

1. 문제 링크: https://www.hackerrank.com/challenges/revising-the-select-query-2/problem

2. 정답 코드:

select name
from city
where countrycode = 'USA' and population > 120000

 

- 문제 4

1. 문제 링크: https://www.hackerrank.com/challenges/select-all-sql/problem

2. 정답 코드:

select *
from city

 

- 문제 5

1. 문제 링크: https://www.hackerrank.com/challenges/select-by-id/problem

2. 정답 코드:

select *
from city
where id = '1661'


- 문제 6

1. 문제 링크: https://www.hackerrank.com/challenges/japanese-cities-attributes/problem

2. 정답 코드:

select *
from city
where countrycode = 'JPN'


- 문제 7

1. 문제 링크: https://www.hackerrank.com/challenges/japanese-cities-name/problem

2. 정답 코드:

select name
from city 
where countrycode = 'JPN'

 

- 문제 8

1. 문제 링크: https://www.hackerrank.com/challenges/weather-observation-station-1/problem

2. 정답 코드:

select city, state 
from station

 

- 문제 9

1. 문제 링크: https://www.hackerrank.com/challenges/name-of-employees/problem

2. 정답 코드:

select name
from employee
order by name

 

- 문제 10

1. 문제 링크: https://www.hackerrank.com/challenges/salary-of-employees/problem

2. 정답 코드:

select name 
from employee
where salary > 2000 and months < 10
order by employee_id asc


- 문제 11

1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-the-count-function/problem

2. 정답 코드:

select count(*)
from city
where population > 100000


- 문제 12

1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-sum/problem

2. 정답 코드:

select sum(population)
from city
where district = 'California'


- 문제 13

1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-the-average-function/problem

2. 정답 코드:

select avg(population)
from city
where district = 'California'


- 문제 14

1. 문제 링크: https://www.hackerrank.com/challenges/average-population/problem

2. 정답 코드:

select round(avg(population),0)
from city


- 문제 15

1. 문제 링크: https://www.hackerrank.com/challenges/japan-population/problem

2. 정답 코드:

select sum(population)
from city 
where countrycode = 'JPN'


- 문제 16

1. 문제 링크: https://www.hackerrank.com/challenges/population-density-difference/problem

2. 정답 코드:

select max(population)-min(population)
from city

 

- 문제 17

1. 문제 링크: https://leetcode.com/problems/replace-employee-id-with-the-unique-identifier/submissions/1884409345/

2. 정답 코드:

select 
    u.unique_id, e.name
from employees e
left join employeeuni u
on e.id = u.id


- 문제 18

1. 문제 링크: https://leetcode.com/problems/product-sales-analysis-i/description/

2. 정답 코드:

select p.product_name, s.year, s.price
from sales s
join product p
on p.product_id = s.product_id

 

- 문제 19

1. 문제 링크: https://leetcode.com/problems/customer-who-visited-but-did-not-make-any-transactions/description/

2. 정답 코드:

select v.customer_id, count(*) as count_no_trans
from visits v 
left join transactions t 
on v.visit_id = t.visit_id 
where t.transaction_id is null
group by v.customer_id
select v.customer_id, count(*) as count_no_trans
from visits v 
where not exists (
    select 1
    from transactions t
    where t.visit_id = v.visit_id
)
group by v.customer_id
  • left join 을 하면 불필요하게 두 테이블을 합친 후 또 그 중에 is null 인 것만 추출하게 됨 (메모리 낭비)
    • → not exists를 사용해서 transactions 테이블에 없으면서 visits 에만 있는 행을 추출하기

 

- 문제 20

1. 문제 링크: https://leetcode.com/problems/rising-temperature/

2. 정답 코드: 

with selected as (
select 
    id, 
    temperature - lag(temperature,1,temperature) 
        over (order by recordDate) as difference
from weather
)
select id
from selected 
where difference > 0

 

3. 오류 상황: 하루 전의 데이터가 없을 경우, yesterday가 아니더라도 날짜 순서로 정렬했을 때 그 전 행에 해당하는 값을 불러오는 것이므로 문제 조건에 맞지 않음 (문제에선 yesterday 일 때 그 값이랑 비교하는 조건!)

4. 해결 방안: lag 윈도우 함수를 사용하지 말고 날짜 자체를 비교하는 함수를 사용해야함 (datediff / subdate)

select w1.id 
from weather w1
join weather w2
on datediff(w1.recorddate, w2.recorddate) = 1
where w1.temperature > w2.temperature
select w1.id 
from weather w1
join weather w2
on w2.recorddate = subdate(w1.recorddate,1)
where w1.temperature > w2.temperature
select w1.id
from weather w1
where exists (
    select 1
    from weather w2
    where w2.recordDate = subdate(w1.recordDate, 1) -- w2 : 날짜가 하루 전이고
    and w1.temperature > w2.temperature -- 온도가 더 낮은지 확인
)
  • where exists 함수 사용할 때
    • subdate(날짜, interval) : 날짜 보다 interval 이전인 날짜 리턴
    • → 하루 전 날짜 리턴

 

- 파이썬 수업날 복습 (클래스|파일)

 

- 함수만 쓸 때 vs 클래스를 쓸 때

  • 함수만 쓰면: 데이터랑 기능이 흩어져서 사람이 기억해야 하는 코드
  • 클래스 쓰면: 현실 세계처럼 물건 단위로 정리된 코드

- __init__ 생성자

  • 인스턴스가 생성될 때 자동으로 호출되는 메서드
  • 생성될 때 호출된다고 해서 생성자(constructor)라고도 불림

- 인스턴스 변수 (instance variable)

  • 각 객체마다 별도로 관리되는 변수
  • self.name, self.age와 같이 self를 통해 참조하는 변수
  • 각각 인스턴스 마다 각각 값을 가질 수 있음

- 클래스 변수 (class variable)

  • 클래스로부터 만들어진 모든 인스턴스가 공유하는 변수
  • 클래스 블록 내에서 self 없이 바로 변수를 정의하면 클래스 변수로 설정됨
class Car:
    wheels = 4  # 클래스 변수: 모든 Car 인스턴스는 바퀴가 4개
    def __init__(self, color):
        self.color = color  # 인스턴스 변수: 각 차마다 색이 다를 수 있음

car1 = Car("red")
car2 = Car("blue")

print(car1.color)  # "red" (car1만의 인스턴스 변수)
print(car2.color)  # "blue" (car2만의 인스턴스 변수)

print(car1.wheels) # 4 (클래스 변수는 모든 객체가 공유)
print(car2.wheels) # 4
  • car1.wheels = 3 를 하면
    • car1에만 새로운 인스턴스 변수를 만드는 것
    • Car.wheels 는 그대로 4임

- 인스턴스 메서드 (Instance Method)

  • 첫 번째 매개변수로 self 받음
  • 각 인스턴스에 대해서 동작하며, 인스턴스 변수를 다루는 데 주로 사용함
class Person:
    def __init__(self, name):
        self.name = name

    def say_hello(self): #인스턴스 메서드
        print(f"Hello, my name is {self.name}")

person1 = Person("alice")
person1.say_hello()

 

- 클래스 메서드 (Class Method)

  • 첫 번째 매개변수로 cls 받음 (self 대신 cls 키워드 사용)
  • 데코레이터 @classmethod 사용
  • 클래스 자체를 인자로 받음
  • 활용: 클래스 변수를 다루는 상황 / 새로운 인스턴스를 생성하는 메서드 등을 정의
class Person:
    count = 0

    def __init__(self, name):
        self.name = name
        Person.count += 1

    @classmethod
    def how_many(cls):
        print(f"지금까지 {cls.count}명이 만들어졌습니다.")

p1 = Person("Alice")
p2 = Person("Bob")
Person.how_many()  # "지금까지 2명이 만들어졌습니다."

 

- 정적 메서드 (Static Method)

  • 첫 번째 매개 변수로 self나 cls 받지 않음
  • 사실 클래스에 굳이 소속될 필요 없음. but '분류상' 틀에 넣어야 깔끔해서 넣는 것.
    (주로 클래스나 인스턴스 변수에 접근할 필요가 없는 경우)
  • 데코레이터 @staticmethod 사용
class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b

result = MathUtils.add(3, 5)
print(result)  # 8

 

 

- 접근 지정자와 캡슐화

  • Java나 C++의 접근 지정자(Public, Protected, Private)와 달리 파이썬에서는 안더스코어를 붙여 사용함
구분 Java / C++ (키워드 방식) Python (언더스코어 방식) 의미
Public public int age; self.age 누구나 접근 가능 (기본값)
Protected  protected int age; self._age [관례] 클래스 내부와 상속 관계에서만 쓰자고 약속함
Private private int age; self.__age [강제성 있음] 이름 변형을 통해 외부 접근을 막음

 

  • _variable (Weak Internal Use) 
    • 문법적으로는 Public과 똑같음. 밖에서 호출해도 에러 안남
    • '이건 이 클래스 내부 구현을 위한거니까, 밖에서 직접 수정하면 코드가 꼬일 수 있어.'라고 경고를 주는 것
  • __variable (Strong Private)
    • "이 변수는 이 클래스 내에서만 쓰겠다. 상속 받은 자식 클래스 조차도 함부로 못 건드리게 하겠다."
      • 자식 클래스에게 공유하고 싶다면 _ 하나만 쓰기!
    • Name Mangling이 일어남
      • self.__password라고 선언하면, 파이썬은 내부적으로 이름을 _ClassName__password로 바꿔버림
      • 외부에서 acc.__password라고 치면 '그런 이름은 없다'는 AttributeError 발생함
class BankAccount:
  def __init__(self, owner, balance, password):
    self.owner = owner
    self.__balance = balance # 이 변수는 직접 접근하기 어렵게 함
    self.__password = password

  def deposit(self,amount):
    self.__balance += amount

  def withdraw(self, amount):
    if self.__balance >= amount:
      self.__balance -= amount
    else:
      print("잔고 부족")
  
  def get_balance(self):
    return self.__balance
  
  def get_password(self):
    return self.__password 
  
  def change_password(self,pw):
    self.__password = pw
  
acc = BankAccount("Alice",1000,12345)
print(acc.get_balance())
acc.deposit(500)
print(acc.get_balance())
acc.withdraw(2000)
print(acc.get_balance())
print(acc.get_password())
acc.change_password(54321)
print(acc.get_password())
print(acc.owner)
print(acc._BankAccount__password) # name mangling

 

 

- 상속 (Inheritance)

  • 기존 클래스를 재사용하여 새로운 클래스를 만들 수 있게 하는 기능
  • 상속을 통해 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 변수 & 메서드를
    • 자식 클래스(서브 클래스)에서 물려 받을 수 있음
  • 필요하다면 물려받은걸 확장 또는 수정도 할 수 있음

- 다형성 (Polymorphism) & 오버라이딩 (Overriding)

  • 다형성
    • 같은 메서드 이름이 다양한 클래스에서 다른 형태로 동작할 수 있음을 의미
  • 오버라이딩
    • 자식 클래스에서 부모 클래스의 메서드를 재정의하는 것
class Animal:
    def speak(self):
        print("동물 소리")

class Cat(Animal):
    def speak(self):
        print("야옹")

class Dog(Animal):
    def speak(self):
        print("멍멍")

animals = [Cat(), Dog(), Animal()]
for a in animals:
    a.speak()
    # Cat 인스턴스 -> "야옹"
    # Dog 인스턴스 -> "멍멍"
    # Animal 인스턴스 -> "동물 소리"

 

 

- 실습 문제 1

class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  
  def move(self,dx,dy):
    self.x += dx
    self.y += dy
    return self

  def show(self):
    print(f"Point({self.x}, {self.y})")
  
p = Point(1,2)
p.move(2,3).show()

 

  • move 메서드에 return self 를 추가하여
    • move 의 결과값을 변수에 따로 저장할 필요 없이 
    • 한 줄로 p.move(2,3).show() 작성 

https://myun0506.tistory.com/57

 

클래스

- 함수만 쓸 때 vs 클래스를 쓸 때함수만 쓰면: 데이터랑 기능이 흩어져서 사람이 기억해야 하는 코드클래스 쓰면: 현실 세계처럼 물건 단위로 정리된 코드- __init__ 생성자인스턴스가 생성될 때

myun0506.tistory.com

 

 

- 파일 열기 (open 함수)

file_object = open("파일이름", "모드")

 

  • 주요 모드 종류
    • "r": 읽기 전용 모드(기본값). 해당 파일이 존재하지 않으면 에러 발생
    • "w": 쓰기 전용 모드. 파일이 존재하면 내용을 모두 지우고, 존재하지 않으면 새로 만듦
    • "a": 추가(append)모드. 파일의 끝에 새로운 내용을 덧붙임. 파일이 없으면 새로 만듦
    • "x": 쓰기 전용으로 새 파일을 만들기 위한 모드. 파일이 이미 존재하면 에러 발생
    • "r+": 읽기/쓰기 겸용 모드. 기존 파일에 대해 읽고 쓰기 모두 가능
    • "b": 바이너리 모드. "rb", "wb" 등의 형태로 다른 모드와 조합하여, 텍스트가 아닌 이미지, 음악 파일 등 이진 데이터 처리 시 사용
    • "t": 텍스트 모드(기본값). "r","w" 등이 기본적으로 "t" 모드임

- 파일 읽기

  • 읽기 모드("r")로 연 파일에 대해 다음과 같은 메서드를 사용해서 내용을 읽을 수 있음
    • read() : 파일 전체 내용을 문자열로 읽어옴
    • readline() : 파일에서 한 줄씩 읽어옴
    • readlines() : 파일 전체 내용을 한 줄씩 나누어 리스트로 반환
file = open("example.txt", "r", encoding="utf-8")  # UTF-8 인코딩 지정 가능
content = file.read()  # 파일 전체 읽기
print(content)

line = file.readline()  # 첫 번째 줄 읽기
print(line)
line = file.readline()  # 두 번째 줄 읽기
print(line)

lines = file.readlines()  # 모든 줄을 읽어 리스트로 반환
for l in lines:
    print(l.strip())  # strip()으로 양 끝 공백 제거
file.close()

 

- 파일 쓰기

  • 파일에 쓰기 위해서는 "w", "a", "r+", "x" 등 쓰기 기능이 지원되는 모드로 열어야 함
    • "w" 모드: 기존 내용을 모두 지우고 새로 쓰기 시작함
    • "a" 모드: 기존 파일의 끝에 내용을 이어 붙임

- with 문을 이용한 파일 처리

  • with 문 사용하면 블록이 끝날 때 자동으로 파일을 닫아주기 때문에 close()를 깜빡하는 실수를 방지할 수 있음
with open("example.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
    
# 여기서는 with 블록을 빠져나가면 f가 자동으로 close() 처리됩니다.

# 쓰기 예시
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("안녕하세요!\n")
    f.write("이 내용은 output.txt에 쓰여집니다.\n")

# with 블록 종료 시 자동으로 f.close() 호출

 

- 바이너리 파일 다루기

  • 이미지, 오디오, 영상, PDF 등 텍스트로 이루어지지 않은 파일은 바이너리 모드("b")로 열어야함
# 이미지 파일 복사 예제
with open("image.jpg", "rb") as src:
    data = src.read()

with open("copy.jpg", "wb") as dst:
    dst.write(data)
  • "rb"로 원본 이미지를 읽고, "wb"로 복사본 작성함
  • 텍스트 인코딩 관련 인자는 필요 없음

- 예외 처리

  • 파일이 존재하지 않거나 경로가 잘못된 경우
  • 권한 부족으로 파일을 열 수 없는 경우
  • 디스크 문제가 발생한 경우
  • → try-except 구문 사용
try:
    with open("nonexistent.txt", "r", encoding="utf-8") as f:
        data = f.read()
        print(data)
except FileNotFoundError:
    print("파일을 찾을 수 없습니다.")
except PermissionError:
    print("파일에 접근할 권한이 없습니다.")

 

https://myun0506.tistory.com/58

 

파일 열기/읽기/쓰기, 주요 모드, with문을 활용한 파일 처리, 예외처리

- 파일 열기 (open 함수)file_object = open("파일이름", "모드") 주요 모드 종류"r": 읽기 전용 모드(기본값). 해당 파일이 존재하지 않으면 에러 발생"w": 쓰기 전용 모드. 파일이 존재하면 내용을 모두 지

myun0506.tistory.com

 

 

- 아티클 스터디 : 파이썬 초보자가 저지르는 10가지 실수

(https://yozm.wishket.com/magazine/detail/1605/)

  • 요약
    • 파이썬을 처음 접하는 초보자들이 많이 저지르는 실수와 이를 고칠 수 있는 방법을 설명한다
  • 주요 포인트 (나쁜 습관들과 이를 고칠 수 있는 방법 제시)
    • import * 사용
      • 비효율적임
      • 변수명에 충돌을 일으킬 수 있음
        • → import math \n from math import pi 로 특정 객체를 불러오거나
        • → import math 처럼 전체 모듈을 불러온 후 객체 사용 전에 math.floor 처럼 모듈 명을 명시
    • 예외 처리 except 절에 예외를 지정하지 않음
      • try/except 를 사용할 때에는 except 절에 예외를 꼭 지정하기
    • 수학 계산에 Numpy를 사용하지 않음
      • 수학 연산에 있어 빠르고 효율적인 작업!!!
      • 수학 연산에는 Numpy 사용하기
    • 이전에 열었떤 파일을 닫지 않음
      • write/read 메소드 사용할 때 예외 발생하면 이미 열린 파일은 닫히지 않는 등의 문제 발생할 수 있음
      • with 구문 사용하면 예외 발생하더라도 파일을 정상적으로 자동으로 닫아줌
    • PEP8의 가이드라인을 벗어남
      • 코드 작성에 대한 최고의 코드 샘플과 가이드라인 제공
      • → 권장하는대로 따르기
    • 딕셔너리 사용할 때 .keys와 .values 적절하게 사용하지 않음
      • .keys 사용하지 않고 딕셔너리 반복만으로도 key 값을 얻을 수 있음
      • value 값 얻어야할 땐 .items() 사용하면 효율적임
    • 컴프리헨션을 사용하지 않음 (혹은 언제나 사용)
      • for-loop 대신 리스트 컴프리헨션으로 간단히 처리하기
      • but 남용하진 말기
    • range(len()) 사용
      • 인덱스와 반복 객체를 둘다 불러오고 싶을 떈 enumerate 사용하기
      • 두가지 리스트를 함께 반복하는 경우엔 zip이 더 효율적임
    • + 연산자를 사용한 문자열 연결
      • f-string 사용하기
    • Mutable value를 디폴트 매개변수로 사용
      • 함수 호출할 때 해당 인자가 존재하지 않는다면 디폴트 매개변수를 사용하는데
      • 이 때 mutable value가 사용된다면 각각 다른 함수의 사용에 같은 주솟값을 공유하게 되어
      • 상태오염/보안결함 이 발생할 수 있음
        • → None과 같은 immutable value로 설정하기
전체적인 포인트를 보자면 결국 명시성, 효율성을 강조하는 것이라고 이해함
import 변수명, numpy 사용, 딕셔너리의 키/value 함수 활용등은 효율성을 강조하고
f-string 이나 파이썬 코드 가이드라인, 컴프리헨션 등은 또 명시성을 강조하는데 
컴프리헨션은 효율성 뿐만 아니라 명시성 측면에서도 코드의 역할을 한눈에 보여준다는 점에서 중요한 기능인 것 같다
학부생때 배웠던 많은 지식들을 많이 활용하지 못하고 문제풀이에만 급급했던 것 같아서
이를 보완하고자 효율성 측면에서, 명시성 측면에서 더 발전된 코드를 짤 수 있도록 더 신경쓰고 노력해야할 것 같다.

 

'[데이터분석] 부트캠프 TIL' 카테고리의 다른 글

20260116 TIL  (0) 2026.01.16
20260115 TIL  (1) 2026.01.15
20260113 TIL  (0) 2026.01.13
20260112 TIL  (1) 2026.01.12
20260111 TIL  (1) 2026.01.12