카테고리 없음

내일배움캠프_[베이직반]파이썬 핵심 쏙쏙_4회차

iron-min 2025. 10. 30. 20:51

1. 오늘배운것

데이터 불균형 : 정상 범주의 관측치 수와 이상 범주의 관측치 수가 현저히 차이나는 데이터

 

정상을 정확히 분류하는 것과 이상을 정확히 분류하는 것 중 일반적으로 이상을 정확히 분류하는 것이 더 중요

왜냐하면 보통 이상 데이터가 target값이 되는 경우가 많기 때문

 

1. 불균형 데이터의 위험

  • 정확도 함정: 불균형 데이터로 학습된 모델은 다수 클래스(정상)에 치우친 예측을 할 가능성이 높습니다. 전체 데이터 100% 정상 95% 불량 5%
  • 결함 탐지 실패: 소수 클래스(불량)를 충분히 학습하지 못하면 결함 제품을 놓칠 위험이 있습니다. 이는 품질 문제로 이어질 수 있습니다.

2. QA/ QC에서의 목표

  • 데이터 균형 유지: 데이터셋을 구축할 때 클래스 균형을 최대한 맞추는 것이 중요합니다.
  • 데이터 증강 기법이나 샘플링 기법을 활용하거나, 생산 환경에서 결함 데이터를 의도적으로 추가 수집합니다.

3. QA에서의 해결 방안

  • 데이터 수집 전략 강화:
    • 소수 클래스(불량) 데이터를 더 많이 수집하는 방안을 마련or 샘플링 기법.
    • 생산 환경에서 다양한 불량 케이스를 시뮬레이션하거나 의도적으로 생성.
  • 모델 검증 강화:
    • 불균형 데이터 상황에서 과소 적합(underfitting)이나 과적합(overfitting)을 방지하기 위한 교차 검증 및 다양한 시나리오 기반 테스트 수행

 

 

데이터의 불균형을 해결하는 법

언더 샘플링과 오버 샘플링의 기법

 

 

언더 샘플링: 다수 범주의 데이터를 소수 범주의 데이터 수에 맞게 줄이는 샘플링 방식을 말함.

 

 1) Random Sampling Random Sampling : 다수 범주에서 무작위로 샘플링을 하는 것

 

 

코드예시)

import numpy as np
import pandas as pd
from sklearn.utils import resample

# 예제 데이터셋 생성
data = {'feature1': np.random.randn(1000),  # 랜덤 피처 데이터
        'feature2': np.random.randn(1000),
        'class': [0] * 900 + [1] * 100}    # 클래스 불균형 (0: 900개, 1: 100개)
df = pd.DataFrame(data)

# 클래스 분리
df_majority = df[df['class'] == 0]  # 다수 클래스 (0)
df_minority = df[df['class'] == 1]  # 소수 클래스 (1)

# 랜덤 언더샘플링
df_majority_downsampled = resample(df_majority,
                                   replace=False,  # 복제하지 않음
                                   n_samples=len(df_minority),  # 소수 클래스 크기와 동일
                                   random_state=42)  # 재현성을 위해

# 언더샘플링 데이터 병합
df_balanced = pd.concat([df_majority_downsampled, df_minority])

print("언더샘플링 전 데이터 분포:")
print(df['class'].value_counts())

print("\n언더샘플링 후 데이터 분포:")
print(df_balanced['class'].value_counts())

 

 

2) Tomek Links : 두 범주 사이를 탐지하고 정리를 통해 부정확한 분류경계선을 방지하는 방법

 

다른 클래스의 데이터 두 개를 연결했을 때 주변에 다른 임의의 데이터 Xk가 존재할 때

선택한 두 데이터에서 Xk까지의 거리보다 선택한 두 데이터 사이의 거리가 짧을 때 선택한 두 데이터 간의 링크를 Tomek Link라 부릅니다.

 

 

 

코드예시)

from imblearn.under_sampling import TomekLinks
import numpy as np
import pandas as pd

# 예제 데이터 생성
np.random.seed(42)
X = np.vstack((np.random.normal(0, 1, (100, 2)), np.random.normal(3, 1, (10, 2))))  # 피처 데이터
y = np.array([0] * 100 + [1] * 10)  # 클래스 라벨 (불균형)

# Tomek Link 적용
tomek = TomekLinks(sampling_strategy='auto')  # 다수 클래스 데이터만 제거
X_resampled, y_resampled = tomek.fit_resample(X, y)

# 결과 출력
print("Tomek Link 적용 전 데이터 크기:", X.shape)
print("Tomek Link 적용 후 데이터 크기:", X_resampled.shape)
print("원래 클래스 분포:", pd.Series(y).value_counts())
print("Tomek Link 적용 후 클래스 분포:", pd.Series(y_resampled).value_counts())

 

 

 

오버 샘플링: 다수 범주의 데이터를 소수 범주의 데이터 수에 맞게 줄이는 샘플링 방식을 말함.

 

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

 

from sklearn.utils import resample
import pandas as pd

# 데이터 생성
data = {'feature': [1, 2, 3, 4, 5, 6], 'class': [0, 0, 0, 0, 0, 1]}  # 클래스 0이 다수
df = pd.DataFrame(data)

# 소수 클래스 분리
df_majority = df[df['class'] == 0]
df_minority = df[df['class'] == 1]

# 랜덤 오버샘플링
df_minority_oversampled = resample(df_minority,
                                   replace=True,     # 복제 허용
                                   n_samples=len(df_majority),  # 다수 클래스와 동일한 크기로
                                   random_state=42)  # 재현성

# 오버샘플링 데이터 병합
df_oversampled = pd.concat([df_majority, df_minority_oversampled])

print("오버샘플링 전 데이터 분포:")
print(df['class'].value_counts())
print("\n오버샘플링 후 데이터 분포:")
print(df_oversampled['class'].value_counts())

 

 2) SMOTE : 소수 범주에서 가상의 데이터를 생성하는 방법

 

K값을 정한 후 소수 범주에서 임의의 데이터를 선택한 후

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

 

 

from imblearn.over_sampling import SMOTE
import numpy as np
import pandas as pd

# 데이터 생성 (불균형 데이터셋)
X = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [10, 10], [20, 20]])  # 특징 데이터
y = np.array([0, 0, 0, 0, 0, 1])  # 클래스 (불균형 데이터)

print("SMOTE 적용 전 클래스 분포:")
print(pd.Series(y).value_counts())

# SMOTE 초기화 (k_neighbors=2)
smote = SMOTE(k_neighbors=2, random_state=42)

#훈련데이터 테스테로 분할 후에 해야한다.
x_train, x_test

# 데이터 오버샘플링
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)


print("\nSMOTE 적용 후 클래스 분포:")
print(pd.Series(y_resampled).value_counts())

print("\nSMOTE로 생성된 데이터:")
print(X_resampled)

 

 

인코딩

 

코드예시)

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder

# 예시 데이터
df = pd.DataFrame({
    "color": ["red", "blue", "green", "blue", "red"],
    "size": ["S", "M", "L", "M", "L"],
    "price": [100, 150, 200, 130, 170]
})

X = df[["color", "size"]]
y = df["price"]

# 1) Train/Test 분리 먼저!
X_train, X_test = train_test_split(X, test_size=0.2, random_state=42)

# 2) Label Encoding (size는 S<M<L 순서가 있음)
le = LabelEncoder()
X_train["size"] = le.fit_transform(X_train["size"])  # Train으로 fit
X_test["size"] = le.transform(X_test["size"])        # Test는 transform만

# 3) One-Hot Encoding (color는 순서 없음)
ohe = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
X_train_color = ohe.fit_transform(X_train[["color"]])
X_test_color = ohe.transform(X_test[["color"]])

print("인코딩 완료")
print(X_train)
print(X_train_color)

 

 

스케일링

필요한 이유: 모델이 숫자를 볼 때 스케일 차이 때문에 특정 변수만 중요하다고 착각할 수 있다.

 

 

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 예시 데이터 생성
data = {
    "price": [100, 150, 200, 130, 170, 210, 190, 160, 180, 140]  # 수치형 피처
}
df = pd.DataFrame(data)

# Train/Test 분리
X_train, X_test = train_test_split(df, test_size=0.3, random_state=42)

# StandardScaler 사용
scaler = StandardScaler()

# Train 데이터로 fit하고 transform
X_train_scaled = scaler.fit_transform(X_train[["price"]])

# Test 데이터는 transform만 적용
X_test_scaled = scaler.transform(X_test[["price"]])

print("===== 원본 데이터 (Train) =====")
print(X_train.head())

print("\n===== 표준화 데이터 (Train 결과) =====")
print(X_train_scaled[:5])

print("\n===== 표준화 시 사용된 평균, 표준편차 =====")
print("평균(mean):", scaler.mean_)
print("표준편차(std):", scaler.scale_)

 

 

중요한 규칙

Train/Test Split 먼저 하고 → 그 다음 인코딩/스케일링

fit은 Train만 (fit_transform)

Test에는 transform만

✅ SMOTE는 오버샘플링이고, Train ,test 분할 후 Train 에만 적용한다.

Test 정말 우리 모델이 완벽하게 예측하는지 검증하기 위한 데이터셋이기때문에

절대절대 건드려서는 안된다.