본문 바로가기
데이터 분석/Machine Learning

클러스터링 분석 - (4) 변별력 있는 변수 찾기

by 친절한 휘저씨 2021. 12. 21.

기계학습(machine learning)에서는 분석 목적과 데이터 특성에 맞는 적절한 알고리즘을 선택하고 매개변수를 잘 조정하는 것도 중요하지만, 좋은 입력 데이터를 만들기 위해 적절한 변수를 찾는 것이 더욱 중요합니다. 해결해야 할 문제와 사용할 데이터의 연관성이 낮으면 아무리 좋은 알고리즘을 적용한다고 할 지라도 좋은 결과를 기대할 수 없을 테니까요. 이것은 예측 분석뿐만 아니라 클러스터링 분석에서도 마찬가지입니다. 이번 시간에는 더 나은 군집화 결과를 만들 수 있도록 변별력 높은 변수를 찾아가는 과정에 대하여 알아보도록 하겠습니다.

 

 

너무 많은 변수를 사용할 위험

클러스터링 분석은 데이터 전처리를 위해 사용하기도 하지만 군집화 결과 자체를 현업에 활용하기 위한 목적으로도 많이 사용됩니다. 대표적인 사례가 몇 차례 말씀드렸던 고객 세분화(customer segmentation)인데요, 보통 이런 작업을 진행할 때는 데이터 분석가와 현업 담당자들이 모여 고객을 유형화하는데 필요할 것으로 생각되는 특징이나 변수에 대한 아이디어 수집, 토론 과정을 거치게 됩니다. 이 과정에서 다양한 의견이 나오기 마련이고, 여기서 논의된 특징 혹은 변수들은 대부분 입력 데이터에 모두 포함하여 분석을 진행해보게 됩니다. 논의된 변수 대부분을 데이터셋에 집어넣게 되는 이유는 다음과 같은 것들을 들 수 있습니다.

  1. 정답이 없는 비지도학습(unsupervised learning)의 특성 때문에 어떤 변수가 좋은 변수인지 미리 판단하기 어려움
  2. 변수를 이것저것 다 넣으면 ‘기계가 알아서 잘(?) 판별해주겠지’ 하는 기대심리
  3. 의견을 제시한 사람에 대한 존중(?)

이런 이유들 때문에 고객 세분화를 위한 클러스터링 분석에서는 일반적으로 굉장히 많은 변수가 담긴 데이터셋을 사용하게 됩니다. 하지만, 너무 많은 변수를 사용하게 되면 아래와 같은 몇 가지 문제가 발생하게 됩니다.

  1. 알고리즘 학습(model fitting) 시간 증가
  2. 모델이 복잡해지면서 과적합(overfitting) 위험 증가
  3. 집화 결과 검토의 난이도 증가 (군집별로 어떤 차이가 있는지 살펴봐야 할 변수가 늘어나기 때문)

이런 문제를 최소화하려면 군집화 알고리즘을 적용하기에 앞서 변수를 전반적으로 한 번 정리하는 과정을 거칠 필요가 있습니다. 2가지 이야기를 해볼 건데요, 좀 더 쉬운 이야기부터 해보도록 하겠습니다.

 

 

변수 간의 관계 미리 보기

변수 논의 과정에서는 많은 변수들이 등장하다 보니 서로 유사성이 높은 것들도 존재하고, 한 변수가 다른 변수에 많은 영향을 주는 변수들도 있기 마련입니다. 분석용 데이터셋이 완성되면 상관계수 히트맵을 그려봄으로써 변수 간의 이러한 관계에 대해 좀 더 쉽게 들여다볼 수 있습니다.

 

### 필요한 모듈 불러오기
%matplotlib inline	# 시각화 결과를 Jupyter Notebook에서 바로 보기
import matplotlib.pyplot as plt    # 모듈 불러오기

### 상관계수 테이블
corr = df.corr()    # 'df'라는 데이터셋을 'corr'라는 이름의 상관계수 테이블로 저장 

### 상관계수 히트맵 그리기

# 히트맵 사이즈 설정
plt.figure(figsize = (20, 15))	

# 히트맵 형태 정의. 여기서는 삼각형 형태(위 쪽 삼각형에 True, 아래 삼각형에 False)
mask = np.zeros_like(corr, dtype=np.bool) 
mask[np.triu_indices_from(mask)] = True

# 히트맵 그리기
sns.heatmap(data = corr,    # 'corr' = 상관계수 테이블
            annot = True,  # 히트맵에 값 표시
            mask=mask,   # 히트맵 형태. 여기서는 위에서 정의한 삼각형 형태
            fmt = '.2f',   # 값 표시 방식. 소숫점 2번째자리까지 
            linewidths = 1.,  # 경계면 실선 구분 여부
            cmap = 'RdYlBu_r')  # 사용할 색 지정 ('python colormap 검색')
plt.title('상관계수 히트맵')
plt.show()

히트맵을 그린 후 아래와 같은 과정을 통해 분석에 활용할 변수의 수를 줄일 수 있습니다.

  1. 특히 높은 상관을 보이는 변수 묶음(들)이 있는지 확인
  2. 묶음 별로 상대적으로 중요도가 낮다고 판단되는 변수는 분석에서 제외 검토하기

위의 예시에서도 특정 변수 하나가 다른 여러 개의 변수와 높은 상관을 보이는 케이스를 발견할 수 있네요. 이런 경우에 변수 간의 중요도를 고려하여 일부 변수를 제외하는 것을 고려해 볼 수 있습니다. 물론 모든 변수가 그 나름대로의 의미를 갖고 있다고 판단되면 모두 활용할 수도 있습니다. 이런 과정들을 통해 사전에 분석에 소요되는 시간을 줄이고, 클러스터링 모델의 복잡성을 낮출 수 있습니다.

 

 

주성분 분석(Principle Components Analysis) 활용하기

주성분 분석(PCA)은 데이터의 특징을 최대한 손실 없이 살리면서 데이터의 차원을 축소하는 기법을 의미합니다. 여기서 ‘차원’이라는 것은 데이터셋의 ‘변수’라고 이해해도 무방합니다. 많은 변수를 사용하는 분석의 전처리 과정에서 종종 활용하는 방식이고, 클러스터링 분석에서도 취급하는 변수의 수를 줄일 때 유용하게 사용할 수 있습니다. PCA의 동작 원리를 이해하는 것과, PCA를 통해 새롭게 만들어진 변수(≒주성분)를 해석하는 것이 쉽지 않기 때문에 아래 몇 가지 참고자료들을 먼저 찬찬히 보시는 것을 추천드릴게요.

 

[PCA 이해를 위한 참고자료]
‘지톨이’님의 글 : PCA in Machine Learning
‘Tamarae’님의 글 : 주성분 분석(PCA)으로 차원 축소하기
‘Excelsior-JH’님의 글 : 차원 축소 - PCA, 주성분분석 (1)

 

PCA를 이해하는 것은 어렵지만, 사용하는 것은 그리 어렵지 않습니다.
PCA 적용 결과를 함께 보시면 좀 더 직관적인 이해가 쉬워질 것으로 생각됩니다.

 

# 모듈 불러오기
from sklearn.decomposition import PCA

# 주성분 분석
pca = PCA(n_components = 10)   # 데이터의 처음 10개의 주성분만 유지하도록 설정
pca.fit(df)    # 'df'라는 원본 데이터셋으로 PCA 모델 만들기
df_pca = pca.transform(df)   # 처음 10개의 주성분을 사용해 데이터 변환
# 새로운 데이터 형태 확인
print('원본 데이터 형태:', str(df.shape))    # 원본 데이터셋의 개체(행)수와 변수의 갯수 출력 
print('축소된 데이터 형태:', str(df_pca.shape))    # 주성분 데이터셋의 개체(행)수와 주성분의 갯수(=10) 출력

'''
원본 데이터 형태: (496639, 57)
축소된 데이터 형태: (496639, 10)
'''
print('PCA 주성분 형태:', pca.components_.shape)    
print('PCA 주성분:', pca.components_)  # 행: 주성분, 중요도에 따라 정렬 / 열: 원본 데이터의 '변수'에 대응하는 값

'''
PCA 주성분 형태: (10, 57)
PCA 주성분: [[ 6.18609258e-02 5.57421081e-02 1.33774819e-01 4.72781000e-02
-1.29827684e-02 -8.48676552e-02 -2.70926756e-02 -4.45507424e-02
-2.85566499e-02 -4.99305113e-02 -1.36604999e-02 -8.66943601e-03
-2.18610398e-02 -2.80602958e-03 -4.56489824e-02 -1.86827049e-02
…
3.30210170e-02 2.31132348e-02 2.03529529e-03 9.02030881e-04
2.49012794e-03 1.29844714e-02 1.44442098e-02 1.16955669e-02
6.53853607e-02]
…]
'''
print('각 주성분의 분산 비율:', pca.explained_variance_ratio_)  # 각 주성분이 원본 데이터를 얼마나 설명하는가? 

'''
각 주성분의 분산 비율 : [0.44248607 0.24631839 0.11119554 … ]
'''
# 히트맵으로 주성분과 변수와의 상관관계를 시각화하기
# 어떤 특성(변수) 정보가 각각의 주성분과의 연관성이 높은지 확인
plt.figure(figsize=(30,5))    # 히트맵 사이즈 설정
plt.matshow(pca.components_, cmap = 'RdYlBu_r', fignum=1)    # 행렬 데이터 시각화하기
plt.yticks([0, 9])    # 세로축 축 값 표기
plt.colorbar()  # orientation = 'horizontal', 상관계수 bar 그리기
plt.xticks(range(len(df.columns)), df.columns, rotation = 80, ha = 'left')  # 가로축 축 값 표기
plt.xlabel('특성')
plt.ylabel('주성분')

  • 위의 예시에서는 약 50만 개 개체의 57개 특성 정보가 담긴 데이터셋으로 주성분을 10개만 남기는 작업을 진행했습니다.
  • 각 주성분의 분산 비율을 보시면 첫 번째 주성분부터 10번째 주성분까지 전체 데이터를 얼마나 설명하는지 확인할 수 있습니다.
  • 예시에서는 앞선 3개의 주성분이 전체 데이터의 약 80%(0.44 + 0.24 + 0.11) 정도를 설명하는 것으로 나타나네요.
  • 그다음은 각각의 주성분과 개별 특성(변수)과의 관계를 살펴볼 차례입니다.
  • 가로축이 특성이고, 세로축이 첫 번째 주성분부터 10번째 주성분을 의미합니다.
  • 각각의 주성분마다 상관관계가 높게 나타나는 변수들 확인이 가능하며,
  • 앞선 주성분일수록, 그리고 그 주성분과 상관관계가 높은 변수일수록 다른 변수보다 변별력이 높다고 해석할 수 있습니다.
  • 반대로 어느 주성분에서도 상관관계가 미미한 변수가 있다면 변별력이 상대적으로 낮은 변수라고 해석할 수 있습니다.

PCA는 위의 예시처럼 모든 변수를 사용하여 변수의 상대적인 변별력을 가늠해보는 데 사용할 수도 있지만, 변수의 수 자체를 줄이는데도 직접적으로 활용할 수 있습니다. 자주 활용되는 부분이 범주형 변수의 더미 변수들만 모아서 새로운 (주성분) 변수를 만드는 작업입니다. 클러스터링 분석에 범주형 변수가 많이 사용될 수밖에 없는 상황이라면 변수의 수는 급격하게 늘어날 수밖에 없고, 모델의 학습 성능 저하(차원의 저주, Curse of dimensionality)를 유발할 가능성 또한 높아집니다. 다양하게 주성분 수를 설정하여 데이터를 축소시키고, 설명력(분산 비율)이 너무 떨어지지 않을 만큼의 주성분(들)만 더미 변수들 대신 사용하는 방식으로 변수의 수를 줄일 수 있습니다.

 

 

클러스터링 결과에 대한 이야기는..

수학과 친하지 않은 분들은 PCA 이해가 다소 어려웠을 것으로 생각되네요. 꼭 어려운 공식까지는 아니더라도 어느 정도 개념만 익혀도 활용하시는데 큰 어려움은 없을 것으로 생각되기 때문에 일단 최대한 많은 분석에 활용을 해보시는 걸 추천드립니다. 그러면 “아 이럴 때 PCA 써볼 만하겠구나” 하고 좀 더 감이 오실 거에요.

조만간 클러스터링 분석 결과를 어떻게 하면 좀더 쉽게, 효율적으로 확인할 수 있을지 시각화에 대한 이야기도 한 번 해보려고 합니다. 오늘 이야기는 특히 더 내용이 길었는데 읽어주셔서 감사합니다. 😄

 

 

 

반응형

댓글