티스토리 뷰

SQL 코드카타

Q161. Weather Observation Station 16

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

2. 정답 코드:

SELECT ROUND(MIN(LAT_N), 4)
FROM STATION
WHERE LAT_N > 38.7780;

 

Q162. Weather Observation Station 17

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

2. 정답 코드:

SELECT ROUND(LONG_W, 4)
FROM STATION
WHERE LAT_N > 38.7780
ORDER BY LAT_N
LIMIT 1;
SELECT ROUND(LONG_W, 4)
FROM STATION
WHERE LAT_N = (SELECT MIN(LAT_N) FROM STATION WHERE LAT_N > 38.7780);

# 서브쿼리 활용

 

Q98. 550. Game Play Analysis IV ★어려움

1. 문제 링크: https://leetcode.com/problems/game-play-analysis-iv/description/

2. 정답 코드:

SELECT
    ROUND(SUM(IF(DATEDIFF(next_day, first_day) = 1, 1, 0)) / COUNT(DISTINCT player_id), 2
    ) AS fraction
FROM (
    SELECT
        player_id,
        event_date,
        MIN(event_date) OVER (PARTITION BY player_id) AS first_day,
        LEAD(event_date, 1) OVER (PARTITION BY player_id ORDER BY event_date) AS next_day,
        ROW_NUMBER() OVER (PARTITION BY player_id ORDER BY event_date) AS rn
    FROM Activity
) AS find_day
WHERE rn = 1;

데이터 분석 SQL에서 정말 자주 등장하는 '리텐션(Retention)' 계산 문제!

 

📌 문제 핵심

"각 플레이어 중, 처음 가입(로그인)한 날 바로 다음 날에도 연속해서 접속한 플레이어의 비율은 얼마인가?"

이 문제를 풀려면 두 가지 산을 넘어야 한다.

  1. 각 유저의 첫 로그인 날짜그다음 로그인 날짜를 한 줄에 나란히 놓기
  2. 전체 유저 수 대비 연속 접속 유저의 비율 계산하기

🔍 단계별 쿼리 해설

1단계: 서브쿼리로 데이터 정렬하기 (윈도우 함수 활용)

단순히 SELECT만 해서는 '어제가 첫날인지' 알 수 없다. 그래서 윈도우 함수를 사용해 데이터를 가공한다.

  • MIN(event_date) OVER(...): 이 플레이어가 세상에 처음 나타난 날(first_day)을 모든 행에 붙여준다
  • LEAD(event_date, 1) OVER(...): 현재 로그인 날짜 바로 다음에 로그인한 날짜(next_day)를 옆 칸으로 끌어온다
  • ROW_NUMBER() OVER(...): 로그인 순서대로 번호를 매긴다. 우리가 필요한 건 '첫날'의 데이터이므로 rn = 1인 행만 나중에 골라내기 위함!

2단계: 메인 쿼리에서 조건 필터링 및 계산

이제 준비된 재료(서브쿼리)를 가지고 요리를 한다.

  • WHERE rn = 1: 플레이어당 여러 개의 접속 기록이 있지만, 문제에서 요구하는 "가입 첫날 기준"을 맞추기 위해 첫 번째 기록만 남긴다.
  • DATEDIFF(next_day, first_day) = 1: 다음 접속일과 첫 접속일의 차이가 정확히 '1'인 경우만 찾는다.
  • SUM(IF(조건, 1, 0)): 조건이 맞으면 1, 아니면 0을 주어 연속 접속한 사람들의 총합을 구한다.
  • COUNT(DISTINCT player_id): 전체 유저 수로 나누어 비율을 구하고, ROUND로 소수점 둘째 자리까지 반올림한다.

✅ 핵심 포인트 (복습)

  1. LEAD 함수는 다음 데이터를 현재 행으로 가져올 때 유용하다.
  2. DATEDIFF는 날짜 사이의 간격을 계산할 때 필수!
  3. ROW_NUMBER를 통해 여러 행 중 내가 분석하고자 하는 특정 시점(첫 로그인)을 정확히 집어낼 수 있다.

마무리하며: 리텐션 분석은 실제 현업에서도 사용자 이탈을 방지하기 위해 가장 먼저 확인하는 지표이다. 이 쿼리 패턴을 익혀두면 실무에서도 큰 도움이 될 것 같다!


Python 코드카타 (https://github.com/heeso0908/codekata.git)

Q54. 2016년

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/12901

2. 정답 코드:

def solution(a, b):
    answer = ''
    day = 0
    day2 = ['FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED', 'THU']
    for n in range(1, a):
        if n in (1, 3, 5, 7, 8, 10, 12):
            day += 31
        elif n == 2:
            day += 29
        elif n in (4, 6, 9, 11):
            day+= 30
    day += b
    temp = day % 7
    answer = day2[temp-1]
    return answer

# 내가 작성한 코드

금요일~목요일 순으로 day2라는 리스트 생성  
for 문 + if 문을 사용해서 특정 월을 꽉 채웠을 때 더해줄 숫자를 나눔  
- 1, 3, 5, 7, 8, 10, 12월 → day += 31 (12월은 원래 필요 X)  
- 2월 → day += 29 (윤년)  
- 4, 6, 9, 11월 → day += 30  

그런 다음 남은 일수 day += b  
day2[(day % 7) - 1]을 하여 요일 출력!
def solution(a, b):
    # 1월 1일이 금요일(FRI)이므로 나머지에 따라 인덱스 설정
    # day % 7 이 1이면 FRI, 2이면 SAT ... 0이면 THU
    day2 = ['THU', 'FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED']
    
    # 각 월의 일수 (1월부터 12월까지)
    months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    
    # a-1월까지의 일수 합계 + b일
    # 예: a=5, b=24 -> months[0]~months[3]까지 합친 후 24를 더함
    total_day = sum(months[:a-1]) + b
    
    return day2[total_day % 7]

# 더 간단한 버전


라이브 세션) 머신러닝 실습 6일차: 회귀

1) 지표: MSE / RMSE / MAE / R^2

공식을 보면 다 정답값과 예측값의 차이


2) 선형회귀(Linear Regression)

단일 선형회귀: 독립변수가 1개

다중 선형회귀: 독립변수가 2개 이상


3) 다항회귀(Polynomial Regression) = 비선형회귀

전처리 단계에서 트릭을 써주고, (x^2 → X2 이런식으로 바꾸기)

다중 선형회귀를 사용하면 된다!

기본적으로 회귀에서는 상수항을 포함?(b)


4) 규제(Regularization) : 과적합 방지

오차(첫번째 수식의 내용) + 패널티(두/세번째의 빨강 박스) → 파라미터가 극단적인 값들이 안 나오도록 규제

 

파라미터에 극단적인 값들이 들어가면 오차를 확 키움!

오차가 커지면 커질수록 더 공격적으로 머신러닝을 하게 됨 → 패널티! 

오차 식
Ridge 식
Ridge 식
Lasso 식

(1) 두번째 식: Ridge(릿지 회귀)

(2) 세번째 식: Lasso(랏쏘 회귀)

(3) λ(람다) = 얼마나 강하게 규제할지 정도! = 스위치


라이브 세션) 머신러닝 이론 6일차: 앙상블 학습

모델을 여러 개를 써서 하나의 값을 만드는 방법!

성능을 올려주는 장점도 있을 수 있지만, 주로 앙상블을 사용하는 이유는 더 안정적(덜 흔들림=신뢰↑)으로 할 수 있기 때문!

1) 결정 트리 = 스무고개

스무고개 과정으로 불순도를 줄여가고자 특정 피쳐를 더 사용하면서(Feature Importance) 값 체크하는 과정

 

[한계점] 불안정함(Variance ↑)

Max_depth가 None이면 과적합이 발생할 수 있다

Feature Importance 자동 제공 → 데이터가 조금만 바뀌어도 트리 구조가 크게 달라짐

 

+ 스케일링 불필요 → 단일 트리의 분산이 높음

결정 트리에서도 불안정함이라는 한계점이 있기 때문에
이 한계점을 보완하고자! 앙상블 학습이 생겨났다~!


하나의 단일 모델은 흔들릴 수 있지만
여러 모델을 평균을 내서 쓰면 상대적으로 덜 흔들린다?!
→ 앙상블 학습!


앙상블이 단일 모델보다 항상 덜 불안정한 것은 아니지만(예외가 있음)
대체적으로 단일 모델보단 여러 모델의 평균이 더 안정적이므로 앙상블 학습 많이 사용함!

2) 앙상블 학습(Ensemble Learning)

앙상블이란?

: 2인 이상의 연주, 전체적인 어울림 또는 함께, 동시에란 뜻

 

(1) Voting → 서로 다른 모델 → 다양성 확보

: 서로 다른 모델의 합주(다수결/확률 평균) → 극단 예측 완화

 

(2) Bagging → 같은 모델을 부트스트랩으로 여러 개 만들고 평균

: 같은 모델 여러 개 평균(부트스트랩) → Variance(분산) 감소

같은 모델이지만 데이터셋을 다르게 사용

 

+ Random Forest: Bagging+특성 무작위화 → 트리 간 상관↓ → 평균 효과↑

데이터와 Feature까지도 다르게 봐서(상관관계를 낮춰서) 더 심화 모델

 

(3) Boosting → 실수를 기억하며 순차 보정(A가 실수한거 B가 보정)

: 앞 모델(학습)의 실수를 뒤 모델이 보완(순차 학습) → Bias(편향)↓ → 정확성↑

 

(4) 앙상블 특징

· 앙상블 다양성: 단일 모델 X(획일화 X) / 다양한 모델 O(같은 모델이라도 여러 개 사용)

· 앙상블 독립성: A모델이 실수하는 시점과 B모델이 실수하는 시점이 다르냐! ★중요

                         → 다르면 앙상블 평균이 안정적!

                              모델들이 같이 틀리지 않을수록(상관관계가 낮을수록) 앙상블의 효과는 극대화된다!


 

3) Bias vs Variance

· Bias(편향): 모델이 너무 단순해서 중요 패턴 학습 못함 → 과소적합

· Variance(분산): 모델이 너무 복잡해서 과도하게 적합 → 과적합

두 값은 Trade-off 관계이므로 적절한 균형점을 찾아야 한다!

출처: https://scott.fortmann-roe.com


4) Voting(투표 기반 앙상블)

(1) Hard Voting: 단순 다수결

(2) Soft Voting: 예측 확률 (품질) 평균

      → 결과를 내는게 아니라 확신도(Confidence)를 반영하므로 더 정교한 결과 도출!

           Hard Voting보다 대체로 안정적(예외도 있음)


5) Bagging(Bootstrap Aggregating)

랜덤 포레스트는 데이터를 중복 허용해서 랜덤 샘플링(Bootstrap)을 한다!

하나의 트리는 전체 데이터의 약 63%만을 학습에 사용하고,

학습에 참여하지 못한 나머지 37% 데이터가 OOB 샘플이다!

 

(1) OOB 평가 프로세스: 나를 학습하지 않은 트리에게 묻는다

→ 검증 데이터를 따로 분리할 필요가 없다?

 

(2) Random Forest

= Bagging(트리 x N) + 특성 무작위화(max_features)

· 병렬적 다양성: 일부러 다르게 만들기! → 여러 개의 결정 트리를 독립적으로 학습시켜 평균을 내는 방식

Original Data → Bootstrap(무작위 데이터 샘플링) → Feature Randomness(시야 제한) → 상관관계가 낮은 다양한 트리 생성!

 

(3) max_features(특성 무작위화)가 왜 필요할까?

Bagging만 쓰면 강력한 피쳐 때문에 모든 트리가 비슷한 규칙으로 시작 → 복사본 평균 효과

Random Forest는 분기할 때마다 피처를 일부만 허용(무작위로 제한) → 다양성↑ → 상관관계↓

 

+ Bagging은 일부러 불안정한 모델을 만들어서 안정화하는 것을 목적으로 하기 때문에 max_depth = None 사용!


6) Feature Importance의 위험성

특정 변수 유형이 높게 나올 수 있음

- 연속형 변수

- 한번이라도 분할에 쓰인 변수

- 훈련 과정에서의 과적합 영향


7) Permutation Importance ★중요★

특정한 변수를 망가뜨림 → 다시 정확도 측정 → 정확도 감소량 = 중요도 → 성능이 얼마나 떨어지는지를 알려줌


+ 모델 선정할 때 GridSearchCV는 다른 것들보다 오래 걸림


8) Boosting & Gradient Boosting

편향 문제는 평균을 낸다고 해서 해결되지 않음!

Boosting은 Bias를 줄이지만, Variance를 올릴 수 있음(오히려 노이즈까지 외워버릴 수도 있어서?)

 

Bagging → 흔들림(Variance)을 줄이는 앙상블 (안정성 향상)

Boosting → 오차(Bias)를 줄이는 앙상블 (정확성 향상)

 

Boosting은 얼마나 틀렸는가(잔차)가 중요! → 각각 모델들이 잔차를 가지고 논다!

 

(1) 핵심 아이디어

여러 개의 약한 모델(ex. max_depth=1 부터~)이 순차적으로 학습하면서 앞 모델이 틀린 부분(오차, 잔차)을 다음 모델이 보완!

 

(2) 핵심 로직

  • 첫 번째 모델 → 데이터를 학습해 예측
  • 오차(Residual = 실제 - 예측) 계산
  • 다음 모델 → 이 오차(잔차)를 예측하도록 학습
  • 최종 예측 = 이전 예측 + 새로운 보정(오차 보정)

(3) AdaBoost(Adaptive Boosting): 오답노트를 좀 더 중요하게 공부한다!

틀린 샘플의 가중치를 올려, 다음 약한 모델이 어려운 샘플에 더 집중하게 만드는 순차형 앙상블

  • 처음에는 모든 샘플 가중치가 동일함(w = 1/N)
  • 틀린 샘플의 가중치 ↑ → 다음 모델이 그 샘플을 더 중요하게 학습
  • 각 모델의 성능에 따라 모델 가중치(α_t) 부여 → 잘한 모델한테만 가중치!
  • 최종 예측 = 모델별 예측 x 가중치(α_t)의 합

그런데 가중치를 준 샘플이 노이즈일 수도 있음-!

 

- 약한 학습기(Weak learner): 보통 깊이 1 의사결정나무

 

- 핵심 하이퍼파라미터

  n_estimators: 약한 모델의 개수 (너무 많으면 과적합 위험)

         → 스텝 수(n_estimators)가 너무 적으면 언더핏(Underfitting), 지나치게 많으면 오버핏(Overfitting) 신호가 보일 수 있음

  learning_rate: 한 단계 보정 강도(보폭), 작을수록 천천히, 안정적으로 → 더 많은 스텝 필요(시간이 더 걸림)

 

  + CV 평균이 Test와 근접하면 안정적이고, 차이가 많이 벌어지면 과적합 의심


AdaBoost 모델에서 n_estimators(트리 개수)를 늘리면 무조건 좋아질까? 그래프를 통해 분석해 보자

이미지 약간 틀릴 수 있으니 주의

🔍 그래프 핵심 포인트 (Actual Data)

  • Best 구간 (50 ~ 100): 교차 검증(CV) 정확도가 가장 높은 지점 → 효율과 성능을 모두 잡은 Sweet Spot
  • 과적합 구간 (200 부근): 테스트 점수는 높게 유지되지만, CV 점수가 눈에 띄게 하락 → 모델이 데이터의 노이즈까지 학습하기 시작했다는 증거
  • 안정화 구간 (300): 다시 조금 회복되지만, 50개일 때와 큰 차이가 없어 연산량만 늘어나는 비효율적인 구간

⚠️ 200 구간, 과적합(Overfitting)의 신호

트리 개수가 200개에 가까워지면서 모델이 데이터의 노이즈(Noise)까지 학습하기 시작함

  • 현상: 학습 데이터에는 완벽해 보이지만, 실제 검증(CV) 데이터에서는 성능이 떨어지는 전형적인 과적합 발생
  • 원인: learning_rate=0.5 설정에서 트리가 너무 많아지면 모델이 지나치게 복잡해진다

✅ 결론: "50~100개가 정답"

이 모델의 Sweet Spot은 50~100 사이! 200개까지 늘리는 것은 계산 리소스만 낭비하고 성능 불안정성을 초래할 뿐이다

💡 한 줄 팁: 성능을 더 높이고 싶다면 트리 개수를 늘리기보다, 학습률(Learning Rate)을 0.1 이하로 낮추고 다시 테스트!

약 175 지점(낮아지는 구간?)이 집착하는 구간(가중치의 함정) → 과적합
→ 시험에 딱 한 번 나오는 킬러 문항에만 매달리다 전체 공부를 망치는 것과 같다


보폭(learning_rate) x 횟수(n_estimators)의 균형 게임! → CV mean으로 확인? → 혼동행렬까지 추가 확인 필요

→ 보폭이 작다고 무조건 좋은 것도 아니고, 횟수가 많다고 무조건 좋은 것도 아니다!

 

보폭이 작을수록 더 천천히 안정적으로 좋아짐 → 더 많은 횟수를 시행해야 안정적으로 됨

보폭이 크면 빠르게 좋아짐 → 과적합 위험도 함께 증가

보폭 x 횟수 히트맵을 그렸을 때 고원처럼 안정적이고 높은 구간을 선택하는 것이 합리적이다!


(4) Gradient Boosting: 오차의 방향(기울기)을 따라가며 Loss를 직접 줄이는 일반화된 알고리즘

1. 첫 번째 모델 → 데이터 전체를 대략 예측
2. 잔차(residual) = 실제값 − 예측값
3. 두 번째 모델 → 이 잔차(residual)를 예측
4. 전체 모델 = 이전 예측 + (학습률 × 잔차 보정)
5. 이 과정을 여러 번 반복하면 Loss가 점점 줄어듦

즉, 각 스텝은 “이전 모델이 틀린 부분”을 따라가며 오차를 줄이는 경사하강법(Gradient Descent) 과정

 

 

Q. Gradient(기울기)를 사용하는 이유?

: AdaBoost는 이진 분류 기반이라 Loss의 형태가 제한적인데,

Gradient Boosting은 손실 함수(Loss Function)를 설정할 수 있어서 회귀와 다중 분류, 사용자 정의 Loss까지 모두 다룰 수 있음!!

가중치를 바꾸는 대신, 손실(Loss)를 줄이는 방향으로 이동!
→ 기울기가 손실을 줄이는 방향을 알려주는 나침반 역할!
 

 

 

(5) 경사하강법(Gradient Descent) 시각화

경사하강법은 기울기의 반대 방향으로 조금씩 이동하며 Loss를 최소화하는 지점을 찾는 방법!

 

(6) 손실 함수(Loss Function) 하이퍼파라미터

손실 함수를 바꾼다는 것 = 문제를 재정의하는 것

 

💡Gradient Boosting에서 선택 가능한 분류/회귀 손실 함수 종류

  손실 함수 설명 언제 쓰는지?
분류 log_loss (기본값) 로그 손실(Cross-Entropy) 대부분의 분류 문제(확률 출력 가능)
exponential 지수 손실(AdaBoost와 동일) 이진 분류에서 AdaBoost 효과를 원할 때
회귀 squared_error 평균 제곱 오차(L2) 일반적인 회귀(이상치에 민감)
absolute_error 절대 오차(L1) 이상치가 있을 때(중앙값 예측)
huber L1+L2 혼합 이상치에 적당히 강건하면서 안정적
quantile 분위수 회귀 특정 분위수(ex.상위 90%)를 예측할 때

 

💡 Gradient Boosting 회귀에서의 손실 함수 선택 가이드

데이터에 이상치가 있는가?

  • YES: huber 또는 absolute_error(RobustScaler를 골랐던 것과 같이 이상치에 강건하므로!)
  • No: squared_error(기본값, 가장 일반적)
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함