세조목

최종 프로젝트 22일차(24.04.19) 본문

데이터 분석 공부/프로젝트

최종 프로젝트 22일차(24.04.19)

세조목 2024. 4. 19. 23:06

최종 프로젝트 22일차입니다.

금일은 클러스터링 분석 작업을 진행했습니다.

어제 포스팅에서 저희가 정한 기준에 따라서 컬럼을 삭제해가면서

실험해보겠다고 했는데요,

2024.04.18 - [데이터 분석 공부/프로젝트] - 최종 프로젝트 21일차(24.04.18)

 

최종 프로젝트 21일차(24.04.18)

최종 프로젝트 20일차입니다. 전일 클러스터링 분석을 위한 기초 작업을 모두 마쳐놓았습니다. 금일 진행했던 사항은 두 가지입니다. 군집 개수 정하기 컬럼 제거하면서 군집 결과 확인하기 군

eyeoftheworld1209.tistory.com

 

팀원들 모두 진행하는 방식이 조금씩 상이했습니다.

저의 경우 한 개 컬럼을 제거하고,

그 데이터셋을 가지고서 K-means 군집화를 한 후

그 결과값을 가지고서 Radar plot을 그려서 군집화가 제대로 이루어졌는지를 확인했는데

다른 팀원들의 경우 군집화를 한 후, 이를 시각화하기위해서 PCA를 추가적으로 진행했습니다.

그 중에서 한 명은 두 개 컬럼만 남긴 데이터셋으로 바로 PCA를 진행했고,

나머지 한 명은 PCA를 총 두 번(ex. 초기 군집화 時 한 번, 시각화하기위해 한 번) 돌렸습니다.

저희는 PCA를 하기로한게 아닌데 왜 PCA를 했는지가 의아하긴했습니다.

 

두 개 컬럼만 남긴 데이터셋으로 PCA를 진행한 경우는 이해가 되는데

PCA를 두 번 돌린 경우는 이해가 잘 안 됐습니다.

왜냐하면 차원을 한 번 축소해서 결과값을 확인했는데

여기서 한 번 더 PCA를 진행하면 기존 결과값이 어그러진다고 생각했기 때문입니다.

 * 나중에 확인 결과 현업에서는 이런식으로 시각화를 위해 PCA를 한 번 더 진행하는 것이 일반적이라고 들었습니다.

 

관련해서 팀원들과 계속 얘기 나눈 결과 그러면 처음부터 PCA를 하고 군집화를 진행하자는 쪽으로

의견이 모아졌습니다.

 

우선 몇 개의 차원으로 축소해야 할 지 판단해야했으므로

차원별 분산보존율을 확인했습니다.

아래 첫번째 이미지에서 확인할 수 있는 것처럼

차원을 축소했을 때 각 차원이 기존 데이터의 분산을 얼마나 보존하고 있는지를 확인할 수 있는데요,

각 비율을 모두 더했을 때 90% 이상 정도가 나오면 기존 분산을 잘 보존하고 있다고 볼 수 있습니다.

그래서 각 차원별 분산 보존율을 확인해본 결과 5차원 이상 10차원 이하에서 정해야할 것 같았습니다.

결과적으로 저희가 정한 차원은 6개의 차원이었는데 그 이유는

차원이 높아질수록 보존율이 높아지는 것은 맞지만 저희가 가지고 있는 데이터셋의 특성상

리뷰별 특성이 그렇게까지 명확하지 않으므로 차원을 높일 경우 데이터들이 흩어져서

군집화가 제대로 이루어지지 않을 것이라고 판단했기 때문입니다.

# 차원별 분산보존율
column = []
sum = 0

for a in range(2, 21):
   for b in range(a):
	   column.append(f'pc{b}')
   pca = PCA(n_components=a)
   df_anal_pca = pd.DataFrame(data = pca.fit_transform(df_anal), columns = column)
   column = []

   for c in range(len(pca.explained_variance_ratio_)):
      sum+=pca.explained_variance_ratio_[c]
   print(f'{a}차원의 분산 보존율은 {sum}입니다.')
   sum = 0

 

6개의 차원으로 축소시킨 후 k-means 클러스터링을 진행했고,

radar plot을 그리기위해 중심점을 잡아주었습니다.

# 차원 축소
pca = PCA(n_components=6)
df_anal_pca = pd.DataFrame(data = pca.fit_transform(df_anal), columns = ['pc1', 'pc2', 'pc3', 'pc4', 'pc5', 'pc6'])

# k-means 클러스터링
kmeans = KMeans(n_clusters=6, random_state=0).fit(df_anal_pca)

# radar plot을 그리기위한 별도의 데이터프레임 생성
df_centroids = pd.DataFrame(kmeans.cluster_centers_, columns = df_anal_pca.columns)
df_centroids

차원, 군집별 중심점

이를 가지고서 radar plot을 그렸습니다.

from collections import Counter
import plotly.graph_objects as go

# 군집별 데이터 개수 카운팅
c = Counter()
c.update(kmeans.labels_) # kmeans.labels_에 있는 레이블의 등장 횟수를 c에 추가함(딕셔너리 형태)
c

# radar plot 그리기
def plot_radar_from_centroid(df_centroids):
    fig = go.Figure()
    categories = df_centroids.columns
    for row in df_centroids.iterrows():
        fig.add_trace(go.Scatterpolar(
            r=row[1].tolist(),
            theta=categories,
            fill='toself',
            name='cluster {}'.format(row[0])
        ))

    fig.update_layout(
        autosize=False,
        width=1000,
        height=800,
    )
    fig.show()

plot_radar_from_centroid(df_centroids)

 

이렇게 군집이 이루어졌는데요,

위 plot은 차원 6개 군집 6개일 때의 plot입니다.

차원은 앞서 말씀드린것과 같이 5개와 10개 사이에서 고민했으나

데이터 특성상 차원이 너무 많아지면 데이터가 흩어져서 군집화하기가 힘들 것 같았기에 6개 정도로 추렸고,

군집의 경우 실무 경험이 많으신 튜터님의 의견을 적극 반영하여 6개로 정했습니다.

튜터님의 말씀을 들어보니 일반적으로 4개에서 6개 정도로 군집을 많이 설정한다고 하셨습니다.

그래서 군집 4, 차원 6  / 군집 5, 차원 6 / 군집 6, 차원 6 으로 radar plot을 돌려보았을 때

가장 군집이 잘 이루어졌다고 판단되었던 군집 6, 차원 6을 최종 선정했습니다.

 

차원과 군집이 정해졌고, radar plot까지 그려봤으니

이제 각 군집이 어떠한 특성을 가지고 있는지 확인할 필요가 있었습니다.

그러려먼 우선 각 차원이 어떤 특성을 가지고 있는지를 확인해야했습니다.

# 주성분과 feature간의 관계 확인
pca_com = pca.components_
pca_comdf = pd.DataFrame(pca_com, columns = df_anal.columns, index=[f'pca{idx+1}' for idx in range(pca_com.shape[0])])
pca_comdf

# 차원 정체성 확인 작업
feature_pca = pca_comdf.transpose().sort_values('pca6', ascending=False)
feature_pca

이런식으로 각각의 특성들이 특정 차원에 어느정도의 영향을 미치는지를 확인할 수 있는데

차원별로 내림차순해서 가장 영향을 많이 미치는 특성들을 확인했습니다.

이 작업이 마무리가 되면 다시 radar plot을 보고서 각 군집이 어느 차원에 몰려있는지를 확인 후

앞 단계에서 살펴봤던 결과값을 가지고서 군집의 정체성을 설명할 수 있습니다.

이 작업은 내일 이어서 게속 진행할 예정입니다.