2025.12.16 TIL (본캠프, 42일차)
오늘은 어제 배운 클러스터링을 실습하였다.
어제 배운 개념들이 실제로 어떻게 작동하는지 눈으로 확인할 수 있었다.
코드 한 줄 한 줄의 의미가 중요하지만, 처음이기에 외우는것보다 나는 각 단계가 어떤 의미인지 이해하려고 했다.
데이터 준비
먼저 필요한 라이브러리들을 import했다.
표준화, PCA, K-Means, 시각화 등 어제 배운 모든 기법들이 라이브러리로 준비되어 있었다.(복붙이 아니라 직접 입력하는게 핵심)
신기했던 건 yellowbrick이라는 라이브러리인데, 이건 K값을 자동으로 추천해주는 Elbow Method를 구현하는 것이였다.
데이터를 로드한 후, 먼저 결측치를 확인했다. 이제 이건 기본이다.
비지도학습에서는 피처 선택이 중요하다
클러스터링에 사용할 컬럼을 지정하는 부분이 있었다:
feature_names=['customer_zip_code_prefix','price','shipping_charges','payment_sequential','payment_value']
어제 강의에서 "컬럼이 가지는 개념적 의미는 무엇인지?"를 물었던 이유가 여기였다.
무작정 모든 컬럼을 쓰는 게 아니라, 분석 목적에 맞는 컬럼을 선택해야 한다는 뜻이다.
비지도 학습 전처리 과정
표준화
StandardScaler를 사용했다. 어제 배운 내용 그대로다:
scale_df = StandardScaler().fit_transform(base_df1)
fit_transform을 한 번에 한다. fit은 평균과 표준편차를 계산하고, transform은 그것을 적용한다.
PCA로 차원 축소
pca = PCA(n_components=3)
pca.fit(scale_df)
pca.explained_variance_ratio_.sum()
3개의 주성분을 설정했을 때, 전체 분산의 몇 %를 설명하는지 확인한다.
튜터는 이 값이 높을수록 좋다고 했다. 예를 들어 0.85가 나오면 "5개 컬럼의 85%를 3개로 설명한다"는 뜻이다.
그리고 실제로 PCA를 적용해서 변환된 데이터를 얻는다:
pca_df = pca.fit_transform(scale_df)
이제 원본 5개 컬럼이 3개 주성분(PC1, PC2, PC3)으로 축소되었다.
다음 단계는 최적의 K값 찾기
Elbow Method
visualizer = KElbowVisualizer(model, k=(3,12))
visualizer.fit(pca_df)
visualizer.show()
K 범위를 3부터 12까지 설정하고, 각 K에서의 성능을 시각화한다.
산점도가 팍 꺾이는 지점이 Elbow Point다. 거기가 추천 K값이다.
Distance Map
intercluster_distance(MiniBatchKMeans(5, random_state=42), pca_df)
K=5일 때 각 클러스터 간 거리를 히트맵으로 본다.
색이 밝을수록 거리가 멀다.
대칭 구조로 나타나고, 대각선은 자기 자신과의 거리(0)이므로 검은색이다.
어제 강의에서 "이는 참고치일 뿐이다"라고 했던 이유가 이제 이해된다. 히트맵이 실행할 때마다 약간 달라질 수 있기 때문이다.
(핵심) 클러스터링 실행
K-Means 적용
kmeans = KMeans(n_clusters=5, random_state=42, init='random')
kmeans.fit(pca_df)
labels = kmeans.labels_
K=5로 정하고 K-Means를 실행한다.
random_state=42는 재현성을 위해 랜덤 시드를 고정하는 것이다. 그래야 같은 결과가 나온다.
실행되면 각 데이터 포인트에 0부터 4까지의 클러스터 번호가 할당된다.
결과 확인
base_df.groupby(['Cluster'])['customer_id'].count().reset_index()
각 클러스터에 몇 개의 고객이 속하는지 확인한다.
혹시 한 클러스터에 대부분의 고객이 몰려있다면 문제가 있다는 신호다.
시각화 통해 확인
2D 산점도
sns.scatterplot(data = kmeans_df, x = 'PC1', y='PC2', hue='Cluster',palette = 'Set3')
PCA의 첫 두 주성분으로 2차원에 시각화한다.
색으로 구분된 5개 클러스터가 명확히 분리되어 보인다. 만약 섞여있다면 K값이나 피처를 다시 조정해야 한다.
3D 산점도
fig = plt.figure(figsize=(12,10))
ax = plt.subplot(111, projection='3d')
ax.scatter(x, y, z, s=60, c=kmeans_df["Cluster"], marker='*', alpha = 0.7, cmap = 'Pastel1')
모든 3개 주성분을 3차원으로 본다. 2D보다 더 많은 정보를 담을 수 있다. 별 모양 마커를 사용해서 보기 좋게 표현했다.
레이더 차트 (가장 인상적)
레이더 차트는 각 클러스터의 특성을 한눈에 비교할 수 있다.
각 축이 하나의 컬럼을 나타내고, 클러스터별로 다르게 칠해진 영역이 나타난다.
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
angles += angles[:1]
360도를 균등하게 나눈다. num_vars가 5이면 72도씩 간격을 둔다.
실제로 레이더 차트를 보니 각 클러스터의 특징이 명확했다:
- Cluster 0: 이 영역이 크다
- Cluster 1: 저 영역이 크다
- ...
이것이 바로 "인사이트"다. 각 클러스터가 어떤 특징을 가지고 있는지 한눈에 알 수 있다.
하루를 마무리하며....
"아, 이게 데이터분석이구나"
어제까지는 개념만 배웠는데, 오늘 직접 코드를 짜면서 느꼈다. 클러스터링은:
- 데이터를 준비하고
- 여러 기법으로 최적값을 찾아서
- 알고리즘을 실행하고
- 결과를 시각화해서
- 비즈니스 인사이트를 도출하는
전체 과정이다.
기술은 도구일 뿐이고, 진짜 중요한 건 "이 결과가 의미 있는가?"를 판단하는 것이다.
놀랐던 건 코드가 생각보다 간단하다는 것이다.
특히 PCA, K-Means, 시각화까지 한 파일에서 모두 처리할 수 있다는 게 신기했다.
레이더 차트를 봤을 때 깨달았다. 숫자만 봐서는 알 수 없는 패턴이 한눈에 보인다.
- 2D 산점도: 클러스터가 잘 분리되었는지 확인
- 3D 산점도: 더 많은 정보를 담음
- 레이더 차트: 각 클러스터의 특성 비교
코드를 보면서 각 파라미터의 의미를 생각해봤다:
- n_components=3: 몇 개의 주성분을 만들 것인가? (차원 축소 정도)
- n_clusters=5: 몇 개의 클러스터로 나눌 것인가?
- random_state=42: 재현성을 위한 랜덤 시드
- init='random': 초기 중심점을 어떻게 설정할 것인가?
모든 게 선택이고, 이 선택들이 결과에 영향을 미친다.
오늘 새롭게 알게된 사실은 "정답이 없는 데이터에서 정답을 찾아내는" 그것이 데이터분석가의 일이다.