빅데이터 QAQC_3기/빅데이터 QAQC_3기 TIL

TIL_251029

usungusung 2025. 10. 29. 21:50

Today I learned

 

 

1. [라이브세션 복습] 기초통계 - 추론통계 3회

1) 모집단과 표본

  • 모수: 모집단의 특성(전수조사)
  • 통계량: 표본의 특성(표본조사)
  • 표본 추출방법
    • 단순 랜덤 추출: 무작위 샘플링
    • 계통 추출: 5개장 1개씩 샘플링
    • 집락 추출: 특정 구역 내에서만 샘플링
    • 층화 추출: 특정 상품군에서 샘플링
  • 표본분포
    • 같은 모집단에서 동일한 크기의 표본을 여러 번 추출할 때 계산되는 통계량의 분포
    • 모집단이 정규분포가 아니더라도, 충분한 표본 수가 있을 경우, 표본 평균은 정규분포를 따름
표본 평균 예시
import numpy as np
import matplotlib.pyplot as plt

# 모집단 생성 (균등분포 또는 왜도 있는 분포)
population = np.random.exponential(scale=2.0, size=10000)

# 표본 평균 시뮬레이션
def simulate_sampling_means(n_samples=30, n_iter=1000):
    sample_means = []
    for _ in range(n_iter):
        sample = np.random.choice(population, size=n_samples)
        sample_means.append(np.mean(sample))
    return sample_means

sample_means = simulate_sampling_means()

plt.hist(sample_means, bins=30, edgecolor='black')
plt.title("표본평균의 분포 (n=30)")
plt.xlabel("표본 평균")
plt.ylabel("빈도")
plt.show()

 

2) 중심극한정리

  • 충분한 표본 수(n ≥ 30)가 확보되면 표본평균의 분포가 정규 분포에 근사한다.
중심극한정리 예시
# 중심극한정리 실험 (비정규분포 → 평균 분포 시 정규화 확인)
means_5 = simulate_sampling_means(n_samples=5)
means_30 = simulate_sampling_means(n_samples=30)
means_100 = simulate_sampling_means(n_samples=100)

plt.hist(means_5, bins=30, alpha=0.5, label='n=5')
plt.hist(means_30, bins=30, alpha=0.5, label='n=30')
plt.hist(means_100, bins=30, alpha=0.5, label='n=100')
plt.legend()
plt.title("중심극한정리 시뮬레이션")
plt.show()

 

3) 표준 오차와 신뢰구간

- 표준오차(Standard Error, SE)

  • 표본 분포의 표준편차
  • 표본평균이 가질 수 있는 통계적 변동성을 수치화한 지표
  • n(표본 크기)가 커질수록 SE가 작아짐 - 평균 추정의 신뢰도가 높아진다는 의미
  • 표준편차 vs 표준오차
구분 표준편차
Standard Deviation, SD
표준오차
Standard Error, SE
의미 데이터가 흩어진 정도 표본평균의 불확실성 정도
대상 개별 데이터 값들의 산포 여러 표본들의 산포
증가/감소 요인 데이터 자체의 다양성에 따라 결정 표본 수가 커질수록 감소
계산식

 

- 신뢰구간


표본 평균
신뢰수준에 해당하는 임계값
(95%: 1.96, 99%: 2.58)

표본 크기
표본 표준편차
(시그마 기호는 모표준편차)
표준오차
  • 모집단의 실제 값이 포함될 범위를 추정하는 구간
  • 표본 데이터로부터 모집단의 평균이나 비율 추정
  • 범위 내에 모집단의 평균이 존재할 확률
  • 모집단의 표준편차 σ를 모를 경우 t-분포 사용
신뢰구간 파이썬 예시
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# 주어진 값들
mean = 50.3          # 표본평균
std = 0.5            # 표본 표준편차
n = 40               # 표본 크기
alpha = 0.05         # 유의수준 (95% 신뢰수준)
z_value = norm.ppf(1 - alpha/2)  # Z = 1.96

# 표준오차 및 신뢰구간 계산
se = std / np.sqrt(n)
margin = z_value * se
ci_lower = mean - margin
ci_upper = mean + margin

# 시각화용 x축 범위
x = np.linspace(mean - 4*se, mean + 4*se, 200)
y = norm.pdf(x, mean, se)

# 그래프 그리기
plt.figure(figsize=(8, 5))
plt.plot(x, y, label='Sampling Distribution (Mean)')
plt.axvline(mean, color='blue', linestyle='--', label='Sample Mean')
plt.axvline(ci_lower, color='red', linestyle='--', label='95% CI Lower')
plt.axvline(ci_upper, color='red', linestyle='--', label='95% CI Upper')
plt.fill_between(x, y, 0, where=(x >= ci_lower) & (x <= ci_upper), color='red', alpha=0.2)
plt.title("95% Confidence Interval for the Mean")
plt.xlabel("Mean Value (mm)")
plt.ylabel("Probability Density")
plt.legend()
plt.grid(True)
plt.show()

print(f"95% Confidence Interval: ({ci_lower:.3f}, {ci_upper:.3f})")

 

- 신뢰수준과 유의수준

신뢰구간
(Confidence Interval)
표본 평균을 중심으로 설정된 추정 가능한 범위
신뢰수준
(Confidence Level)
추정 구간이 실제 모집단 평균을 포함할 확률
유의수준
(Significance Level, a)
틀릴 가능성, 추정이 빗나갈 확률
  • 신뢰구간이 좁을수록 무집단 평균 추정치가 정확해짐.
  • 관측 개수(표본크기)가 클수록 신뢰구간이 좁아짐
신뢰구간 파이썬 실습
# 다양한 표본 수에 따른 표준오차 차이
import numpy as np
import matplotlib.pyplot as plt
import koreanize_matplotlib
# 모집단 생성 (평균 100, 표준편차 15)
population = np.random.normal(loc=100, scale=15, size=10000)

# 서로 다른 표본 크기들에 대해 평균 분포 확인
sample_sizes = [5, 10, 30, 100, 500]
plt.figure(figsize=(12, 8))

for i, n in enumerate(sample_sizes, 1):
    sample_means = []
    for _ in range(1000):
        sample = np.random.choice(population, size=n)
        sample_means.append(np.mean(sample))
   
    plt.subplot(2, 3, i)
    plt.hist(sample_means, bins=30, edgecolor='black')
    plt.title(f"표본 크기 n={n}")
    plt.xlim(80,120)
    plt.xlabel("표본 평균")
    plt.ylabel("빈도")

plt.tight_layout()
plt.suptitle("표본 수가 많아질수록 평균 분포가 좁아짐 (SE 감소)", y=1.02)
plt.show()

# 이거 코랩가서 열어라

※ 표본 크기가 늘어날 수록, 신뢰 구간은 좁아지는 모습

 

4) 가설 검정

  • 표본 데이터를 기반으로 모집단에 대한 주장을 통계적으로 판단하는 방법
  • 표본 데이터를 바탕으로 모집단에 대한 주장의 옳고 그름을 판단
귀무가설
(H₀)
'차이가 없다, 효과가 없다 '
전제로 한 기본 가설
대립가설
(H₁)
'차이가 있다, 효과가 있다'
증명하고 싶은 가설
유의수준
(α)
H₀이 참,
but 실수로 기각할 확률
p-value
(p)
H₀이 참인데
데이터가 극단적인 확률

 

구분 의미 예시 통계적 결과  
1종 오류
(Type I Error)
실제로는 귀무가설이 참인데 기각 신약은 효과 없는데 효과 있다고 판단 잘못된 기각
→ "잘못된 긍정"
유의수준 α
2종 오류
(Type II Error)
실제로는 귀무가설이 거짓인데 채택 신약은 효과 있는데 없다고 판단 잘못된 보류
→ "놓친 기회"
β

 

 

- 가설 검정의 절차

1. 귀무가설과 대립가설 수립 - 귀무가설: 변화 없음, 차이 없음, 기존과 동일
- 대립가설: 변화 있음, 차이 있음, 새로움 존재
2. 유의수준 설정 - 일반적으로 0.05 사용 (틀릴 확률 5% 허용)
3. 검정통계량 계산 표본평균, 표준편차, 표본크기 바탕으로 계산
4. 결론 도출 - 신뢰수준: 계산된 값이 기준 범위를 벗어나면 귀무가설 기각
- p-value가 작으면 귀무가설 기각(알반적으로 p < a)

 

- 단측검정 vs 양측검정

단측검정 한쪽 방향만 확인 신약 효과가 기존보다 크다
양측검정 양방향 모두 확인 신약 효과가 기존보다 크거나 작다

 

5) 모수 검정

  • 정규분포 등 모집단 분포에 대한 전제를 가지는 검정 방법
  • 평균의 차이를 비교할 때 사용
  • 정규성, 등분산성 등 통계적 조건을 만족해야 함
검정 종류 사용 조건 특징 및 설명 세부 유형 예시
t-test 표본 수가 작고(n < 30), 모집단의 분산을 모를 때 평균 비교 시 사용 정규성, 등분산성 조건이 필요. 평균 차이 검정용 - 단일표본 t-test
- 독립표본 t-test
- 대응표본 t-test
z-test 표본 수가 충분히 크고(n ≥ 30), 모집단의 표준편차를 알고 있을 때 사용 Z-score를 기반으로 평균 차이 검정 수행. 큰 표본에서 사용됨 - 단일표본 z-test (주로 사용됨)
ANOVA 3개 이상의 집단 평균을 비교할 때 사용 그룹 수가 많을 때 t-test 반복 시 오류 위험 증가 → 한 번에 통합 비교 - 일원 ANOVA: 한 기준 (예: 지역)
- 이원 ANOVA: 두 기준 (예: 지역+성별)

 

6) 정규성 검정

  • 대부분의 통계 검정은 데이터가 정규분포를 따른다는 전제 하에 수행됨
    • '데이터가 정규분포를 따르는지' 정규성 검정을 통해 먼저 확인
    • Shapiro-Wilk Test, Q-Q 플롯 등

- Shapiro-Wilk Test

  • 가장 널리 사용되는 정규성 검정 방법
  • 귀무가설: 데이터가 정규분포를 따른다
Saphiro-Wilk Test 파이썬 예시
from scipy.stats import shapiro

data = [75, 78, 72, 74, 77, 79]
stat, p = shapiro(data)
print(f'Stat = {stat:.4f}, p-value = {p:.4f}')
Stat = 0.9658, p-value = 0.8631
  • p > 0.05 → 정규성을 만족함
  • p < 0.05 → 정규성을 만족하지 않음 → 비모수 검정 사용

 

- Q-Q 플롯

  • 데이터가 정규분포를 다르는지 시각적으로 확인하는 방법
    • 그래프가 45도 직선에 가가우면 정규성 만족
    • 데이터 점들이 직선에 가까우면 정규성 가정이 만족
    • 선에서 멀리 떨어진 점들이 많다면 정규성 위배 가능성
Q-Q 플롯 파이썬 예시
import scipy.stats as stats
import matplotlib.pyplot as plt

data = [75, 78, 72, 74, 77, 79]

stats.probplot(data, dist="norm", plot=plt)
plt.title("Q-Q Plot")
plt.grid(True)
plt.show()

 

 

7) 비모수 검정

  • 정규분포를 따르지 않으면 순위를 기반으로 하는 비모수 검정 사용
  • 데이터 수가 적어 정규성을 판단하기 어려울 때 사용하는 방법
검정명 비교 대상 사용 예시 Python 함수
Mann-Whitney U Test 독립 2집단 남녀 만족도 비교 mannwhitneyu()
Wilcoxon Test 대응 2집단 교육 전후 점수 비교 wilcoxon()
Kruskal-Wallis Test 독립 3집단 이상 공정 A/B/C 생산량 비교 kruskal()
Chi-square Test 범주형 독립성 성별 vs 과목 선호 chi2_contingency()

 

Mann-Whitney U Test : 두 독립 집단 간의 중앙값 or 분포 차이 비교
from scipy.stats import mannwhitneyu

group1 = [78, 75, 80, 74]  # Group A
group2 = [70, 68, 69, 71]  # Group B

stat, p = mannwhitneyu(group1, group2, alternative='two-sided')
print(f'U = {stat}, p-value = {p:.4f}')
U = 16.0, p-value = 0.0286

※ p < 0.05 조건일 때 두 집단의 중앙값(or 분포) 차이 있음
위 결과의 경우 p = 0.0286 이므로, A와 B의 결과는 다르다
Wilcoxon Test : 같은 집단에서의 사전-사후 변화 같이 쌍으로 대응되는 데이터 차이 비교
from scipy.stats import wilcoxon

before = [100, 95, 90, 87]
after = [110, 100, 92, 88]

stat, p = wilcoxon(before, after)
print(f'W = {stat}, p-value = {p:.4f}')
W = 0.0, p-value = 0.1250

※ p < 0.05 조건일 때 전 후 데이터 차이 있음


Kruskal-Wall H Test : 세 개 이상의 독립 집단 간 중앙값 또는 분포 차이가 있는지?
from scipy.stats import kruskal

groupA = [72, 74, 73, 71]
groupB = [68, 69, 70, 66]
groupC = [75, 77, 76, 78]

stat, p = kruskal(groupA, groupB, groupC)
print(f'H = {stat:.2f}, p-value = {p:.4f}')
H = 9.85, p-value = 0.0073

※ p < 0.05 조건일 때 적어도 한 집단은 다른 분포
Chi-square Test : 범주형 변수 간 독립성을 검정하여 두 변수 간 관련성 확인
import pandas as pd
from scipy.stats import chi2_contingency

# 교차표 생성
data = pd.DataFrame({'Male': [30, 10], 'Female': [20, 40]},
                    index=['Math', 'Literature'])

stat, p, dof, expected = chi2_contingency(data)
print(f'Chi2 = {stat:.2f}, p-value = {p:.4f}')
Chi2 = 15.04, p-value = 0.0001

※ p < 0.05 조건일 때 서로 관련성 있음

 

8) 통계 도식화

 

 

2. QAQC 문제풀이

 

3. [라이브세션] 머신러닝 오프닝 4회차

 

1) 앙상블 모델

  • 여러 모델의 예측을 결합하여 더 나은 결과를 얻는 방법
  • 배깅(bagging)
    • 원래 데이터에서 여러번 샘플링하여 다양한 데이터셋을 만들고, 각각에 대해 독립적으로 모델을 학습시킴
    • 랜덤 포레스트 : 여러개의 결정 트리를 독립적으로 학습시켜 각 트리가 서로 다른 데이터와 특성을 사용
  • 부스팅(boosting)
    • 이전 모델이 잘못 예측한 데이터에 더 많은 가중치를 두어 순차적으로 모델 개선
    • 이전 모델의 오차를 보완하는 방향으로 학습
앙상블 모델의
장점 단점
더 안정적이고 강건한 예측 가능 학습, 예측에 더 많은 시간과 자원 필요
과적합 위험 최소화 모델이 복잡해져 해석의 어려움 발생
더 높은 예측 성능 적절한 앙상블 방법과 파라미터 선택이 중요

 

 

1-1) 결정 트리

  • 의사결정 규칙을 나무 형태로 도표화 like 스무고개
  • 각 내부 노드는 하나의 특성에 대한 조건을 나타냄
  • 트리는 불순도(지니계수 or 엔트로피)가 가장 크게 감소하는 방향으로 특성과 분할 기준을 선택하며 성장
    • 불순도?
      • 각 노드에 데이터가 얼마나 섞여있는가?
      • 노드에 포함된 데이터가 단일 클래스면 불순도 = 0
      • 모든 클래스가 균등하게 섞여 있으면 불순도는 최대
    • Gini계수: 불순도를 측정하는 대표 지표
  • 장단점
    • 모델의 의사결정 과정의 시각화 = 해석이 용이함
    • 과적합 되기 쉬움 - 가지치기 기법

결정 트리의 예시

 

 

1-2) 랜덤 포레스트

  • 여러 개의 결정트리를 생성하고, 이들의 예측을 종합하여 최종 결정을 내리는 앙상블 모델
  • 각 트리는 원본 데이터에서 무작위 추출로 학습됨
  • 작동 원리
    • 부트스트랩 샘플링 - 특성의 무작위 선택 - 개별 트리의 학습 - 앙상블 예측
  • 장단점
    • 장; 과적합 위험 낮음, 특성 중요도 계산, 이상치에 강건, 대규모 데이터에서도 원할
    • 단: 계산 비용과 자원 요구량 높음, 모델 복잡성 및 해석 복잡, 하이퍼파라미터(트리의 개수, 최대 깊이 등) 튜닝이 복잡

랜덤 포레스트 예시

 

결정 트리, 랜덤 포레스트 파이썬 실습
# 필요한 라이브러리 임포트
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
import seaborn as sns

# 1. 데이터 준비 - 가상의 대출 데이터 생성
np.random.seed(42)
n_samples = 1000

data = {
    'income': np.random.normal(5000000, 2000000, n_samples),        # 연소득
    'credit_score': np.random.normal(650, 100, n_samples),          # 신용점수
    'employment_years': np.random.normal(5, 3, n_samples),          # 근속년수
    'dti_ratio': np.random.normal(0.3, 0.1, n_samples),             # DTI
    'ltv_ratio': np.random.normal(0.6, 0.2, n_samples),             # LTV
    'age': np.random.normal(40, 10, n_samples)                      # 나이
}
df = pd.DataFrame(data)

# 현실적인 범위로 값 클리핑
df['credit_score'] = df['credit_score'].clip(300, 900)
df['employment_years'] = df['employment_years'].clip(0, 40)
df['dti_ratio'] = df['dti_ratio'].clip(0, 1)
df['ltv_ratio'] = df['ltv_ratio'].clip(0, 1)
df['age'] = df['age'].clip(20, 80)

# 2. 회귀용 연속 타깃 생성 (0~1 사이의 상환 점수 repay_score)
#    – 분류 때 쓰던 규칙을 연속화 + 노이즈 추가 → 시그모이드로 0~1 압축
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 표준화에 가까운 간단한 스케일링(선형결합을 만들기 위한 기준화)
cs_z = (df['credit_score'] - 650) / 100          # 평균 650, 표준편차 100 기준
dti_z = (0.4 - df['dti_ratio']) / 0.1            # DTI 낮을수록 유리하게
emp_z = (df['employment_years'] - 2) / 3
inc_z = (df['income'] - 3000000) / 2000000
ltv_z = (0.7 - df['ltv_ratio']) / 0.2

linear_score = 0.9*cs_z + 0.8*dti_z + 0.6*emp_z + 0.7*inc_z + 0.6*ltv_z
noise = np.random.normal(0, 0.5, size=n_samples)  # 현실적인 잡음
df['repay_score'] = sigmoid(linear_score + noise) # 0~1 연속 타깃
데이터 만드는 과정임
여기 안봐도 됨
# 3. 데이터 분할
X = df.drop('repay_score', axis=1)
y = df['repay_score']
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
데이터를 훈련용/테스트 데이터로 분할

# 4-1. 회귀 모델 정의 및 학습 (결정트리 회귀)
dt_reg = DecisionTreeRegressor(
    max_depth=5,
    min_samples_split=50,
    min_samples_leaf=20,
    random_state=42
)
dt_reg.fit(X_train, y_train)
DecisionTreeRegressor를 통해 dt_reg 변수에 결정트리 회귀 학습

- depth: 트리의 깊이, 스무고개 몇번까지? 이런 으미
- split: 노드를 분할하기 위한 최소 샘플수, 너무 작은 샘플로 분할되는 것을 방지하는 역할
- leaf: 리프 노드(최종 결과를 출력하는 노드)가 너무 작아지는걸 방지
# 4-2. 회귀 모델 정의 및 학습 (랜덤포레스트 회귀)
rf_reg
= RandomForestRegressor(
    n_estimators=100,
    max_depth=5,
    min_samples_split=50,
    min_samples_leaf=20,
    random_state=42,
    n_jobs=-1
)
rf_reg.fit(X_train, y_train)
RandomForestRegressor를 통해 rf_reg 변수에 랜덤포레스트 회귀 학습

- estimators : 트리의 최종 갯수, 즉 100개의 트리 만들거임
- n_jobs: cpu 코어 수 할당, 안써도 무방
나머지는 위와 같음

# 5. 예측
dt_pred = dt_reg.predict(X_test)
rf_pred = rf_reg.predict(X_test)
 
# 6. 회귀 평가지표: MSE, RMSE만 출력
dt_mse = mean_squared_error(y_test, dt_pred)
dt_rmse = np.sqrt(dt_mse)
rf_mse = mean_squared_error(y_test, rf_pred)
rf_rmse = np.sqrt(rf_mse)

print("결정트리 회귀")
print("MSE:", round(dt_mse, 6))
print("RMSE:", round(dt_rmse, 6))
print()
print("랜덤포레스트 회귀")
print("MSE:", round(rf_mse, 6))
print("RMSE:", round(rf_rmse, 6))
결정트리 회귀 MSE: 0.025324 RMSE: 0.159136
랜덤포레스트 회귀 MSE: 0.017791 RMSE: 0.133381
# (선택) 예측 산점도 간단 시각화 – 모델 한 개만 보기 좋게
plt.figure(figsize=(6,5))
sns.scatterplot(x=y_test, y=rf_pred, alpha=0.4)
plt.plot([0,1],[0,1], ls='--')
plt.xlabel('실제 repay_score')
plt.ylabel('예측 repay_score (RF)')
plt.title('랜덤포레스트 회귀: 실제 vs 예측')
plt.show()
# 7. 새로운 고객 회귀 예측 (연속 점수)
new_customer = pd.DataFrame({
    'income': [6000000],
    'credit_score': [750],
    'employment_years': [5],
    'dti_ratio': [0.3],
    'ltv_ratio': [0.6],
    'age': [35]
})

dt_new = dt_reg.predict(new_customer)[0]
rf_new = rf_reg.predict(new_customer)[0]
print("\n새로운 고객 repay_score 예측 (0~1, 높을수록 상환 가능성이 높음)")
print("결정트리:", round(float(dt_new), 4))
print("랜덤포레스트:", round(float(rf_new), 4))
새로운 고객 repay_score 예측
(0~1, 높을수록 상환 가능성이 높음)
결정트리: 0.8715 랜덤포레스트: 0.9605

 

 

2) 부스팅 모델

  • 약한 학습자들을 순차적으로 학습시켜 강한 학습자를 만드는 방법
  • 약한 학습기
    • 단순한 모델
    • 하나의 간단한 기준으로 판단
  • 강한 학습기
    • 여러가지 조건을 복합적으로 고려
    • 높은 정확도로 불량을 판단
  • 부스팅의 핵심 원리: 순차적 학습
    • 첫 번째 모델이 잘못 분류한 데이터에 집중
    • 두 번째 모델은 이전 모델의 실수를 보완
    • 각 모델들이 서로 다른 관점에서 문제점을 발견

- 모델의 종류

2-1) AdaBoost(Adaptive Boosting) 

  • 가장 초기의 부스팅 알고리즘 
  • 잘못 분류된 데이터에 더 높은 가중치를 부여 
    • 언제 사용함? 
      • 데이터셋이 비교적 작고 노이즈가 적을 때
      • 모델의 작동 원리를 명확하게 설명해야 할 때
      • 이진 분류 문제에 효과적
      •  

2-2) Gradient Boosting Machine(GBM)

  • 경사하강법의 원리를 부스팅에 적용(그림1)
    • 경사하강법: const function 음의 기울기 방향으로 이동하면서 최솟값을 찾아나가는 방식
  • 복잡한 비선형의 관게를 잘 포착해 낼 수 있음
  • 언제 사용함? 
    • 예측 성능이 가장 중요한 고려사항
    • 데이터의 비선형성이 강할 때
    • 충분한 학습 시간을 확보할 수 있을 때

2-3) XG Boost(eXtreme Gradient Boosting)

  • 정규화 항을 도입하여 과적합을 방지
    • 유사) 선형회귀 + Regularization → 릿지(L2 정규화), 라쏘(L1정규화)
  • 병렬 처리를 통한 학습 속도 향상
  • 트리 가지치기(tree pruning)를 통해 모델의 복잡도를 제어
  • 결측치 처리를 자동화
  • 2차 미분(Hessian)을 활용하여 더 정확한 방향으로 모델 최적화
  • 언제 사용함?
    • 대규모 데이터셋을 다룰 때
    • 결측치가 많은 데이터를 다룰 때 - 자동 처리
    • 과적합 방지가 필요할 때
    • 높은 예측 성능과 적절한 학습 속도가 모두 필요할 때
  • LightGBM
    • GBM 모델의 파생 모델로, 리프 중심 트리 분할(Leaf-wise tree growth) 방식을 사용한다는 점이 가장 큰 특징 (효율성과 속도)
      • 기존의 레벨 단위 트리 분할과 달리, 가장 큰 손실 감소를 가져올 수 있는 리프 노드를 찾아 분할함으로써 더욱 효율적인 트리 구조를 만들 수 있습니다.
        • 기존 GBM 모델 : 균형 트리 분할 vs. LGMB 모델 : 리프 중심 트리 분할
        • 균형 트리 분할 : 안정적이지만, 때론 불필요한 분할도 수행 리프 중심 트리 분할 : 메모리 사용량이 적고 학습속도가 빠름 (더 적은 수의 노드로 깊은 트리를 만들 수 있기 때문)
     
    • 언제 사용함? 
      • 매우 큰 데이터셋을 다룰 때
      • 빠른 학습 속도가 필수적일 때
      • 메모리 자원이 제한적일 때
      • But, 데이터셋이 너무 적으면 과적합 위
부스트 보델 예시들
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor, AdaBoostRegressor, GradientBoostingRegressor
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import xgboost as xgb
# lightgbm은 설치되어 있지 않으므로 제외

# 데이터 생성
np.random.seed(42)
n_samples = 1000
data = {
    'income': np.random.normal(5000000, 2000000, n_samples),
    'credit_score': np.random.normal(650, 100, n_samples),
    'employment_years': np.random.normal(5, 3, n_samples),
    'dti_ratio': np.random.normal(0.3, 0.1, n_samples),
    'ltv_ratio': np.random.normal(0.6, 0.2, n_samples),
    'age': np.random.normal(40, 10, n_samples)
}
df = pd.DataFrame(data)
df['credit_score'] = df['credit_score'].clip(300, 900)
df['employment_years'] = df['employment_years'].clip(0, 40)
df['dti_ratio'] = df['dti_ratio'].clip(0, 1)
df['ltv_ratio'] = df['ltv_ratio'].clip(0, 1)
df['age'] = df['age'].clip(20, 80)

def determine_repayment_score(row):
    score = 0
    score += 1 if row['credit_score'] > 650 else 0
    score += 1 if row['dti_ratio'] < 0.4 else 0
    score += 1 if row['employment_years'] > 2 else 0
    score += 1 if row['income'] > 3000000 else 0
    score += 1 if row['ltv_ratio'] < 0.7 else 0
    score += np.random.normal(0, 0.5)
    return np.clip(score / 5, 0, 1)

df['repayment_prob'] = df.apply(determine_repayment_score, axis=1)
X = df.drop('repayment_prob', axis=1)
y = df['repayment_prob']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 회귀 모델 정의
models = {
    # 🚀 AdaBoost 회귀
    'AdaBoost': AdaBoostRegressor(
        n_estimators=100,     # 약한 학습기(기본: 결정트리) 개수
        learning_rate=0.1,    # 학습률: 낮출수록 천천히 학습
        random_state=42
    ),

    # 📈 Gradient Boosting 회귀 (GBM)
    'Gradient Boosting': GradientBoostingRegressor(
        n_estimators=100,     # 트리 개수 (많을수록 성능↑, 과적합 주의)
        learning_rate=0.1,    # 학습률
        max_depth=3,          # 각 트리의 최대 깊이 (작을수록 일반화↑)
        min_samples_split=5,  # 노드 분할을 위한 최소 샘플 수
        random_state=42
    ),

    # 💥 XGBoost 회귀 (정규화 포함, 빠르고 성능 좋음)
    'XGBoost': xgb.XGBRegressor(
        n_estimators=100,         # 트리 개수
        learning_rate=0.1,        # 학습률
        max_depth=3,              # 트리 깊이
        min_child_weight=1,       # 리프 노드의 최소 가중치 합 (작으면 과적합↑)
        subsample=0.8,            # 트리당 사용할 샘플 비율 (과적합 방지)
        colsample_bytree=0.8,     # 트리당 사용할 특성 비율
        random_state=42
    ),

    # ⚡ LightGBM 회귀 (속도 매우 빠름, 대용량 데이터 적합)
    'LightGBM': lgb.LGBMRegressor(
        n_estimators=100,         # 트리 개수
        learning_rate=0.1,        # 학습률
        max_depth=3,              # 트리 최대 깊이
        num_leaves=31,            # 리프 노드 수 (너무 크면 과적합)
        subsample=0.8,            # 샘플링 비율
        colsample_bytree=0.8,     # 특성 샘플링 비율
        random_state=42
    )
}

# 모델 학습 및 평가
print("\n📊 회귀 모델 성능 비교 (RMSE, R²)")
print("="*50)
for name, model in models.items():
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    r2 = r2_score(y_test, y_pred)
    print(f"{name:<20} | RMSE: {rmse:.4f} | R²: {r2:.4f}")
 

'빅데이터 QAQC_3기 > 빅데이터 QAQC_3기 TIL' 카테고리의 다른 글

TIL_251103  (0) 2025.11.03
TIL_251030  (0) 2025.10.30
TIL_251028  (0) 2025.10.28
TIL_251027  (0) 2025.10.27
TIL_251024  (0) 2025.10.24