→ 머신 러닝 중 비지도 학습에 해당하는 군집화와 차원 축소에 대한 내용
정답이 없을 때, 정답을 찾아가는 과정
데이터 분석에서 피쳐(컬럼) 유사성의 개념을 기반으로 전체 데이터셋을 그룹으로 나누는 그룹핑 기법
현업에서는 kaggle dataset 과는 다르게, 방대한 DB가 구축되어 있음
러프한 프로세스 살펴보기
다양한 이상치 기법에 각 기업에서만 적용하는 특별한 이상치 기준을 추가해줘야 해요!
예: 특정 아이피기 짧은 시간에 수백만 번 접속한 경우 소개한 이상치 기법으로 분류가 안 될 수 있음 → 이상치 기준 추가로 정해 따로 분리해야 함
단순히 기법만 사용하는 게 아니라 AND 조건으로 이상치를 까다롭게 처리해야 함
→ 정상인 유저를 이상한 유저라고 판단하면 절대 안 되기 때문!
★ AND 조건을 이용해 이상치를 까다롭게 분류해주세요 제발~ ★
e.g. z-score가 -3부터 3 범위를 벗어나고 ip 주소가 너무 많은 유저
🡆 이상치는 머신 러닝 학습에 필요 없으니 그냥 drop해 주세요!
→ 원본 데이터가 가지고 있는 분포를 가지고 가야 해서 minmax는 안 씀
※ 표준화는 필수가 아님 ※
하지만 누가 봐도 표준화를 해야겠다는 컬럼(e.g. 혼자 단위가 엄청 큼)이 있을 수 있으니까 알아두세요~
추천 방식
① 표준화를 안 하고 돌려본다
② 표준화를 하고 돌려본다
③ 둘을 비교한다
④ PROFIT!
df[’pay_amt’] = 0,0,0,0,1,2,3,100
과 같은 값이 있다고 가정🡆 표준화보다는 정규화에 가까워요!
🡆 잘 사용하지 않아요!
(데이터 분포를 가져갈 수 없기 때문에 클러스터링에서는 아예 사용 안 함)
Min-Max Scaling은 모든 피처가 정확하게 [0,1] 사이에 위치하도록 데이터를 변경한다. 2차원 데이터셋일 경우에는 모든 데이터가 x축의 0과 1, y축의 0과 1 사이의 사각 영역에 담기게 된다.
Min-Max Scaling은 다음과 같은 공식으로 구할 수 있다:
즉, 데이터에서 최솟값을 빼고 전체 범위로 나누는 것이다.
그래서 정규화=Min-Max Scaling인가? 사실 많은 인터넷 자료에서 두 개를 같은 개념으로 두고 보지만, Normalization ⊃ Min-Max Scaling이라는 표현이 더 맞을 것이다.
위에 유클리디안 거리로 계산하는 방법은 scikit-learn의 Normalizer로 구현 가능하다.
🡆 표준화에 가까워요!
🡆 원래 데이터가 가지고 있는 분포를 그대로 가지고 가기 때문에 많이 사용해요! → 표준 정규 분포 따라가게 되는 거랑 같은 이치
클러스터링에서 표준화는 필수가 아닙니다!
둘 다 해보고 비교해봐야 해요
→ 표준화를 해서 클러스터링 결과가 더 좋을 수도 있고, 표준화를 하지 않았을 때 클러스터링 결과가 더 좋을 수도 있기 때문
표준화와 정규화의 차이를 모르겠어요!
더 알아보기
- 표준화(Standardization)
- 표준화 또는 Z-score 정규화는 표준정규분포의 속성()을 갖도록 피처가 재조정되는 것
- 0 주위에 표준편차 1의 값으로 배치되도록 피처를 표준화하는 것은 다른 단위를 가진 측정값을 비교할 때 중요할 뿐만 아니라 많은 기계 학습 알고리즘의 일반적인 요구 사항임
- 정규화(Normalization)
- 목적
- 데이터셋의 numerical value 범위의 차이를 왜곡하지 않고 공통 척도로 변경하는 것
- 기계학습에서 모든 데이터셋이 정규화 될 필요는 없고, 피처의 범위가 다른 경우에만 필요
- 정규화를 통해 피처 벡터의 유클리디안 길이가 1이 되도록 데이터 포인트를 조정함
- 다른 말로 하면 지름이 1인 원(3차원이라면 구)에 데이터 포인트를 투영함
- 즉, 각 데이터 포인트가 다른 비율로 스케일이 조정된다는 것
- 이러한 정규화는 특성 벡터의 길이는 상관 없고 데이터의 방향만이 중요할 때 많이 사용
- 정규화와 표준화 모두 경사 하강 알고리즘을 더 빠르게 동작할 수 있도록 도와주는 것
- 언제 정규화를 하고 언제 표준화를 할까?
- 명확한 답은 없지만 통상적으로는 표준화를 통해 이상치를 제거하고, 그 다음 데이터를 정규화 해 상대적 크기에 대한 영향력을 줄인 다음 분석을 시작
- 예시
- cluster analysis에서 특정 거리 측도를 기반으로 피처 간의 유사성을 비교하기 위해 표준화가 특히 중요할 수도 있음
- 주성분 분석(Principal Component Analysis)은 보통 Min-Max Scaling보다 표준화를 선호(왜냐하면 분산을 극대화하는 성분에 관심이 있기 때문)
- 이미지 프로세싱에서 정규화가 자주 사용되는데, pixel intensities를 특정 범위(RGB 색상 범위의 경우 0~255) 내에 맞추려면 정규화가 필요하기 때문
🡆 대충 데이터를 표준화해서 나쁠 거 없다는 뜻
→ 데이터 분석가는 결제금액과 경험치를 동시에 보면서 또 다른 변수를 확인하고 싶음 🡆 PCA를 진행: 가장 높은 분산을 가지는 데이터의 축을 찾아 그 축으로 차원을 축소
→ 20개의 차원을 눈으로 볼 수 없음(3차원까지가 한계): 차원을 축소해 PC1, PC2 고름 → PCA plot
→ 점수가 제일 높으니까 2개로 해야지~ 🡆 절대 안 됨!
→ 해당 그래프는 어디까지나 참고용임
(백만 명을 두 그룹으로 나눈다? 말도 안 됨)
→ 어디까지나 참고로만 하는 것
→ elbow-point에서 "시작"임!
(elbow-point가 정답은 아님: 컬럼을 바꾸는 순간 k값도 달라지기 때문)
yellow brick library - elbow method가 가장 최근에 나온 scree plot이에요~
k-means clustering 시행: 데이터를 거리기반 K개의 군집(Cluster)으로 묶는(Clusting) 알고리즘입니다. K-means 알고리즘에서 K는 묶을 군집(클러스터)의 개수를 의미하고 means는 평균을 의미해요. 각 군집의 평균(mean)을 활용하여 K개의 군집으로 묶는다는 의미입니다.
게임 유저 클러스터링인데 결제 금액을 뺐을 때 클러스터링이 잘 된다고 결제 금액 컬럼을 빼는 건 어불성설
# 기본 라이브러리 import
import pandas as pd
import numpy as np
# 시각화 라이브러리 import
import seaborn as sns
import matplotlib.pyplot as plt
# 표준화 라이브러리 import
from sklearn.preprocessing import StandardScaler
# k 값 참고: scree plot을 통한 k 값 확인을 위한 라이브러리 import
from yellowbrick.cluster import KElbowVisualizer
# k 값 참고: distance map 라이브러리 import
from yellowbrick.cluster import intercluster_distance
from sklearn.cluster import MiniBatchKMeans
# k 값 참고: 실루엣 계수 확인을 위한 라이브러리 import
from sklearn.metrics import silhouette_score
# 데이터셋 주성분 분석중 하나인 pca 를 수행하기 위한 라이브러리 import
from sklearn.decomposition import PCA
# k-means 알고리즘 활용을 위한 라이브러리 import
from sklearn.cluster import KMeans
import warnings
warnings.filterwarnings('ignore')
# 데이터셋 로드
base_df = pd.read_csv('merge_df.csv')
# 결측치 확인
base_df.isnull().sum()
# 클러스터링 할 컬럼 지정
feature_names=['customer_zip_code_prefix','price','shipping_charges','payment_sequential','payment_value']
# 지정된 컬럼으로 새로운 dataframe 생성
base_df = pd.DataFrame(base_df, columns=feature_names)
base_df
→ 고유값(e.g. zipcode)은 반드시 빼고 수치형 데이터만 가지고 와서 진행하세요!
→ feature를 가져올 때는 기본적으로 연속형 변수가 핵심
→ 경우에 따라서는 범주형 변수를 인코딩을 통해 수치형 변수로 만들 수도 있음
→ 이진형은 웬만하면 넣지 마세요
# 표준화
# 표준화 방식: standard scaler (평균0, 분산1)
scale_df = StandardScaler().fit_transform(base_df)
scale_df
→ 표준화는 컬럼 하나하나 넣어주는 거 아님!
한 번 넣어주면 알아서 컬럼끼리 수행함
# 주성분 개수를 판단하기 위한 pca 임의 시행
pca = PCA(n_components=3)
pca.fit(scale_df)
# 설정한 주성분의 갸수로 전체 데이터 분산을 얼만큼 설명 가능한지
pca.explained_variance_ratio_.sum()
→ n_components=3
: 3차원으로 보겠다는 이야기임
→ 눈으로 보고 싶으면 2 또는 3 넣으면 됨!
(4 이상은 파이썬도 못 그리고(시각화 못하고) 우리도 못 그려요)
→ base_df의 컬럼 3개를 가져오는 게 아니라 그냥 성분을 3개로 한다는 것!
# pca 시행
pca_df = pca.fit_transform(scale_df)
pca_df = pd.DataFrame(data = pca_df, columns = ['PC1','PC2','PC3'])
# Show the first 5 firms
pca_df.head()
→ 설정한 주성분의 개수로 전체 데이터 분산을 얼만큼 설명 가능한지가 나옴
PC1, PC2, PC3은 base_df의 컬럼이 아님! 주의!!
# 주성분 개수를 판단하기 위한 pca 임의 시행 pca = PCA(n_components=1) pca.fit(scale_df) # 설정한 주성분의 갸수로 전체 데이터 분산을 얼만큼 설명 가능한지 pca.explained_variance_ratio_.sum()
→ 주성분이 1개인 경우에는 전체 데이터의 분산을 41% 설명할 수 있다는 이야기
- 주성분 2개로 하면 62%
※주의사항※
주성분의 개수가 5개라고 하면 이 5개가 각각의 컬럼을 의미하는 건 아님!
이거를 하나로 합쳐놓고 성분을 5개를 뺀 것! 컬럼을 가져온 게 아님!! 뭉쳐놓고 차원 축소를 해 놓고 거기서 성분을 5개 뽑은 것!!!
# 초기 k 값 참고를 위한 scree plot 을 그리고, 군집이 나뉘는 시간까지 고려한 k 값 확인
model = KMeans()
# k 값의 범위를 조정해 줄 수 있습니다.
visualizer = KElbowVisualizer(model, k=(3,12))
# 데이터 적용
visualizer.fit(pca_df)
visualizer.show()
# 초기 k 값 참고를 위한 distance map 시각화
# 그룹의 갯수를 지정해 줄 수 있습니다. 저는 5로 적어두었습니다.
intercluster_distance(MiniBatchKMeans(5, random_state=42), pca_df)
# KMEANS
# 군집개수(n_cluster)는 5,초기 중심 설정방식 랜덤,
kmeans = KMeans(n_clusters=5, random_state=42,init='random')
# pca df 를 이용한 kmeans 알고리즘 적용
kmeans.fit(pca_df)
# 클러스터 번호 가져오기
labels = kmeans.labels_
# 클러스터 번호가 할당된 데이터셋 생성
kmeans_df = pd.concat([pca_df, pd.DataFrame({'Cluster':labels})],axis = 1)
# 클러스터 번호가 할당된 데이터셋 생성
kmeans_df.groupby(['Cluster'])['PC1'].count().reset_index()
base_df
# 3차원으로 시각화
x =kmeans_df["PC1"]
y =kmeans_df["PC2"]
z =kmeans_df["PC3"]
fig = plt.figure(figsize=(12,10))
ax = plt.subplot(111, projection='3d')
ax.scatter(x, y, z, s=40, c=kmeans_df["Cluster"], marker='o', alpha = 0.5, cmap = 'Spectral')
ax.set_title("The Plot Of The Clusters(3D)")
plt.show()
# 2차원으로 시각화
plt.figure(figsize=(8,6))
sns.scatterplot(data = kmeans_df, x = 'PC1', y='PC2', hue='Cluster')
plt.title('The Plot Of The Clusters(2D)')
plt.show()
→ 대부분 2차원으로 그려요~
(더 잘 보임)
POINT
고유값은 다 drop
feature는 연속형 범주만 가져오셔야
범주형 쓸 거면 인코딩해야
파생범주 대환영
클러스터링 완료 후 역추적해야 함
(군집별 EDA 진행)
→ 클러스터가 어떤 특성인지는 클러스터 번호를 맨 마지막 컬럼에 붙이고 역추적