[머신러닝] 데이터가 너무 한쪽으로 치우쳐있는 문제 해결하기 - bin/로그 변환/이상치 제거/Box-Cox 변환
2025. 2. 28. 21:00ㆍAI & DS/머신러닝
bin이란?
- bin은 히스토그램(histogram)에서 데이터를 나누는 구간의 개수를 의미
- 히스토그램은 연속적인 데이터를 특정 범위로 나누어 빈도수를 시각적으로 표현하는 그래프
- Bin 개수(구간 수)가 적으면?
- 너무 뭉뚱그려져서 데이터의 세부적인 분포를 확인하기 어려움
- Bin 개수(구간 수)가 많으면?
- 너무 세분화되어서 노이즈(noise)가 많아 보일 수 있음
📌 bin이 많을 때 노이즈가 증가하는 이유
- 과도한 세분화(over-segmentation)
- 데이터를 작은 구간으로 너무 많이 나누면, 각 bin에 포함된 샘플 개수가 적어짐.
- 샘플 개수가 적으면 작은 변동(랜덤한 노이즈)도 강조되어 패턴이 아닌 우연한 변동(random fluctuation)이 더 도드라져 보임.
- 데이터의 변동성이 커 보임
- bin 개수가 적으면 데이터를 전반적인 경향(trend)으로 볼 수 있음.
- 하지만 bin 개수가 많으면, 미세한 변화까지 시각적으로 강조되면서 실제 의미 없는 변동이 중요한 것처럼 보일 수 있음.
- 특히, 데이터가 원래부터 잡음이 많은 경우라면 bin을 많이 설정할수록 노이즈가 심해 보일 가능성이 큼.
- 일반화(generalization) 어려움
- bin을 많이 설정하면 데이터가 너무 좁은 범위로 나뉘어 오버피팅(overfitting)과 비슷한 효과가 나타남
- 모델이 학습할 때 불필요한 세부적인 특징까지 학습하여 오버피팅하는 것과 같은 효과
- 즉, 데이터의 근본적인 패턴을 보기 어려워지고, 작은 차이들만 강조될 수 있음.
- 같은 데이터라도 bin 개수에 따라 다르게 보일 수 있음.
- 예시 1) bin이 적을 때 (5개)
- 전반적인 분포를 쉽게 볼 수 있음. 세부적인 노이즈는 덜 보이고, 큰 패턴(trend)이 부각됨.
- 예시 2) bin이 많을 때 (50개)
- 너무 세분화되어 특정 구간의 작은 차이들이 강조됨. 원래 없던 패턴이 있는 것처럼 보일 수 있음 (노이즈 증가).
sns.histplot(df['MedInc'], bins=10) # 구간을 10개로 설정
sns.histplot(df['MedInc'], bins=50) # 구간을 50개로 설정 (더 세밀하게 표현)
- bins=10 → 데이터가 적게 나뉘어 대략적인 분포만 확인 가능
- bins=50 → 데이터가 더 세밀하게 나뉘어 패턴을 더 잘 볼 수 있음
해당 그래프에서 bin 개수 조절 이유
bins_dict={
"MedInc": 35, "HouseAge": 30, "AveRooms": 40, "AveBedrms": 40,
"Population": 50, "AveOccup": 50, "Latitude": 30, "Longitude": 30
}
- MedInc, AveRooms, AveBedrms → 이상치(outlier) 포함 가능성 있음 → bin 수를 늘려서 세부 패턴 확인
- Population, AveOccup → 일부 지역에서 급격한 변화 가능 → bin을 50개로 설정하여 작은 변화도 관찰 가능
- Latitude, Longitude → 지역적 패턴 확인 → bin을 30개로 설정
그래프 개선 방법 (로그 변환 & 정규화)
히스토그램을 보면 인구수(Population)와 가구당 평균 거주 인원(AveOccup) 등의 데이터는 한쪽으로 치우친(skewed) 분포
이 경우, 로그 변환(log transformation) 또는 정규화(normalization)을 사용하면 더 나은 해석이 가능
로그 변환 (Log Transformation)
- 한쪽으로 치우친 데이터를 정규 분포(Normal Distribution)에 가깝게 변환 가능
- 값의 차이가 클 때(예: 1 ~ 1000000) 범위를 줄여서 패턴을 더 명확하게 보이도록 만듦
로그 변환 적용 코드
import numpy as np
df['Population_log'] = np.log1p(df['Population']) # log1p(1 + x) 변환
df['AveOccup_log'] = np.log1p(df['AveOccup'])
sns.histplot(df['Population_log'], bins=30, kde=True)
plt.show()
- Population이 한쪽으로 몰려 있던 분포가 더 균형 잡힌 형태로 변형됨
- 작은 값과 큰 값의 차이가 줄어들어 해석이 더 쉬워짐
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 예제 데이터 생성 (Population 데이터 예시)
np.random.seed(42)
population = np.random.exponential(scale=10000, size=1000) # 원래 데이터 (비로그)
population_log = np.log1p(population) # 로그 변환된 데이터
# 히스토그램 그리기 (로그 변환된 데이터)
plt.figure(figsize=(10, 5))
sns.histplot(population_log, bins=50, kde=True)
# X축 눈금(로그 변환된 값) -> 원래 값으로 변환
xticks_log = np.linspace(population_log.min(), population_log.max(), 5) # 로그 스케일 값 선택
xticks_original = np.expm1(xticks_log) # 원래 값으로 변환 (exp1 = e^x - 1)
plt.xticks(xticks_log, labels=[f"{int(x):,}" for x in xticks_original]) # 원래 값으로 X축 표시
plt.xlabel("Population (Original Scale)") # X축 라벨 변경
plt.title("Histogram with Original Scale X-axis")
plt.show()
- 그래프의 데이터는 여전히 로그 변환된 상태이지만, X축 눈금만 원래 값으로 표시
- 데이터는 로그 변환된 상태로 유지됨 (왜곡된 분포를 완화하기 위해)
- X축 눈금은 원래 값으로 변환되어 가독성이 높아짐
- 모델 학습을 위해서는 로그 변환된 데이터를 사용하고, 시각화할 때만 원래 값으로 표현 가능
정규화 (Normalization)
- 데이터를 0~1 범위로 변환하여 값의 크기를 일정하게 조정하는 과정
- 데이터가 서로 다른 스케일을 가질 경우 모델이 학습하기 쉽게 만들어줌
Min-Max 정규화 적용 코드
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df[['MedInc', 'HouseAge', 'Population', 'AveRooms']] = scaler.fit_transform(df[['MedInc', 'HouseAge', 'Population', 'AveRooms']])
- 모든 데이터가 0~1 사이의 값으로 변환됨
- Population처럼 값의 크기가 큰 특성이 다른 변수보다 영향을 많이 주는 문제 해결
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler
# 데이터 로그 변환
df['Population_log'] = np.log1p(df['Population'])
df['AveOccup_log'] = np.log1p(df['AveOccup'])
# Min-Max 정규화 적용
scaler = MinMaxScaler()
df[['MedInc', 'HouseAge', 'Population', 'AveRooms']] = scaler.fit_transform(df[['MedInc', 'HouseAge', 'Population', 'AveRooms']])
# 히스토그램 다시 그리기
fig, axes = plt.subplots(4, 2, figsize=(12, 10))
fig.suptitle("Feature Distribution (After Log Transformation & Normalization)", fontsize=14)
selected_features = ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population_log', 'AveOccup_log', 'Latitude', 'Longitude']
bins_dict = {"MedInc": 35, "HouseAge": 30, "AveRooms": 40, "AveBedrms": 40, "Population_log": 30, "AveOccup_log": 30, "Latitude": 30, "Longitude": 30}
for i, feature in enumerate(selected_features):
ax = axes[i//2, i%2]
sns.histplot(df[feature], bins=bins_dict[feature], kde=True, ax=ax)
plt.show()
- Population, AveOccup의 분포가 더 균형 있게 변형됨
- 데이터가 너무 한쪽으로 몰리지 않고, 해석하기 쉬운 형태로 변환됨
- 전체적인 히스토그램이 더 직관적으로 바뀜
(좌측) 원본 데이터 (Original)
- AveRooms (상단 왼쪽)
- 한쪽(왼쪽)에 데이터가 몰려 있고, 오른쪽에 긴 꼬리 (Right-Skewed, 우측 편향)
- 평균 방 개수가 대부분 낮은 값(1~10)에 분포
- 일부 값(예: 100개 이상의 방 개수)은 극단적인 이상치 (Outliers)로 보임
- AveBedrms (하단 왼쪽)
- AveRooms와 유사하게 왼쪽에 몰려 있고, 긴 꼬리를 가짐 (우측 편향)
- 대부분 침실 개수가 1~5 사이에 존재
- 이상치가 많아 보이며, 분석 및 모델 학습에 불리할 가능성
(중앙) 로그 변환 적용 (Log Transform)
- AveRooms_log (상단 중앙)
- 데이터가 정규 분포에 가까워짐 (대칭적인 종 모양)
- 긴 꼬리가 줄어들었으며, 극단적인 이상치의 영향이 완화됨
- 모델이 데이터를 학습하기 더 적합한 형태로 변경됨
- AveBedrms_log (하단 중앙)
- AveRooms_log와 유사하게 더 정규 분포에 가까워짐
- 하지만 여전히 일부 데이터가 한쪽에 몰려 있음
로그 변환(Log Transform)의 효과
- 한쪽으로 치우친 분포(우측 편향, Skewed Right)를 완화하여 정규 분포에 가깝게 변환
- 값이 큰 이상치(Outlier)의 영향을 줄이고, 작은 값들 사이의 차이를 강조
(우측) Box-Cox 변환 적용 (Box-Cox Transform)
- AveRooms_boxcox (상단 우측)
- 가장 정규 분포(Normal Distribution)에 가까운 형태
- 대칭적인 종 모양을 가지며, 이상치의 영향을 최소화
- 로그 변환보다 더 정규 분포에 가깝게 변형됨
- AveBedrms_boxcox (하단 우측)
- AveRooms_boxcox와 유사하게 대칭적인 분포를 가짐
- 분포가 부드러워지면서, 모델 학습 시 데이터가 더 잘 활용될 가능성
Box-Cox 변환(Box-Cox Transform)의 효과
- 로그 변환보다 더 정규 분포에 가깝게 변형
- 데이터 분포를 정규성에 맞추는 데 효과적 (특히 선형 회귀 모델에 적합)
로그 변환 vs Box-Cox 변환
- 로그 변환은 간단하면서도 데이터 분포를 균형 잡히게 하는 데 효과적
- Box-Cox 변환은 로그 변환보다 더 정규 분포에 가깝게 만들지만, 데이터에 0 이하의 값이 있으면 적용 불가
'AI & DS > 머신러닝' 카테고리의 다른 글
[머신러닝] 공모전 추천 시스템(2) - chatGPT OpenAI 활용 (0) | 2025.02.28 |
---|---|
[머신러닝] 회귀 모델 - Linear Regression(선형 회귀)/Bagging Regressor(배깅 회귀)/Boosting Regressor(부스팅 회귀) (0) | 2025.02.28 |
[머신러닝] 하이퍼파라미터 / 최적의 하이퍼파라미터 찾기란 무엇인가? / Random Forest와 하이퍼파라미터 (0) | 2025.02.27 |
[머신러닝] 분류 학습 예측 모델 - KNN / Random Forest / 3가지 모델의 단점 및 원인 (0) | 2025.02.27 |
[머신러닝] 분류 학습 모델 - Logistic Regression (0) | 2025.02.27 |