강의/데이터 분석 심화

[ 데이터 분석 심화 ] 머신러닝 기초 | 머신러닝 전처리 핵심 기술

da-hong 2025. 6. 27. 00:47
📺 라이브세션 
강의: 머신러닝 오프닝 2회차 
날짜: 6월 25일 오후 3:00

 

1. 인코딩 (Encoding)

: 범주형 데이터숫자로 변환하는 과정

- 머신러닝 모델은 숫자만 입력받을 수 있고, 문자열 그대로 넣으면 모델이 학습하지 못함

 

🔹 One-Hot Encoding

  • 사용 대상
    • 순서가 없는 범주형 변수 (예: 성별, 혈액형)
    • 범주의 개수가 너무 많지 않을 때
  • 동작 방식
    • 각 범주를 새로운 열로 만들어 0과 1로 표시
    • 예: 혈액형(A, B, O) → A열(1,0,0), B열(0,1,0), O열(0,0,1)

 

💻 실습

 

아래 혈액형(원본) 데이터에서 'blood_type'은 순서가 없는 범주형 변수이다. pd.get_dummies( )를 사용해 OneHotEncoding을 해주면 각 혈액형이 새로운 열로 만들어져서 불리언 타입으로 표시되고, dtype = int 로 설정해주면 1, 0으로 변환된다. 

#pandas에 있는 get_dummies를 사용하여 OneHotEncoding
df_encoded = pd.get_dummies(df, columns=['blood_type'], dtype=int)

 

🔹 Label Encoder

  • 사용 대상
    • 순서가 있는 범주형 변수 (예: low < medium < high초급 < 중급 < 고급)
    • 범주는 있지만 One-hot을 쓰기엔 너무 많은 경우
  • 동작 방식
    • 각 범주에 대해 고유한 정수값을 할당
    • 예: 만족도(만족, 보통, 불만) → 만족: 2, 보통: 1, 불만: 0

 

💻 실습

 

아래 만족도(원본) 데이터에서 'satisfaction'은 순서가 있는 범주형 변수이다. 일단 Scikitlearn에서 LabelEncoder 를 import 해서 객체를 생성해준다. fit_transform( ) 메서드를 사용하면 satisfaction 컬럼의 각 고유 값이 0부터 시작하는 정수값으로 변환되어 'satisfaction_encoded' 라는 새로운 열이 생성된다. 

from sklearn.preprocessing import LabelEncoder 
le = LabelEncoder() #객체 생성(선언)
df['satisfaction_encoded'] = le.fit_transform(df['satisfaction']) #변환하여 적용

 


2. 스케일링 (Scaling)

: 수치형 데이터의 단위(스케일)를 맞춰 민감도를 완화하는 전처리 과정

- 머신러닝 모델은 입력 변수들의 크기 차이에 민감해서 스케일이 크거나 단위가 다른 변수는 모델이 편향되게 학습할 수 있음

 

🔹 StandardScaler (표준화)

  • 사용 대상
    • 데이터가 정규분포에 가깝거나 대칭적일 때
    • 값의 분포 자체를 보존하고 싶을 때 
    • 선형회귀, 로지스틱 회귀, SVM, KNN, PCA 등
  • 동작 방식
    • 각 값을 평균 0, 표준편차 1로 변환
    • 데이터의 모양(분포 곡선)은 유지하면서, 중심0으로 옮기고 크기1로 맞춤
  • 주의: 이상치가 있으면 평균과 표준편차가 흔들릴 수 있음

 

💻 실습

Scikitlearn에서 StandardScaler 를 import 해서 객체를 생성해주고  fit_transform( ) 메서드를 사용하면 데이터가 평균이 0, 표준편차가 1로 스케일링 된다. 

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)

 

🔹 MinMaxScaler (정규화)

  • 사용 대상
    • 데이터 분포가 비정규형일때
    • 값의 범위를 일정한 크기로 맞춰야 할 때
  • 동작 방식
    • 각 값을 0~1 사이로 변환
  • 주의: 이상치가 하나라도 있으면 전체 범위가 압축될 수 있음

 

💻 실습

Scikitlearn에서 StandardScaler 를 import 해서 객체를 생성해주고  fit_transform( ) 메서드를 사용하면 데이터의 값들이  평균이 0~1 사이로 스케일링 된다. 

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)


3. 다중공선성 제거 

다중공선성 

  • 정의: 독립 변수들(Features) 간에 강한 상관관계가 존재하는 현상
  • 문제점 
    • 회귀 계수(Weight) 추정이 불안정해짐 - 선형모델 
    • 모델 해석이 왜곡될 가능성 
    • 모델의 성능훈련 데이터 효율성 저하
  • 주로 선형모델(선형회귀,로지스틱 회귀 등)에서 발생하지만 비선형 모델에서도 불필요한 변수가 많아져 모델의 복잡도가 증가(과적합)될 경우 다중공선성이 문제될 수 있음
    • 비선형 모델(랜덤 포레스트, XGBoost)은 선형 모델과 다르게 변수 간의 독립성을 가정하지 않기 때문에 다중공선성의 영향을 받지 않거나, 적게 받는 경향이 있음 

*️⃣ 과적합

  • 정의: 머신러닝 모델이 학습 데이터에 지나치게 최적화되어, 새로운 데이터에 대한 예측 성능이 저하되는 현상
  • 원인: 너무 복잡한 모델  /  훈련 데이터 부족  /  노이즈가 많은 데이터 
  • 방지: 모델 단순화  /  많은 훈련 데이터 확보  /  정규화(L1/L2), 교차 검증 등
  • 다중 공선성이 있으면 모델 복잡도 증가와 정보 중복으로 과적합 가능성 증가 불필요한 변수 제거로 모델을 단순화하여 과적합 방지 필요

 

🔹 VIF 기반 변수제거

  • VIF(Variance Inflation Factor) 값이 높으면 해당 변수는 다른 변수들과 높은 상관관계를 가짐
  • 일반적으로 VIF ≥ 10 → 다중공선성이 높다고 판단하고 제거 고려
  • 방법:
    1. 모든 변수에 대해 VIF를 계산
    2. VIF 값이 가장 높은 변수를 제거하고 다시 VIF 계산
    3. VIF 값이 10 이하가 될 때까지 반복
from statsmodels.stats.outliers_influence import variance_inflation_factor

def calculate_vif(X):
    vif_data = pd.DataFrame()
    vif_data["Variable"] = X.columns
    vif_data["VIF"] = [variance_inflation_factor(X.values, i)
                       for i in range(X.shape[1])]
    return vif_data.sort_values('VIF', ascending=False)

 

🔹 상관관계 기반 변수 제거

  • 피어슨 상관계수를 계산하여 상관계수 0.9 이상인 변수 쌍 중 하나를 제거
  •  방법:
    1. 피어슨 상관행렬을 계산
    2. 상관계수가 0.9 이상인 변수 쌍을 찾음
    3. 도메인 지식이나 모델 성능을 고려하여 제거할 변수를 결정
# 상관계수 행렬 계산
corr_matrix = df_numeric.corr().abs()

# 상관관계가 높은 변수 찾기
threshold = 0.9
high_corr_vars = set()

for i in range(len(corr_matrix.columns)):
    for j in range(i):
        if corr_matrix.iloc[i, j] > threshold:
            colname = corr_matrix.columns[i]
            high_corr_vars.add(colname)

# 상관계수가 높은 변수 제거
df_corr_reduced = df_numeric.drop(columns=high_corr_vars)

print("제거된 변수들:", high_corr_vars)

 

🔹 PCA 분석

  • 다중공선성이 높은 변수를 직접 제거하지 않고, 새로운 축으로 변환하여 차원을 줄이는 방법
  • PCA(Principal Component Analysis)를 사용하여 주요 정보를 유지하면서 변수를 축소
  •  방법:
    1. 주성분 개수(n_components)를 결정
    2. PCA를 적용하여 새로운 변수로 변환
    3. 변환된 변수를 모델에 사용
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 데이터 표준화(데이터의 크기가 PCA에 영향을 미치므로 StandardScaler() 적용)
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df_numeric)

# PCA 적용
pca = PCA(n_components=0.95)  # 설명된 분산 95% 유지
df_pca = pca.fit_transform(df_scaled)

print(f"PCA 적용 후 차원 수: {df_pca.shape[1]}")

 

*️⃣ 다중공선성 처리 기준

  • 해석 목적: 다중공선성 처리 필요(but 도메인 지식 기반 처리❗️) - 변수 하나하나의 영향력을 정확히 보기 위해
  • 예측 목적: 다중공선성 처리 불필요 - 모델의 해석(변수 중요도)에 영향을 줄 수 있지만 예측 결과 자체에는 영향 X

4. 데이터 분할 

  • 모델을 훈련하고 평가하기 위해 데이터를 훈련 데이터(Train)와 테스트 데이터(Test)로 나눈다.
  • 모델이 훈련 데이터만 잘 맞추고 테스트 데이터에선 못 맞추는 과적합(overfitting)을 방지하기 위함
  • 보통 train : test = 7:38:26:4 등 사용
    • 훈련 데이터: 모델 학습에 사용
    • 테스트 데이터: 모델이 본 적 없는 데이터로, 일반화 성능 평가
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42) # 7:3 비율
# random_state=숫자 → 무작위 분할의 결과를 고정시켜서 재현 가능한 결과 확보

 


5. 샘플링 (Sampling)

데이터 불균형 

  • 불균형 데이터: 정상 범주의 관측치 수이상 범주의 관측치 수현저히 차이나는 데이터 (예: 양품-1만개, 불량품-100개)
  • 일반적으로 소수 클래스(불량)를 정확히 분류하는 것이 더 중요한데, 불균형 데이터로 학습된 모델은 다수 클래스(정상)에 치우친 예측을 할 가능성이 높음 → 정확도는 높아도 불량은 감지 못함 

➡️ 샘플링 기법이나 데이터 증강 기법을 활용하여 데이터의 균형을 최대한 맞추는 것이 중요 

🔹 언더 샘플링

: 다수 범주의 데이터를 소수 범주의 데이터 수에 맞게 줄이는 샘플링 방식

- 단점: 정보 손실 가능 → 거의 쓰이지 않음

 

▪️Random Sampling

: 다수 범주에서 무작위로 샘플링을 하는

from sklearn.utils import resample
df_majority_downsampled = resample(df_majority,
                                   replace=False,  
                                   # 중복 불가(비복원 추출) 
                                   # 언더샘플링 권장 설정
                                   n_samples=len(df_minority),  
                                   # 소수 클래스 크기와 동일
                                   random_state=42) 
                                   # 재현성을 위해

 

▪️Tomek Links

: 데이터 간 경계가 불분명한 샘플을 제거하여 클래스 간 분리도를 높이는 방법

- 서로 다른 클래스인데 서로가 가장 가까운 이웃이면 Tomek Link 쌍으로 판단하고 다수 클래스의 샘플만 제거

 

🔹 오버 샘플링

: 소수 범주의 데이터를 다수 범주의 데이터 수에 맞게 늘리는 샘플링 방식

 

▪️Resampling

: 소수 클래스 데이터를 단순 복제하여 데이터 양을 증가

- 소수 범주에 과적합이 발생할 수 있다는 단점 있음 

from sklearn.utils import resample
df_minority_oversampled = resample(df_minority,
                                   replace=True,     
                                   # 중복 가능(복원추출)
                                   # 오버샘플링 필수 설정
                                   n_samples=len(df_majority),  
                                   # 다수 클래스와 동일한 크기로
                                   random_state=42)  
                                   # 재현성

 

▪️SMOTE

:  기존 소수 클래스 데이터를 기반으로, 새로운 가상의 데이터를 선형 보간(interpolation)하여 생성

- 임의로 선택한 데이터와 가장 가까운 K개의 데이터 중 하나를 무작위로 선정해 Synthetic 공식을 통해 가상의 데이터를 생성하는 방법

from imblearn.over_sampling import SMOTE
smote = SMOTE(k_neighbors=2, random_state=42) # SMOTE 초기화 (k_neighbors=2)
X_resampled, y_resampled = smote.fit_resample(X, y) # 데이터 오버샘플링