변수 구간화(Binning)이란 무엇일까?
변수 구간화(binning)는 연속형 변수를 몇 개의 범주(category) 또는 구간(bin)으로 나누는 과정이다. 즉 연속형 변수를 이산인 범주형 또는 순위형 번수로 변환하는 기법이다. 주로 분석의 단순화, 노이즈 감소, 모델의 성능 향상을 위해 사용된다. 변수 구간화가 중요한 이유는 다음과 같다.
1.
모델의 복잡성 감소: 연속형 변수를 구간화함으로써 모델이 처리해야 하는 데이터의 복잡성을 줄일 수 있습니다. 이는 특히 의사결정트리(decision trees)나 룰 기반 시스템(rule-based systems)과 같은 모델에서 유용합니다.
2.
노이즈와 이상치 처리: 데이터에 존재하는 노이즈나 이상치(outliers)의 영향을 줄일 수 있습니다. 연속 변수의 작은 변동이 결과에 미치는 영향을 완화시키는 데 도움이 됩니다.
3.
비선형 관계 포착: 구간화를 통해 변수 간의 비선형 관계를 더 잘 포착할 수 있습니다. 이는 특히 선형 모델에서 변수 간의 복잡한 관계를 모델링하는 데 도움이 됩니다.
4.
이해와 해석 용이성: 구간화된 데이터는 종종 해석하기가 더 쉽습니다. 예를 들어, 연령을 "청소년", "성인", "노인"과 같은 범주로 나누면 데이터의 해석과 시각화가 더 용이해질 수 있습니다.
5.
모델의 안정성 향상: 특히 작은 데이터셋에서, 구간화는 모델의 예측 안정성을 향상시킬 수 있습니다. 데이터의 미세한 변화가 모델의 예측에 미치는 영향을 줄여줍니다.
6.
특정 알고리즘과의 호환성: 몇몇 기계 학습 알고리즘은 범주형 데이터를 더 잘 처리할 수 있으며, 구간화는 연속형 데이터를 이러한 알고리즘에 적합하게 변환할 수 있습니다.
Q1. 연속형 변수를 구간화 하면서 어느 정도의 정보량의 손실을 감수해야 할 것임을 알 수 있다. 그렇다면, 변수 구간화의 이점을 최대한 보존하면서 정보량의 손실을 최소화하려면 어떻게 구간화는 것이 좋을지 한번 생각해보자.
변수 구간화 방법
변수를 구간화하는 방법으로는 크게 세가지 방법이 있다.
1.
등간격 구간화(equal-width binning): 피쳐의 전체 범위를 같은 간격으로 나누는 방법이다.
2.
등빈도 구간화 (Equal-frequency binning): 각 구간에 동일한 수의 샘플이 있도록 나누는 방법이다.
3.
등밀도 구간화(density-based binning): 데이터의 분포를 기반으로 구간을 나누는 방법으로 데이터의 밀도가 높은 부분을 더 작은 구간으로 나누고, 밀도가 낮은 부분은 더 큰 구간으로 나눈다.
등간격 구간화와 등빈도 구간화는 pandas에서 제공하는 cut, qcut 함수를 활용하여 해볼 수 있다. 다음과 같이 나이를 담은 데이터프레임을 활용하여 실습을 진행해보자.
import pandas as pd
import numpy as np
# 임의의 데이터 생성
data = {'age': np.random.randint(18, 60, size=100)}
df = pd.DataFrame(data)
Python
복사
등간격 구간화는 다음과 같다.
# 등간격 구간화
df['age_bin'] = pd.cut(df['age'], bins=4)
print(df.head())
Python
복사
bins 파라미터를 통해 원하는 수의 구간을 설정할 수 있다.
등빈도 구간화는 다음과 같다.
# 등빈도 구간화
df['age_quantile_bin'] = pd.qcut(df['age'], q=4)
print(df.head())
Python
복사
q 파라미터를 조절하여 구간별 퀀타일을 바꿔가면서 원하는 구간을 설정할 수 있다.
등밀도 구간화는 샘플의 밀도를 기반으로 추정을 하기에 샘플의 분포를 가정해야 한다. 간단하게 표준정규분포 데이터셋을 활용하여 scipy.stats 에서 제공하는 gaussian_kde 함수를 이용해 밀도를 구하여 등밀도 구간화를 시각해보자.
import numpy as np
import pandas as pd
from scipy.stats import gaussian_kde
import matplotlib.pyplot as plt
# 샘플 데이터 생성
np.random.seed(0)
data = np.random.normal(0, 1, 1000)
df = pd.DataFrame(data, columns=['value'])
# 가우시안 KDE를 사용하여 데이터의 밀도 추정
kde = gaussian_kde(df['value'])
# 미세한 그리드 위에서 밀도 평가
density_values = kde(np.linspace(min(data), max(data), 1000))
# 밀도에 따라 데이터 정렬
df_sorted = df.copy()
df_sorted['density'] = kde(df_sorted['value'])
df_sorted.sort_values('density', ascending=False, inplace=True)
# 밀도를 기준으로 구간 나누기
n_bins = 4
df_sorted['bin'] = pd.qcut(df_sorted['density'], q=n_bins, labels=False, duplicates='drop')
# 결과 시각화
plt.figure(figsize=(10, 6))
plt.scatter(df_sorted['value'], df_sorted['density'], c=df_sorted['bin'], cmap='viridis')
plt.colorbar(label='Bin')
plt.xlabel('Value')
plt.ylabel('Density')
plt.title('Density-Based Binning Example')
plt.show()
Python
복사