멀티캠퍼스 데이터분석 5월 11일 수업 내용 — 머신러닝 모델 이론, DecisionTree 실습, LinearRegression 실습
머신러닝 모델 이론
1. Logistic Regression
2. Ridge / Lasso / ElasticNet
3. Support Vector Machine (SVM)
4. Ensemble — Bagging & Boosting
5. Random Forest & XGBoost
6. K-Fold & GridSearchCV & Pipeline
실습



l1_ratio 매개변수로 L1/L2 비율을 조절 가능| 모델 | 패널티 | 특징 가중치 처리 |
|---|---|---|
| Ridge | L2 | 0에 가깝게 축소 |
| Lasso | L1 | 0으로 만들어 제거 |
| ElasticNet | L1 + L2 | 두 방식 결합 |
Ensemble 은 여러 머신러닝 모델을 결합해 더 강력한 모델을 만드는 방법입니다.
| Bagging | Boosting | |
|---|---|---|
| 학습 방식 | 병렬 | 순차 |
| 목표 | 분산 감소 | 편향 감소 |
| 속도 | 빠름 | 느림 |
| 과적합 위험 | 낮음 | 높음 (횟수 많을수록) |

| 매개변수 | 기본값 | 설명 |
|---|---|---|
criterion | 'gini' | 분할 기준 (분류: gini/entropy, 회귀: squared_error/absolute_error) |
splitter | 'best' | 분할 시 특성 선택 방식 (best: 최적 / random: 무작위) |
max_depth | None | 트리 최대 깊이 (None → 과적합 위험) |
min_samples_split | 2 | 노드 분할을 위한 최소 샘플 수 |
min_samples_leaf | 1 | Leaf 노드가 되기 위한 최소 샘플 수 |
max_features | None | 분할 시 고려할 특성 수 (None/sqrt/log2/숫자) |
min_impurity_decrease | 0.0 | 불순도 감소량이 이 값 이상일 때만 분할 수행 |
ccp_alpha | 0.0 | 비용-복잡도 가지치기 (값 클수록 트리 단순화) |
random_state | None | 재현 가능한 결과를 위한 시드값 |
| 이름 | 종류 | 설명 |
|---|---|---|
feature_importances_ | 속성 | 각 특성의 중요도 (합계 = 1) |
classes_ | 속성 | 클래스 목록 |
n_features_in_ | 속성 | 입력 특성(컬럼) 개수 |
fit(X, y) | 메서드 | 모델 학습 |
predict(X) | 메서드 | 예측 |
score(X, y) | 메서드 | 분류: 정확도 / 회귀: R² Score |
predict_proba(X) | 메서드 | 각 클래스별 예측 확률 (분류만) |
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score, f1_score, confusion_matrix, precision_score, recall_score
iris = pd.read_csv('../csv/iris.csv')
X_train, X_test, y_train, y_test = train_test_split(
iris.drop('species', axis=1),
iris['species'],
test_size = 0.2,
random_state = 42,
stratify = iris['species']
)
# max_depth 별 3개 모델 생성
clf_5 = DecisionTreeClassifier(max_depth=5, random_state=42)
clf_3 = DecisionTreeClassifier(max_depth=3, random_state=42)
clf_1 = DecisionTreeClassifier(max_depth=1, random_state=42)
clf_5.fit(X_train, y_train)
clf_3.fit(X_train, y_train)
clf_1.fit(X_train, y_train)
# 훈련 데이터 정확도 비교
print(clf_5.score(X_train, y_train))
print(clf_3.score(X_train, y_train))
print(clf_1.score(X_train, y_train))
# 테스트 데이터 예측 및 F1 Score 비교
pred_5 = clf_5.predict(X_test)
pred_3 = clf_3.predict(X_test)
pred_1 = clf_1.predict(X_test)
print(f1_score(y_test, pred_5, average='micro'))
print(f1_score(y_test, pred_3, average='micro'))
print(f1_score(y_test, pred_1, average='micro'))
feature_names = X_train.columns
class_names = y_train.unique()
plt.figure(figsize=(16, 20))
plot_tree(clf_3, feature_names=feature_names, class_names=class_names)
# min_samples_split 적용 모델
clf = DecisionTreeClassifier(max_depth=3, random_state=42, min_samples_split=40)
clf.fit(X_train, y_train)
plt.figure(figsize=(16, 20))
plot_tree(clf, feature_names=feature_names, class_names=class_names)
💡
max_depth가 클수록 훈련 데이터 정확도는 높지만 과적합 위험이 커집니다.
min_samples_split을 높이면 과적합을 억제할 수 있습니다.
df = pd.read_csv('../data/diabetes.csv')
# 컬럼 설명
# Pregnancies : 임신 횟수
# Glucose : 혈당
# BloodPressure : 이완기 혈압
# SkinThickness : 삼두근 피부 주름 두께
# Insulin : 인슐린
# BMI : 체질량 지수
# DiabetesPedigreeFunction : 당뇨 내력
# Age : 나이
# Outcome : 클래스 결정값 (1: 당뇨 / 0: 정상)
df.describe()
df['Outcome'].value_counts()
X_train, X_test, y_train, y_test = train_test_split(
df.drop('Outcome', axis=1), df['Outcome'],
test_size=0.3, stratify=df['Outcome'], random_state=42
)
clf_7 = DecisionTreeClassifier(max_depth=7, random_state=42)
clf_5 = DecisionTreeClassifier(max_depth=5, random_state=42)
clf_3 = DecisionTreeClassifier(max_depth=3, random_state=42)
clf_7.fit(X_train, y_train)
clf_5.fit(X_train, y_train)
clf_3.fit(X_train, y_train)
print(clf_7.score(X_test, y_test),
clf_5.score(X_test, y_test),
clf_3.score(X_test, y_test))
# 혼동 행렬 & 평가 지표
pred = clf_7.predict(X_test)
cm = confusion_matrix(y_test, pred)
print('정확도', accuracy_score(y_test, pred))
print('정밀도', precision_score(y_test, pred))
print('재현율', recall_score(y_test, pred))
print('F1 Score', f1_score(y_test, pred))
# 특성 중요도
clf_7.feature_importances_
import numpy as np
# 1. 혈당(Glucose) 0 → 0 제외 평균으로 대체
flag = df['Glucose'] == 0
df.loc[flag, 'Glucose'] = df.loc[~flag, 'Glucose'].mean()
# 2. 혈압(BloodPressure) 0 → 결측치로 대체 후 평균 채우기
flag2 = df['BloodPressure'] == 0
df.loc[flag2, 'BloodPressure'] = np.nan
df['BloodPressure'] = df['BloodPressure'].fillna(df['BloodPressure'].mean())
# 3. BMI 0 → 최빈값으로 대체
flag3 = df['BMI'] == 0
df.loc[flag3, 'BMI'] = df['BMI'].value_counts().index[0]
# 평가 지표 출력 함수
def score_print(y, pred):
print('정확도', accuracy_score(y, pred))
print('정밀도', precision_score(y, pred))
print('재현율', recall_score(y, pred))
print('F1 Score', f1_score(y, pred))
# 이상치 대체 후 재학습
X_train, X_test, y_train, y_test = train_test_split(
df.drop('Outcome', axis=1), df['Outcome'],
test_size=0.3, random_state=42, stratify=df['Outcome']
)
clf_7.fit(X_train, y_train)
pred = clf_7.predict(X_test)
score_print(y_test, pred)
from sklearn.preprocessing import StandardScaler
# 스케일링 적용
stdScaler = StandardScaler()
X_train_sc = stdScaler.fit_transform(X_train) # train으로 fit → transform
X_test_sc = stdScaler.transform(X_test) # test는 transform만
clf_7.fit(X_train_sc, y_train)
pred2 = clf_7.predict(X_test_sc)
print('=== 원본 데이터 ===')
score_print(y_test, pred)
print('=== 스케일링 데이터 ===')
score_print(y_test, pred2)
⚠️ 스케일링 주의사항
fit_transform()은 Train 데이터에만 사용합니다.
Test 데이터는 Train의 범위 기준을 그대로 사용해야 하므로transform()만 적용합니다.
| 매개변수 | 기본값 | 설명 |
|---|---|---|
fit_intercept | True | 절편(y절편) 사용 여부 |
copy_X | True | 입력 X를 복사하여 사용 |
n_jobs | None | 병렬 계산에 사용할 CPU 수 |
positive | False | 회귀 계수를 양수로만 제한 |
| 속성 | 설명 |
|---|---|
coef_ | 추정된 회귀 계수 (가중치) |
intercept_ | 절편 값 |
rank_ | 선형 독립 차원 수 (rank_ < 특성 수 → 다중공선성 존재) |
| 메서드 | 설명 |
|---|---|
fit(X, y) | 모델 학습 |
predict(X) | 예측 (array 반환) |
score(X, y) | 결정 계수 (R² Score) |
get_params() | 설정된 매개변수 출력 |
| 지표 | 함수 | 설명 |
|---|---|---|
| MAE | mean_absolute_error() | 오차의 절댓값 평균 |
| MSE | mean_squared_error() | 오차의 제곱 평균 |
| R² | r2_score() | 1에 가까울수록 좋은 모델 |
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
boston = pd.read_csv('../csv/boston.csv')
# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(
boston.drop('Price', axis=1),
boston['Price'],
test_size = 0.3,
random_state = 42
)
# 스케일링
stdScaler = StandardScaler()
X_train_sc = stdScaler.fit_transform(X_train)
X_test_sc = stdScaler.transform(X_test)
lr = LinearRegression() # 기본 (절편 포함)
lr_inter = LinearRegression(fit_intercept=False) # 절편 제외
# 원본 데이터로 학습 & 평가
lr.fit(X_train, y_train)
pred = lr.predict(X_test)
print('MSE:', mean_squared_error(y_test, pred))
print('R2 :', r2_score(y_test, pred))
# 스케일링 데이터로 학습 & 평가
lr.fit(X_train_sc, y_train)
pred = lr.predict(X_test_sc)
print('MSE:', mean_squared_error(y_test, pred))
print('R2 :', r2_score(y_test, pred))
# 절편 제외 모델
lr_inter.fit(X_train, y_train)
pred_inter = lr_inter.predict(X_test)
print('MSE:', mean_squared_error(y_test, pred_inter))
print('R2 :', r2_score(y_test, pred_inter))
# 회귀 계수 비교
print('절편 포함 계수:', lr.coef_)
print('절편 제외 계수:', lr_inter.coef_)
# 결정 계수 비교
print(lr.score(X_train_sc, y_train))
print(lr_inter.score(X_train_sc, y_train))
💡 스케일링이 필요한 이유
특성(컬럼)마다 값의 범위가 다르면 모델이 범위가 큰 특성에 편향되어 학습됩니다.
StandardScaler로 정규화하면 모든 특성을 동등하게 반영합니다.
💡 R² Score 해석
1→ 완벽한 예측0→ 평균만 예측하는 수준음수→ 평균보다 못한 예측
| 개념 | 설명 |
|---|---|
| 과적합 (Overfitting) | 훈련 데이터에는 잘 맞지만 새 데이터에는 틀리는 문제 |
| 규제 (Regularization) | 과적합 방지를 위해 가중치에 패널티 부여 |
| L1 패널티 (Lasso) | 가중치를 0으로 만들어 특성 제거 |
| L2 패널티 (Ridge) | 가중치를 0에 가깝게 축소 |
| 배깅 | 병렬 학습, 분산 감소 → Random Forest |
| 부스팅 | 순차 학습, 편향 감소 → XGBoost |
fit_transform() | Train 데이터에만 사용 (범위 학습 + 변환) |
transform() | Test 데이터에만 사용 (Train 범위 기준으로 변환) |
feature_importances_ | 각 특성의 중요도 (합계 = 1) |
confusion_matrix() | 예측/실제 값의 분류 결과 행렬 |
precision_score() | 정밀도 — 양성 예측 중 실제 양성 비율 |
recall_score() | 재현율 — 실제 양성 중 양성으로 예측한 비율 |
f1_score() | 정밀도와 재현율의 조화 평균 |
r2_score() | 결정 계수 — 1에 가까울수록 좋음 |
mean_squared_error() | MSE — 오차의 제곱 평균 |