빅데이터 QAQC_3기/빅데이터 QAQC_3기 TIL

TIL_251030

usungusung 2025. 10. 30. 20:13

Today I learned

 

 

1. QAQC 문제풀이

링크 닫힘으로 열람 불가

 

2. [라이브세션] 파이썬 베이직반 4회차

 

1. 샘플링

1) 데이터 불균형

  • 정상 범주의 관측치 수와 이상 범주의 관측치 수가 현저히 차이나는 데이터
  • 정상 데이터가 많고 불량 데이터가 매우 적을 때 발생
  • 불균형 데이터의 위험성
    • 정확도 함정: 불균형 데이터로 학습딘 모델은 정상에 치우친 예측을 할 가능성이 높음
    • 결함 탐지 실패: 불량을 충분히 학습하지 않으면 제품 결함을 놓칠 가능성이 있음
  • 해결 방안
    • 불량 데이터를 더 많이 수집, 샘플링 방법을 마련
    • 불량 케이스를 의도적으로 생성
    • 모델 검증 강화

 

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

  • 데이터 불균형을 해결하기 위해 나온 개념

 

언더 샘플링 오버 샘플링
- 다수 데이터를 소수 데이터에 맞게 수를 줄임
- 학습에 사용되는 전체 데이터 수를 감소시키기 때문에, 오히려 성능이 감소할 수 있음
소수 범주의 데이터를 다수 범주의 데이터에 맞게 늘림
Random Sampling, Tomek Links Resampling, SMOTE

 

 

2-1) 언더샘플링 - 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)
데이터를 만들어놓은거임
클래스 불균형을 의도적으로 배치
0이 900개, 1이 100개
# 클래스 분리
df_majority = df[df['class'] == 0]  # 다수 클래스 (0)
df_minority = df[df['class'] == 1]  # 소수 클래스 (1)
- df_majority: ['class'] 칼럼의 0만 모은 데이터, 900개
- df_minority: ['class'] 칼럼의 1만 모은 데이터, 100개
# 랜덤 언더샘플링
df_majority_downsampled = resample(df_majority,
                                   replace=False,  # 복제하지 않음
                                   n_samples=len(df_minority),  # 소수 클래스 크기와 동일
                                   random_state=42)  # 재현성을 위해
- resample(): sklearn의 샘플링 함수(데이터를 무작위로 뽑음)
- replace = False: 복원 추출 금지
- n_samples = len(df_minority) : 다수 클래스(0)의 갯수를 소수 클래스(1)의 갯수로 줄이기
# 언더샘플링 데이터 병합
df_balanced = pd.concat([df_majority_downsampled, df_minority])

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

print("\n언더샘플링 후 데이터 분포:")
print(df_balanced['class'].value_counts())
 
줄어든 다수 클래스 데이터 100개 + 원래의 소수 클래스 데이터 100개 합침

0과 1의 비율이 1:1로 균등한 200개의 데이터셋 완성

 

 

2-2) 언더샘플링 - Tomek Links

  • 두 범주 사이를 탐지하고 정리를 통해 부정확한 분류경계선을 방지하는 방법
  • 선택한 두 데이터에서 Xk까지의 거리보다 선택한 두 데이터 사이의 거리가 짧을 때 선택한 두 데이터간의 링크를 Tomek link라고 부름

 

2-3) 오버샘플링 - 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)
 데이터를 만듦
class 항목에 0이 5개, 1이 1개로 이상 데이터가 너무 적은 형태
# 소수 클래스 분리
df_majority = df[df['class'] == 0]
df_minority = df[df['class'] == 1]
- df_majority = [1,2,3,4,5]
- df_minority = [6]
두 클래스로 나
f# 랜덤 오버샘플링
df_minority_oversampled = resample(df_minority,
                                   replace=True,     # 복제 허용
                                   n_samples=len(df_majority),  # 다수 클래스와 동일한 크기로
                                   random_state=42)  # 재현성
- resample : 무작위 샘플링 함수
- replace = True: 복원 추출을 허용함
- n_sample = len(df_majority): 소수의 클래스를 다수 클래스 만큼 갯수를 맞춤
즉 이렇게 됨
   - df_majority = [1,2,3,4,5]
   - df_minority = [6,6,6,6,6]
# 오버샘플링 데이터 병합
df_oversampled = pd.concat([df_majority, df_minority_oversampled])

print("오버샘플링 전 데이터 분포:")
print(df['class'].value_counts())
print("\n오버샘플링 후 데이터 분포:")
print(df_oversampled['class'].value_counts())
데이터를 병합하여 총 10개의 균형잡힌 데이터셋이 나옴

 

 

2-4) SMOTE(중요)

  • SMOTE 방법은 소수 범주에서 가상의 데이터를 생성한느 방법
  • 기존 소수 클래스 데이터를 기반으로 새로운 데이터를 선형 보간 하여 생성함
  • K값을 정한 후 소수 범주에서 임의의 데이터를 선택, 선택된 데이터와 가장 가까운 K개의 데이터 중 하나를 무작위로 선정해 Synthetic 공식을 통해 가상의 데이터를 생성하는 방법

red: 이상 데이터, green: 선형 보간되어 새로 생성된 이상 데이터

 

2. 인코딩

  • 머신러닝은 숫자만 이해함 - 문자 데이터를 숫자로 바꿔야 함
  • 인코딩 종류
구분 Label Encoding One-Hot Encoding
뭐임 카테고리를 숫자 하나로 변환 각 카테고리를 컬럼으로 나누고 0/1 표시
예시 red = 0, blue = 1, green = 2 red = [1,0,0], blue = [0,1,0], green = [0,0,1]
사용 데이터 순서가 있는 데이터(서열형) 순서 없는 데이터(명목형)
예시 의류 사이즈 S<M<L 색상, 지역, 브랜드
주의사항 숫자 크기 때문에 '순서 오해'위험 컬럼 개수가 늘어남

 

인코딩 파이썬 실습
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)
Train/Test 데이터 분리
# 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만

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


의류 사이즈 별로 S = 2, M = 1, L = 0로 인코딩
(LabelEncoder는 기본적으로 사전순으로 변환)
# 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_color)
 

red = [1,0,0]
blue = [0,1,0]
green = [0,0,1]

 

 

- Train, Test 분할 후 인코딩을 진행하는 이유

  • 분할 전에 인코딩/스케일링을 하게 되면 테스트 데이터의 정보가 학습 기준에 섞임
  • 모델이 테스트 분포를 '미리 확인한 상태'가 되어 성능이 뻥튀기
  • 인코딩도 마찬가지.
    • 분할 미진행 시 테스트 데이터 정보를 미리 훔쳐본 것과 같음

 

3. 스케일링

  • 각 변수별로 수 차이가 클 때 머신러닝 모델이 특정 변수만 중요하다고 착각 할 수 있다.
    • 키 170, 몸무게 70, 연봉 45,000,000 이런 데이터가 있으면 연봉 변수를 더 크게 보지 않을까?
  • 따라서 스케일링으로 데이터를 변환시켜주는 작업이 필요함
구분 StandardScaler MinMaxScaler
하는 일 평균 0, 표준편차 1로 변환 데이터 0~1 범위로 변환
사용 데이터가 정규 분포와 유사할 때, 또는 이상치의 영향이 상대적으로 덜 중요할 때. Min-Max Scaling은 데이터 분포가 정규분포와 다르거나 왜도가 있어도 적용 가능하며, 데이터의 상대적 구조와 비율을 손대지 않으면서 0~1 범위로 선형 변환하는 비모수적 정규화 방법
특징 이상치(Outlier)의 영향을 받지만, 전체적인 데이터 분포의 모양을 유지하며 넓은 범위로 스케일링 될 수 있음. 이상치(Outlier)의 영향을 크게 받아 이상치가 Min 또는 Max 값일 경우 대부분의 데이터가 좁은 범위에 몰릴 수 있음.
스케일링 파이썬 실습
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_)

 

 

'빅데이터 QAQC_3기 > 빅데이터 QAQC_3기 TIL' 카테고리의 다른 글

TIL_251105  (0) 2025.11.05
TIL_251103  (0) 2025.11.03
TIL_251029  (1) 2025.10.29
TIL_251028  (0) 2025.10.28
TIL_251027  (0) 2025.10.27