멀티캠퍼스부트캠프

5주차 Note: 머신러닝

가라어퍼 2026. 5. 8. 18:07

5주차: 5월 4일 ~ 5월 8일

멀티캠퍼스 부트캠프 5주차 요약✍️

[ 5/4 ] 휴강

[ 5/5 ] 어린이날 휴강

[ 5/6 ] 시각화: Looker Studio

[ 5/7 ] 머신러닝: Outlier, dummies, 데이터 불균형, 데이터 Split

[ 5/8 ] 머신러닝: 데이터 Scaling, Regression, Classification


5월 6일👩🏻‍💻

오늘의 소감: Looker는 Tableau와 PowerPoint를 결합한 느낌? UI는 Tableau가 더 예쁘긴 한데, 편의성은 Looker가 조금 더 좋은 듯하다.

둘 모두 시각화 툴이니만큼 크게 차이점이라 할 만한 점은 보이지 않았으니, 두 툴을 함께 공부해도 좋겠다는 생각이 들었다.


수업 시간에 실습한 내용

 

Tableau는 피벗테이블의 느낌이었다면, Looker는 PPT 만드는 느낌이었달까?

두 툴들의 장점이 명확해서 자유자재로 활용할 수 있다면 정말 나의 분석에 날개를 달아줄 듯한 느낌이 들었다.

 


5월 7일👩🏻‍💻

오늘의 소감: 빅분기에서 사용할 수 있는 것들을 많이 배운 날! 시각화가 일찍 끝난 것은 아쉽지만...

학교에서 배웠던 머신러닝을 단단히 다진다 생각하고 열심히 하자!


💻 이상치

wine dataset을 활용한 이상치 처리

라이브러리, 데이터 로드
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine

wine_data = load_wine()
wine = pd.DataFrame(
    data = wine_data['data'],
    columns = wine_data['feature_names']
)
wine['class'] = wine_data['target']

wine


이상치 데이터를 확인
wine.describe()


boxplot()
plt.boxplot(wine['color_intensity'])
plt.show()

그래프로 보았을 때 이상치가 4개 정도 보인다.


이상치 필터링

 

이상치만을 골라내기 위하여 사분위수, IQR을 계산한다.

q_1, q_3 = np.percentile(wine['color_intensity'], [25, 75])
print(q_1)		# 3.2199999999999998
print(q_3)		# 6.2

# IQR 계산
iqr = q_3 - q_1

# 상단 경계 계산
iqr_top = q_3 + 1.5*iqr
# 하단 경계 계산
iqr_bottom = q_1 - 1.5*iqr

print(iqr, iqr_top, iqr_bottom)
# 2.9800000000000004 10.670000000000002 -1.2500000000000009


# 위쪽 이상치 필터링
upper_flag = wine['color_intensity'] > iqr_top
# 아래쪽 이상치 필터링
lower_flag = wine['color_intensity'] < iqr_bottom

wine.loc[upper_flag | lower_flag, ]


이상치 제거, 대체

 

# 극단치 제거
df = wine.copy()
out_idx = df.loc[upper_flag | lower_flag, ].index
df.drop(out_idx, axis=0)

# 극단치 대체
# 상단의 경계에서 벗어난 데이터는 상단의 경계 값으로 채워주고
# 하단의 경계에서 벗어난 데이터는 하단의 경계 값으로 채워준다.
df2 = wine.copy()
df2.loc[upper_flag, 'color_intensity'] = iqr_top

# 검증용 boxplot
plt.boxplot(df2['color_intensity'])
plt.show()

이상치가 제거된 것을 확인할 수 있다.


💻 범주형 데이터의 변환

 

더미 변수 생성
# class column의 값들을 범주형으로 변경
wine['class'] = wine['class'].map(
    lambda x: wine_data['target_names'][x]
)

# 더미 변수 생성
dummie_df = pd.get_dummies(wine, columns = ['class'])
dummie_df


💻 데이터의 불균형 해소

샘플링: 다수 데이터와 소수 데이터를 특정 비율로 조절해주는 기법

 

라이브러리 로드
import pandas as pd
from sklearn.datasets import make_classification
from collections import Counter
from imblearn.under_sampling import RandomUnderSampler

make_classification()

 

make_classification() : 데이터가 불균형한 랜덤 데이터를 생성

x, y = make_classification(
    n_samples= 1000,
    n_features= 5,
    weights= [0.9],
    flip_y= 0
)

# Counter: 숫자 세는 기능
Counter(y)		# Counter({np.int64(0): 901, np.int64(1): 99})

데이터 프레임으로 엮기

df = pd.DataFrame(x)
df['target'] = y

df.head()

언더 샘플링: RandomUnderSampler()

 

언더 샘플링: 다수의 라벨을 가진 데이터를 샘플링하여 소수의 데이터의 수준으로 감소시키는 방법

# RandomUnderSampler 라는 class를 생성
undersampler = RandomUnderSampler()

under_x, under_y = undersampler.fit_resample(x, y)

Counter(under_y)		# Counter({np.int64(0): 99, np.int64(1): 99})

undersampler에서 데이터의 비율을 변경
sampling_strategy 매개변수 → 소수 데이터의 비율을 의미, 0.5면 2배

undersampler2 = RandomUnderSampler(sampling_strategy = 0.3)
under_x2, under_y2 = undersampler2.fit_resample(x, y)
Counter(under_y2)		# Counter({np.int64(0): 330, np.int64(1): 99})

오버 샘플링: RandomOverSampler()

 

오버 샘플링: 소수 데이터를 다수 데이터 개수만큼 증가시켜 학습에 사용하기 위한 방법

랜덤 오버 샘플링: 소수의 데이터를 단순 복제하여 다수의 데이터와의 비율을 맞춰주는 과정

from imblearn.over_sampling import RandomOverSampler
oversampler = RandomOverSampler()
over_x, over_y = oversampler.fit_resample(x, y)
Counter(over_y)		# Counter({np.int64(0): 901, np.int64(1): 901})

# 소수의 데이터 비율을 다수의 반 정도로 샘플링

oversampler2 = RandomOverSampler(sampling_strategy=0.5)
over_x2, over_y2 = oversampler2.fit_resample(x, y)
Counter(over_y2)		# Counter({np.int64(0): 901, np.int64(1): 450})

오버 샘플링: SMOTE()

 

SMOTE: 소수 데이터의 관측값에 대한 K개의 최근접 양수를 이웃으로 찾고, 관측 값과 이웃으로 선택된 값 사이에 임의의 새로운 데이터를 생성하는 방법

from imblearn.over_sampling import SMOTE
smote = SMOTE()
sm_x, sm_y = smote.fit_resample(x, y)
Counter(sm_y)		# Counter({np.int64(0): 901, np.int64(1): 901})

SMOTE 결과 시각화
import matplotlib.pyplot as plt
import seaborn as sns

fig, axes = plt.subplots(2, 2, figsize=(15, 15))

# 4개의 산점도 그래프 생성
sns.scatterplot(
    x = x[:, 2], y = x[:, 3], ax = axes[0][0], hue = y, alpha = 0.4
)

sns.scatterplot(
    x = under_x[:, 2], y = under_x[:, 3], ax = axes[0][1], hue = under_y, alpha = 0.4
)

sns.scatterplot(
    x = over_x[:, 2], y = over_x[:, 3], ax = axes[1][0], hue = over_y, alpha = 0.4
)

sns.scatterplot(
    x = sm_x[:, 2], y = sm_x[:, 3], ax = axes[1][1], hue = sm_y, alpha = 0.4
)

axes[0][0].set_title('Origin Data')
axes[0][1].set_title('Random Under Sample')
axes[0][1].set_xlim(-3.5, 3.5)
axes[0][1].set_ylim(-4.5, 4.5)
axes[1][0].set_title('Random Over Sample')
axes[1][1].set_title('SMOTE')

plt.show()


💻 데이터 분할 (Split)

iris dataset을 활용한 이상치 처리

라이브러리, 데이터셋 로드
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris_data = load_iris()

데이터셋 전처리: 정리, 이상치 처리
iris = pd.DataFrame(iris_data['data'], columns = iris_data['feature_names'])
iris['class'] = iris_data['target']

# target 데이터들의 이름을 변환
iris['class'] = iris['class'].map(
    lambda x: iris_data['target_names'][x]
)

iris


데이터 Split: train_test_split()
X = iris.drop('class', axis=1)
y = iris['class']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size = 0.3, random_state = 42
)

# 데이터의 개수를 확인
print(f'X_train: {X_train.shape}, X_test: {X_test.shape}')
	# X_train: (105, 4), X_test: (45, 4)
print(f'y_train: {y_train.shape}, y_test: {y_test.shape}')
	# y_train: (105,), y_test: (45,)
    
y_train.value_counts()


train_test_split()의 매개변수

test_size: test 데이터의 비율 (0~1)
random_state: 임의의 데이터를 추출하는 과정에서 seed 값을 지정
shuffle: 데이터를 섞을 것인가(시계열 데이터셋인 경우에는 False)
stratify: 특정 변수를 지정하면 해당 변수를 기준으로 계층화. 해당 변수의 비율을 유지하도록 데이터 분할

X_train2, X_test2, y_train2, y_test2 = train_test_split(
    X, y, test_size = 0.3, shuffle=False, random_state = 42
)

y_train2.value_counts()


X_train3, X_test3, y_train3, y_test3 = train_test_split(
    X, y, test_size = 0.3, stratify=y, random_state=42
)

y_train3.value_counts()


5월 8일👩🏻‍💻

오늘의 소감


💻 데이터 Scaling

데이터들의 최솟값과 최댓값, 평균, 표준편차를 출력하는 함수 생성
def scaler_print(train, test):
    print(f"""
    Train Data:
        Min : {round(train.min(), 2)}
        Max : {round(train.max(), 2)}
        Mean: {round(train.mean(), 2)}
        Std : {round(train.std(), 2)}
""")

    print(f"""
    Test Data:
        Min : {round(test.min(), 2)}
        Max : {round(test.max(), 2)}
        Mean: {round(test.mean(), 2)}
        Std : {round(test.std(), 2)}
""")

Standard Scaler

 

평균이 0, 분산이 1인 정규분포로 스케일링

from sklearn.preprocessing import StandardScaler
stdscaler = StandardScaler()

X_train_sc = stdscaler.fit_transform(X_train3)
X_test_sc = stdscaler.transform(X_test3)
scaler_print(X_train_sc, X_test_sc)


Min-Max Scaler
from sklearn.preprocessing import MinMaxScaler

mnscaler = MinMaxScaler()

X_train_sc = mnscaler.fit_transform(X_train3)
X_test_sc = mnscaler.transform(X_test3)

scaler_print(X_train_sc, X_test_sc)


Max Abs Scaler
from sklearn.preprocessing import MaxAbsScaler
mascaler = MaxAbsScaler()

X_train_sc = mascaler.fit_transform(X_train3)
X_test_sc = mascaler.transform(X_test3)

scaler_print(X_train_sc, X_test_sc)


Robust Scaler

 

Robust Scaler: 평균과 분산을 이용한 Standard 대신에 중앙값과 사분위수를 활용하는 방식
중앙값을 0으로 설정, IQR을 사용하여 이상치의 영향을 최소화
quantile_range 매개변수(기본값 (25.0, 75.0)): 더 넓거나 좁은 범위의 값을 이상치로 판단하게 할 수 있다.

from sklearn.preprocessing import RobustScaler
ruscaler = RobustScaler()
ruscaler2 = RobustScaler(quantile_range=(20, 80))

X_train_sc = ruscaler.fit_transform(X_train3)
X_test_sc = ruscaler.transform(X_test3)
scaler_print(X_train_sc, X_test_sc)


X_train_sc = ruscaler2.fit_transform(X_train3)
X_train_sc = ruscaler2.transform(X_test3)
scaler_print(X_train_sc, X_test_sc)


inverse_transform

 

inverse_transform: 스케일링된 데이터를 원본 데이터로 복원

X_origin = ruscaler2.inverse_transform(X_train_sc)
pd.DataFrame(X_origin).head()


💻 회귀 분석

boston dataset을 활용한 회귀 분석

라이브러리, 데이터 로드
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_absolute_error, mean_absolute_percentage_error, \
    mean_squared_error, mean_squared_log_error, root_mean_squared_error
    
boston = pd.read_csv('../csv/boston.csv')
boston.head()

빨간색 박스 부분이 종속 변수이다.


독립변수, 종속변수 분할 후 데이터 분할
X = boston.drop(columns=['CHAS', 'Price'])
y = boston['Price']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)

모델 생성, 학습, 예측
# 모델 생성
lr = LinearRegression()

# 모델 학습
lr.fit(X_train, y_train)

# 예측
pred = lr.predict(X_test)

모델 평가

 

성능 평가 지표

MAE: | 실제값 - 예측값 |
MSE: MEAN( ( 실제값-예측값 )² )
RMSE: √ MSE
MSLE: log( MSE )
MAPE: MAE %
R² Score: SSR / SST

mae = mean_absolute_error(y_test, pred)
mse = mean_squared_error(y_test, pred)
rmse = root_mean_squared_error(y_test, pred)
mape = mean_absolute_percentage_error(y_test, pred)
r2 = r2_score(y_test, pred)

print(f"MAE: {round(mae, 2)}")				# 3.24
print(f"MSE: {round(mse, 2)}")				# 24.64
print(f"RMSE: {round(rmse, 2)}")			# 4.96
print(f"MAPE: {round(mape, 2)*100}%")			# 17.0%
print(f"R2 Score: {round(r2, 2)}")			# 0.66

💻 분류 분석

iris dataset을 활용한 분류 분석

라이브러리, 데이터 로드
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier, plot_tree
import pandas as pd

iris = pd.read_csv('../csv/iris.csv')
iris.head()

빨간색 박스 부분이 종속 변수이다.


독립변수, 종속변수 분할
X = iris.drop('species', axis=1)
y = iris['species']

모델 생성, 학습, 예측
# 모델 생성
clf = DecisionTreeClassifier(max_depth=3, random_state=42)

# 모델 학습
clf.fit(X, y)

트리 구조 시각화
feature_names = X.columns

plt.figure(figsize=(15, 15))
plot_tree(clf, feature_names=feature_names, class_names=iris['species'].unique(), fontsize=10, filled=True)
plt.show()


train, test 데이터 분할 후 모델 적합, 예측, 평가
# 라이브러리 로드
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix

# 분류 모델이기에 계층화 적용
# split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 모델 적합
clf.fit(X_train, y_train)

# 예측
pred = clf.predict(X_test)

# 평가
accuracy_score(y_test, pred)		# 0.9666666666666667
confusion_matrix(y_test, pred)
# array([[10,  0,  0],
#        [ 0,  9,  1],
#        [ 0,  0, 10]])


# 시각화
plt.figure(figsize=(15, 15))
plot_tree(clf, feature_names=X.columns, class_names=iris['species'].unique(), fontsize=10, filled=True)
plt.show()


5주차 소감

연휴가 있어서 빠르게 지나갔던 5주차!

6주차부터는 본격적인 ML, DL, 자연어 처리를 하게 될 것을 생각하니 새삼 시간이 빠르다.

곧 빅분기 실기 접수도 있으니만큼, 이번에 공부하는 내용들로 sklearn에 대한 지식을 확고히 하자.

저번 시험처럼 linear_model 생각 안 나서 모델 못 쓰지 말고

너무 자동완성에 의존하지 말고, 강사님 따라서 친다고도 생각하지 말고... 내가 내 코드를 건축하는 느낌으로 내것으로 만들자!