군집분석
- 군집분석이란 객체의 유사성을 측정해서 유사성이 높은 집단끼리 분류하는 통계기법
- 머신러닝 분야에서 이상치 탐지를 위해 사용되기도 함
- 대표적인 비지도 학습
- 계층적 군집분석과 비계층적 군집분석으로 나뉨
[군집분석 vs 요인분석]
구분 | 내용 |
군집분석 | - 객체간의 상이성을 규명 - 군집의 특성 파악 |
요인분석 | - 유사한 변수를 묶어 다중공선성을 줄이기 위함 |
[계층적 군집분석]
- n개의 군집으로 시작해 점차 군집의 개수를 줄여나가는 방식
- 군집의 거리를 계산하는 방법에 따라 연결법이 달라짐
- 모든 객체는 거리 행렬을 통해 가까운 거리의 객체들의 관계를 규명, 군집 개수 선택
- 연결법
구분 | 내용 |
최단연결법 | - 거리행렬에서 거리가 가장 가까운 데이터끼리 묶어서 군집 형성 |
최장연결법 | - 데이터와의 거리를 계산할때 최장거리로 계산 |
평균연결법 | - 데이터와의 거리를 계산할때 평균거리로 계산 |
중심연결법 | - 두 군집간의 거리를 두 군집의 중심 간 거리로 계산 |
와드연결법 | - 군집 내 편차들의 제곱합에 근거를 두고 군집화 - 데이터의 크기가 너무 크지 않다면 가장 많이 사용 - 군집 내 편차는 작고 군집간 편차는 크게 군집화 - 계산량이 많은 단점이 있지만 군집 크기를 비슷하게 만듬 - 해석력이 좋음 |
- scipy.cluster.hierarchy.linkage(parameters)
- scipy.cluster.hierarchy.dendrogram(parameters)
scipy.cluster.hierarchy.linkage — SciPy v1.12.0 Manual
For method ‘single’, an optimized algorithm based on minimum spanning tree is implemented. It has time complexity \(O(n^2)\). For methods ‘complete’, ‘average’, ‘weighted’ and ‘ward’, an algorithm called nearest-neighbors chain is imple
docs.scipy.org
- scipy.cluster.hierarchy.fcluster(parameters)
scipy.cluster.hierarchy.fcluster — SciPy v1.12.0 Manual
An array of length n-1. monocrit[i] is the statistics upon which non-singleton i is thresholded. The monocrit vector must be monotonic, i.e., given a node c with index i, for all node indices j corresponding to nodes below c, monocrit[i] >= monocrit[j].
docs.scipy.org
예시) USArrests정보로 최단, 와드연결법 실시
- 데이터로드 및 전처리
#컬럼명 변경
us.rename(columns={"Unnamed: 0": "state"}, inplace=True)
#컬럼명 소문자로
us.columns = us.columns.str.lower()
us.head()
- 최단연결법
- 거리계산은 유클리드거리로 진행
- t값을 기준으로 군집화를 실시했을때 총 6개의 군집이 생기는 것을 확인
- 1개의 state가 1개의 군집으로 모인것도 있음을 확인
#군집분석
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
import matplotlib.pyplot as plt
#연결방법: 최단연결, 거리계산방법: 유클리드
single = linkage(
us.iloc[:, 1:],
metric="euclidean",
method="single"
)
#시각화
plt.figure(figsize=(10, 7))
dendrogram(
single,
orientation="top",
labels= us["state"].tolist(),
color_threshold=25,
distance_sort="discending"
)
plt.axhline(y=25, color="r", linewidth=1)
plt.show();
- 와드연결법
- 최단 연결법은 군집이 가지고 있는 객체 수가 비슷하지 않아 군집 해결에 어려울 수 있음
- 이런 문제점을 보완하기 위해 와드연결법을 사용
- 유클리디안 거리를 이용해 와드연결법 실시
- t=250선에서 수평축을 그려보면 군집이 3개로 나누어짐을 알 수 있음
- 각 군집의 객체 수도 비슷함을 알 수 있음
#와드연결법 실행
ward = linkage(
us.iloc[:, 1:],
metric="euclidean",
method="ward"
)
plt.figure(figsize=(10, 7))
dendrogram(
ward,
labels=us["state"].tolist(),
distance_sort="descending",
orientation="top"
)
plt.show();
- 군집이 확인 되었으니 fcluster함수를 이용해 각 객체들이 가진 군집번호 데이터화
#각 군집 데이터화
cluster_label = fcluster(ward, 250, criterion="distance")
cluster_label
#원 데이터에 파생변수로 할당된 클러스터 삽입
us["cluster"] = cluster_label
us.head()
- 클러스터별 평균 파악
- 1번 클러스터: murder, assault, rape의 평균이 다른 클러스터에 비해 높음
- 2번 클러스터: 전체적으로 중간치의 특성을 보임 urbanpop의 평균이 가장 높음
- 3번 클러스터: 전체적으로 낮은 특성을 보임
[비계층적 군집분석]
- 랜덤하게 군집을 묶어가는 알고리즘
- 거리를 계산하는 방식으로 군집화 실행
- 대표적으로 K-means, DBSCAN, 혼합분포 군집분석이 있음
1. K-means
- 속성의 수가 적은 단순한 데이터에 주로 활용
- 주어진 데이터를 k개로 군집화하며 각 클러스터와 거리차이의 분산을 최소화 하는 방식으로 작동(k개는 연구자 마음)
- 변수가 많을 경우 군집화의 정확도가 떨어짐 > pca(차원축소)를 실시해야 함
- 군집화 알고리즘
- 초깃값 설정: k(군집 수)를 설정할 경우 k개의 데이터를 중심점으로 설정
- 클러스터 설정: 각 데이터로부터 중심점까지를 유클리드 거리로 계산해 해당 가장 가까운 클러스터로 데이터를 재할당
- 각 클러스터의 무게중심을 재설정
- 위의 과정을 반복하다가 중심 변화가 작을때 알고리즘 반복 중지
- 최적의 군집 개수 판단 방법
- 콜린스키 하라바츠 스코어
- 모든 클러스터에 대한 클러스터 간 분산과 클러스터 내 분산의 합의 비율
- 높을 수록 좋음
- 엘보우
- 컬러스터 내 오차제곱합(SSE)을 개수마다 비교하는 방법
- 반복문을 통해 클러스터 개수(k)를 늘려가며 SSE값을 비교
- 기울기가 소실되는 구간을 elbow로 판단하고 그 순간을 최적의 클러스터 개수로 판단
- 콜린스키 하라바츠 스코어
예시) iris데이터를 활용한 군집 분석
- 데이터정의
- 최적의 군집 수 결정
- 하라바츠스코어
- 3개가 최적의 군집수로 보임
- 하라바츠스코어
#군집 수 결정(하라바츠스코어)
from sklearn.metrics import calinski_harabasz_score
import warnings
warnings.filterwarnings("ignore")
for k in range(2, 10):
km = KMeans(n_clusters=k, random_state=1)
km.fit(df)
labels = km.labels_
print(k, calinski_harabasz_score(df, labels))
'''
2 513.9245459802768
3 561.62775662962
4 530.4871420421675
5 495.54148767768777
6 473.5154538824768
7 443.84523107907245
8 440.59767319067873
9 407.0468400265113
'''
-
- 엘보우
- 시각화 결과 2개에서 3개가 기울기가 완만해 지는 지점임
- 엘보우
#엘보우 확인
import matplotlib.pyplot as plt
sses = []
for k in range(1, 11):
km = KMeans(n_clusters=k, random_state=1)
km.fit(df)
sses.append(km.inertia_) #kmeans의 sse 확인 메서드
plt.plot(range(1, 11), sses, marker="o")
plt.xlabel("n_clusters")
plt.ylabel("SSE")
plt.show();
- 군집분석 실시
- k=3으로 군집분석 실시 후 groupby, 시각화
- 변수별로 특성이 분명한 것으로 보임
#최적의 군집분석 수행
km = KMeans(n_clusters=3, random_state=1)
km.fit(df)
labels = km.labels_ #군집 결과 도출
df["cluster"] = labels
df.head()
df.groupby(by="cluster").mean()
import seaborn as sns
sns.pairplot(data=df, hue="cluster")
2. 혼합분포 군집분석
- 데이터가 k개의 모집단으로 부터 나왔다는 가정하에 군집분석 실시
- 데이터는 k개의 군집 중 확률이 높은 쪽의 군집에 속하게 됨
- 실생활 데이터는 대부분 정규분포의 형태를 지녀 혼합분포 군집분석이 잘 맞는 경우가 많음
- kmeans에 비해 엄밀한 결과를 얻을 수 있음
- 군집의 크기가 너무 작으면 추정의 정도가 떨어짐
- 데이터가 커지면 EM알고리즘 적용 시 시간/계산비용 증가
- 이상치에 민감하여 전처리 필요
- 유형들의 분포가 정규분포와 차이가 크면 결과가 좋지 않음
- 사용알고리즘: EM(Expectation-Maximization)
- 초깃값 설정: 필요한 모수에 대해 초깃값 설정
- E: 잠재변수 Z의 기대치 계산(X가 특정 군집에 속할 확률을 계산)
- M: 잠재변수 Z의 기대치를 이용해 파라미터 추정
- 수렴조건(최대 가능도가 최대가 되는 지점)이 만족될때까지 E, M을 반복
- from sklearn.mixture.GaussianMixture(parameters)
sklearn.mixture.GaussianMixture
Examples using sklearn.mixture.GaussianMixture: Comparing different clustering algorithms on toy datasets Demonstration of k-means assumptions Density Estimation for a Gaussian mixture GMM Initiali...
scikit-learn.org
예시) iris 데이터에 혼합분포 군집분석 적용
- 데이터정의
- 스케일링 및 군집분석
from sklearn.preprocessing import StandardScaler
from sklearn.mixture import GaussianMixture
#정규분포로 만들어 주기 위해 스케일링 진행
scaler = StandardScaler()
scaled_df = scaler.fit_transform(df)
#군집분석 실시
gm = GaussianMixture(n_components=3)
gm.fit(scaled_df)
gm_labels = gm.predict(scaled_df)
gm_labels
df["gm_cluster"] = gm_labels
df.groupby(by="gm_cluster").mean()
- 시각화
[KMeans와 혼합분포 군집분석 시각화 결과 비교]
- 현데이터에서는 큰 차이가 없는 것으로 나타난다.
- 이론적으로 kmeans는 원형의 데이터, EM은 타원형 데이터를 더 잘 분리하는 것으로 알려져 있다.
- 명확하게 특성이 갈리는 변수는 petal_length, petal_width로 보인다.
'Data Analysis > Statistics' 카테고리의 다른 글
Python_Statistics_TimeSeries (0) | 2024.03.14 |
---|---|
Python_Statistics_Association (0) | 2024.03.13 |
Python_Statistics_Regression (0) | 2024.03.01 |
Python_Statistics_Chi-square (0) | 2023.12.15 |
Python_Statistics_Anova(분산분석) (0) | 2023.12.11 |