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, 데이터셋이 너무 적으면 과적합 위
- GBM 모델의 파생 모델로, 리프 중심 트리 분할(Leaf-wise tree growth) 방식을 사용한다는 점이 가장 큰 특징 (효율성과 속도)
| 부스트 보델 예시들 | |
|
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 |
















