데이터분석 6기/본캠프

2025-04-23 심화프로젝트 3 실험 준비

seyeon1130 2025. 4. 23. 20:37

계층 클러스터링 메모리 사건

우선 어제 계층 클러스터링 하다가 메모라가 다 터져서  튜터님 두 분께 여쭤봤을 때, 두 분 다 다른 대안 머신러닝이 있으면 굳이 쓸 필요 없다고 말씀하셨다.

 

그리고 DBSCAN 또한 KMeans보다 훨씬 덜 쓰이기 때문에, KMeans 위주로 하는 것을 추천하셨다.

 

원핫인코딩 ->라벨인코딩

튜터님께 지금까지 하는 게 잘 돼가고 있는지 확인해달라고 하며 코드들을 다 보여드렸는데, PCA 결과가 이상하다고 하셨다.

 

바로 이거...!

이렇게 각 데이터들이 점 형태로 보이지 않고 다 뭉쳐있으면 문제가 있는 거라고 하셨다.

 

Q. 컬럼수가 너무 많아서 그럴 가능성은 없나요?

A.네. 이러면 안돼요.

 

단호박 그 자체셨다.. 그래서 문제점을 보시다가, 인코딩에 문제가 있는 것 같다고 하셨다.

 

데이터 자체가 도메인이 많은 컬럼들이 아니기 때문에, 순서가 생긴다고 해서 큰 문제가 생기지 않는다고 하셨다.

 

X잘못된 예시

#원핫인코딩
one_hot =['country','category1','category2','payment_type']
df_customer = pd.get_dummies(df_customer, columns=one_hot)


#라벨인코딩
label = ['gender','marketing_info_agree']
encoder = LabelEncoder()

for col in label:
    df_customer[col] = encoder.fit_transform(df_customer[col])

 

O 수정된 버전

label = ['gender','marketing_info_agree','country','category1','category2','payment_type'] #'country','category1','category2','payment_type'추가
encoder = LabelEncoder()

for col in label:
    df_customer[col] = encoder.fit_transform(df_customer[col])

 

모든 범주형 데이터를 라벨 인코딩으로 바꿨다.

 

군집에는 우선 연속형만 넣고,  범주형은 하나씩 넣기

 

범주형 때문에 결과가 확확 달라지기 때문에 하나씩 넣어서 어떤 컬럼이 문제가 있는지를 잘 봐야한다.

 

그래서 아까 집계한 컬럼 중 연속형만 따로 모았다.

df_customer_info = df_customer[['payment_installments','shipping_charges','volume_cm3','weight_kg','price','delivery_delay_days','review_score','approval_delay_minutes','age']]

PCA, KMenas/ DBSCAN 결과

 

pca 결과 / 2차원

pca 결과 / 3차원

 

 

KMeans 결과/ 2차원

 

KMeans결과 /3차원

 

 

DBSCAN 결과 /2차원

DBSCAN 결과 /3차원

 

왜 현업에서는 KMeans를 쓰는지 알 것 같았다.

KMenas는 각각 데이터의 중심을 찾아서 뭉쳐지는 반면, DBSCAN은 얼마나 떨어져있는지를 보고 데이터끼리 뭉치는 거기 때문에 일반적으로는 KMeans가 나을 것 같다.

 

인코딩한 범주형 컬럼들 하나씩 넣어보며 이상 있는지 확인

# 서브플롯 설정
fig, ax = plt.subplots(2, 3, figsize=(18, 10))
ax = ax.flatten()  

for i, col in enumerate(label):
    # 수치형 + 현재 컬럼만 합친 데이터
    df_temp = pd.concat([df_customer_info, df_customer[[col]]], axis=1)

    # PCA
    pca = PCA(n_components=2, svd_solver='full', random_state=42)
    pca_result = pca.fit_transform(df_temp)
    pca_df = pd.DataFrame(pca_result, columns=['PC1', 'PC2'])

    # scatter plot
    ax[i].scatter(
        pca_df['PC1'],
        pca_df['PC2'],
    )
    ax[i].set_title(f'PCA by {col}\nExplained Var: {pca.explained_variance_ratio_.sum():.2f}', fontsize=12)
    ax[i].set_xlabel('PC1')
    ax[i].set_ylabel('PC2')
    ax[i].grid(True)

# 전체 타이틀 & 레이아웃 조정
plt.suptitle('PCA 2D Scatter Plots by Each Label Feature', fontsize=16)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()

 

누가봐도 country랑 카테고리2가 문제 있는 것 처럼 보인다. 딱 각 값에 따라서만 나뉘는 걸로 보인다.

 

군집별 비중

k값이 뭐든, 한 군집의 비중은 50%가 넘으면 안된다. 그래서 비중 구하는 코드를 따로 추가해주기로 한다.

# 클러스터 개수 목록
ks = [8]
# 그래프 크기 설정
plt.figure(figsize=(18, 5))
for i, k in enumerate(ks):
    # KMeans 모델 생성 및 학습
    kmeans = KMeans(n_clusters=k, random_state=42,n_init=10)
    labels = kmeans.fit_predict(pca2_df)
    # 라벨 컬럼 붙이기
    kmeans_df = pd.concat([pca2_df, pd.DataFrame({'Cluster': labels})], axis=1)

    # 3) 비율 계산
    props = kmeans_df['Cluster'].value_counts(normalize=True).sort_index() * 100
    # 콘솔에 출력
    print(f"k = {k}일 때 클러스터 비율 (%)")
    for cluster_id, pct in props.items():
        print(f"  Cluster {cluster_id}: {pct:.2f}%")
    print()


    # subplot 지정
    plt.subplot(1, 3, i+1)
    sns.scatterplot(data=kmeans_df, x='PC1', y='PC2', hue='Cluster', palette='Set3')
    plt.title(f'KMeans Clustering (k = {k})')
    plt.xlabel('PC1')
    plt.ylabel('PC2')
    plt.legend(title='Cluster')
    #kmeans_sil = silhouette_score(pca2_df, labels)
    #print(f"K-Means: 실루엣 점수 = {kmeans_sil:.4f} | 클러스터 개수 = {k}")
plt.tight_layout()
plt.show()

 

그럼 이렇게 예쁘게 잘 나온다!

 

우리팀의 실험 방식

이렇게 구글 스프레드시트에 작업자명, k값, 사용 컬럼, 주성분 개수, plot, 레이더차트, 군집별 비중 등을 넣어서 실험해보기로 했다!