[데이터 전처리] 군집화 - 계층적 군집화 with sklearn

Bpius·2023년 10월 13일
0

데이터 EDA & 전처리

목록 보기
19/46
post-thumbnail

군집화

하나 이상의 특징을 바탕으로 유사한 샘플을 하나의 그룹으로 묶는 작업을 말한다.

  • 샘플들을 소수의 군집으로 묶어 각 군집의 특성을 파악하여 데이터의 특성을 이해하기 위함.
  • 군집 특성을 바탕으로 각 군집에 속하는 샘플들에 대한 세부화된 의사결정 수행.

거리와 유사도

샘플들을 하나의 군집으로 묶기 위해서 '거리' 혹은 '유사도'가 필요.
거리/유사도 척도는 수치형 변수에 대해서 정의되어 있으므로 '숫자'로 바꿔주는 작업이 있어야 한다.

  • 범주형 변수의 숫자화(더미) : 범주형 변수가 특정 값을 취하는지 여부를 나타내는 더미 변수 생성 방법.
    pandas.get_dummies를 사용하여 생성할 수 있으며, '문자' 타입만 사용가능하기에 숫자로 표현되어 있는 범주 변수(날짜, 코드 등)라면 데이터 타입을 'str'로 변경하여 사용.
    인자 :
    data - 더미화를 수행할 DataFrame 혹은 Series.
    drop_first - 첫 번째 더미 변수 제거 할지 여부(3개의 변수가 있다면 2개만 알아도 나머지 1개의 변수는 알 수 있기에)

  • 유클리디안 거리 : 두 변수 사이의 거리(백터 간 거리)

  • 맨하탄 거리 : 정수형 데이터(ex. 리커트 척도, 설문 조사의 단계)에 적합한 거리 척도로 수직/수평으로만 이동한 거리의 합으로 정의.

  • 코사인 유사도 : 변수값의 스케일을 고려하지 않고 방향 유사도를 측정하는 상황(ex. 추천 시스템)에 주로 사용.

  • 매칭 유사도 : '이진형 데이터'에 적합한 유사도 척도로 전체 특징 중 '일치하는 비율'을 고려하여 사용.

  • 자카드 유사도 : '이진형 데이터'에 적합한 유사도 척도로 둘 중 '하나'라도 '1을 가지는 특징' 중 '일치하는 비율'을 고려하여 사용하며 희소한 이진형 데이터에 적합한 유사도 척도.(ex. 상품 구매 데이터)

계층적 군집화

  • 개별 샘플을 군집으로 간주하여, 거리가 가장 가까운 두 군집을 순차적으로 묶는 방식으로 군집을 생성.
  • 개별 샘플부터 계산하기에 계산량은 많지만 데이터가 같다면 누가 하더라도 같은 결과를 도출할 수 있다.

군집간 거리

  • 최단 연결법: 군집들에서 군집 사이의 가장 가까운 샘플끼리의 거리를 측정하는 것으로 군집 안의 개개 샘플들을 다 계산하기에 계산량이 많고, 개개 샘플들의 거리를 모두 보기에 이상치에 민감하다.(반대 개념: 최장 연결법)
  • 평균 연결법: 군집들에서 군집 사이의 가장 가까운 샘플끼리의 거리를 측정하고 그 측정한 모든 조합의 평균으로 거리를 구한다. 모든 군집의 개개 샘플들의 거리를 모두 계산하기에 계산량이 많고, 평균값을 구하기에 이상치에 둔감하다.
  • 중심 연결법: 군집의 중심들 간의 거리를 측정한다. 중심들 간의 계산이기에 계산량이 적고, 중심 간의 거리이기에 이상치에 둔감하다.
  • 와드 연결법: 모든 샘플들 내의 분산을 가장 작게 증가시키는 두 군집을 합친다. 군집들의 중심값 r1...을 구하고 두 군집이 하나로 묶였을 때의 중심 r2를 구한 후, r2와 군집들의 각 개개 샘플들간의 거리를 계산한다. 중심을 구하고 개개 샘플들 계산하기에 계산량이 많고, 중심값을 구해서 계산하기에 이상치에 둔감하지만, 군집들의 크기를 비슷하게 만드는 효과를 기대할 수 있다.
  • 덴드로그램: 계층 군집화 과정을 트리 형태로 보여주는 그래프. 단점은 샘플수가 많을 경우 해석이 불가능할 정도로 복잡해져 문제가 발생.

sklearn.cluster.AgglomerativeClustering 사용

sklearn.cluster.AgglomerativeClustering

주요 인자:

  • n_clusters: 군집 개수 지정
  • affinity: 거리 척도('Euclidean', 'manhattan', 'cosine', 'precomputed')
  • linkage: 군집 간 거리('ward', 'complete', 'average', 'single')

주요 메서드:

  • fit(): 데이터 x에 대한 군집화 모델 '학습'
  • fit_predict(x): 데이터 x에 대한 학습과 결과까지 반환.
  • labels_: fit(학습)한 데이터에 있는 샘플들이 속한 군집 정보를 ndarray 형태로 반환

customer ID별 특성을 정리해놓은 데이터를 가지고 사이킷런 라이브러리를 활용하여 군집화를 진행해보자.

customer ID는 특성이 아니기에 index로 바꾼 후, 수치형이아닌 데이터를 '더미화'한다.
pandas 모듈 get_dummies 사용하여 데이터를 더미화하면, 숫자인 데이터는 그대로 두고 'str'형 데이터들을 '더미화'되어 columns으로 생성된다.

pandas.get_dummies(data, drop_first=True)


군집화를 진행해보자.

from sklearn.cluster import AgglomerativeClustering

clusters = AgglomerativeClustering(n_clusters = 3, # 군집수는 3으로
                                   affinity = 'euclidean', # 거리 측도는 유클리디안 기법으로
                                   linkage = 'ward').fit(df) # 군집 간 거리는 와드 연결법으로 / 그리고  군집 모델을 학습시킨다.
                                   
clusters.labels_  #군집화를 3개로 나누었기에 입력된 data를 학습하여 인덱스별로 (0, 1, 2) 중 하나를 ndarray 형태로 반환한다. 그리고 숫자는 군집을 구분하기 위한 id일 뿐 의미가 있는 수치가 아니다.
array([2, 1, 2, ..., 2, 2, 0], dtype=int64)

군집화된 라벨을 데이터에 추가하여 군집별로 데이터를 묶어서 살펴보자.

아래와 같이 월/총 요금을 3군집으로 나누어 평균을 내면 아래와 같이 확인할 수 있다.
돈을 상대적으로 많이 쓴 '0'군집은 TV 스트리밍 서비스를 많이 사용한다고 해석할 수도 있고, TV 스트리밍 서비스를 통해서 돈을 상대적으로 많이 사용하게 되었다고 해석할 수도 있다.
그리고 노인층의 비율이 21/18/12% 순차적으로 있는 것으로 보아서 퇴직한 노인층이 TV 시청을 위해 요금을 더 많이 하게 됨으로써 사용한 요금이 높게 나온 군집에 포함되어 있다라고 해석할 수도 있다.

베스트셀러 도서 구매 데이터로 다시 군집화를 해보자.
군집화를 진행하면 같은 책들을 구매한 고객별로 군집화가 된다면, 같은 군집에 있는 고객들에게 책 추천시스템을 사용할 수 있을 것이다.

그리고 판다스 crosstab을 사용하여 책을 구매하였다면 매칭이 되어 '1'로 구매하지 않은 책은 '0'으로 데이터를 반환한다.

crosstab 데이터를 가지고 군집화를 실행해보자.

from sklearn.cluster import AgglomerativeClustering as AC

clustering_model = AC(n_clusters = 10, # 군집 개수 10개
                      affinity = "jaccard", # 자카드 유사도 : 이진화(0, 1-1이상이면 모두 1로 취급)
                      linkage = "average") # 평균 연결법 : jaccard는 'ward'를 쓸 수 없다.

clustering_model.fit(matrix_df) # 인스턴스화 된 모델 학습

학습한 데이터를 활용하여 ID별로 어느 군집에 속해있는지 데이터 프레임으로 확인해보자.
index별로 군집화된 label이 생생되었기에 아래와 같이 데이터 프레임으로 생성한다.

그리고 10개로 나눠진 군집들의 수를 확인해보면 대부분 '0'번 군집에 몰려있음을 알 수 있다.
군집화를 나눌 특별한 기준이 있기보다는 대부분 비슷한 경향을 띄고 있으며 '자카드'를 써서 군집의 크기 불균형이 있다는 것을 확인할 수 있다고 볼 수 있다.

기존의 데이터에 군집화된 라벨을 merge하여 군집화별로 groupby를 진행한다.

idxmax : 'axis=0 인덱스, axis=1 컬럼'으로 가장 높은 값을 가지는 인덱스(행) 이름 혹은 컬럼(열) 이름을 반환한다.(max vs argmax)
이것을 이용하여 axis를 1로 하여 군집별로 가장 많이 구매한 책이 무엇인지 확인해보자.

profile
데이터 굽는 타자기

0개의 댓글