240611 Today I Learn
๋น์ง๋ ํ์ต
๐ก ๋น์ง๋ํ์ต
๋ต์ ์๋ ค์ฃผ์ง ์๊ณ ๊ณต๋ถ์ํค๋ ๋ฐฉ๋ฒ
- ์ฐ๊ด๊ท์น
- ๊ตฐ์งํ
K-Means Clustering
๐ก K-Means Clustering
์ฃผ์ด์ง ๋ฐ์ดํฐ๋ฅผ k๊ฐ์ ํด๋ฌ์คํฐ๋ก ๋ฌถ๋ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ๊ฐ ํด๋ฌ์คํฐ์ ๊ฑฐ๋ฆฌ ์ฐจ์ด์ ๋ถ์ฐ์ ์ต์ํํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
- ์ฅ์ : ์ผ๋ฐ์ ์ด๊ณ ์ ์ฉํ๊ธฐ ์ฌ์
- ๋จ์
- ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๊น์์ ์ธก์ ํ๊ธฐ ๋๋ฌธ์ ์ฐจ์์ด ๋ง์ ์๋ก ์ ํ๋๊ฐ ๋จ์ด์ง
- ๋ฐ๋ณต ํ์๊ฐ ๋ง์ ์๋ก ์๊ฐ์ด ๋๋ ค์ง
- ๋ช ๊ฐ์ ๊ตฐ์ง(K)์ ์ ์ ํ ์ง ์ฃผ๊ด์ ์
- ํ๊ท ์ ์ด์ฉํ๊ธฐ ๋๋ฌธ์(์ค์ฌ์ ) ์ด์์น์ ์ทจ์ฝํจ
์ข์ ๊ตฐ์งํ๋?
- ์ค๋ฃจ์ฃ ๊ฐ์ด ๋์์๋ก(1์ ๊ฐ๊น์)
- ๊ฐ๋ณ ๊ตฐ์ง์ ํ๊ท ๊ฐ์ ํธ์ฐจ๊ฐ ํฌ์ง ์์ ์๋ก ์ข์ ๊ตฐ์งํ์ด๋ค.
๊ตฐ์งํ ์ค์ต - iris
- ๋ฐ์ดํฐ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ๋ฌ์ค๊ธฐ
# ๊ธฐ๋ณธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# seaborn iris ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ
iris = sns.load_dataset('iris')
# label(์ด ๊ฒฝ์ฐ species)์ด ์๋ ๋ฐ์ดํฐ ํ๋ ์ ๋ง๋ค๊ธฐ -> ๊ตฐ์งํ์ฉ
iris2 = iris.copy()
iris2 = iris2.drop('species',axis=1)
- K-Means Clustering
sklearn.cluster.KMeans
- ํจ์ ์ ๋ ฅ ๊ฐ
- n_cluster: ๊ตฐ์งํ ๊ฐฏ์ → ์ง์ ํด ์ค์ผํจ. (๊ณ์ ๋ฐ๊ฟ๊ฐ๋ฉด์ ์คํ)
- max_iter: ์ต๋ ๋ฐ๋ณต ํ์ → ์ผ๋ง๋ ๊ตฐ์งํ๋ฅผ ๋ฐ๋ณตํด๋ณผ ๊ฒ์ธ์ง
- ๋ฉ์๋
- labels_: ๊ฐ ๋ฐ์ดํฐ ํฌ์ธํธ๊ฐ ์ํ ๊ตฐ์ง ์ค์ฌ์ ๋ ์ด๋ธ
- cluster_centers: ๊ฐ ๊ตฐ์ง ์ค์ฌ์ ์ ์ขํ
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ถ๋ฌ์ค๊ธฐ
from sklearn.cluster import KMeans
# KMeans(n_clusters = ๊ตฐ์ง์, init = array shape)
kmeans = KMeans(n_clusters = 3, init = 'k-means++', max_iter = 300, random_state= 42)
# fitting
kmeans.fit(iris2)
- Original vs. K-Means
plt.figure(figsize = (12,6))
plt.subplot(1,2,1)
sns.scatterplot(data=iris, x='sepal_length', y='sepal_width', hue='species', palette = 'husl')
plt.title('Original')
plt.subplot(1,2,2)
sns.scatterplot(data = iris2, x = 'sepal_length', y = 'sepal_width', hue = 'cluster', palette= 'pastel')
plt.title('Clustering')
plt.show()
→ original๊ณผ ๊ฑฐ์ ๋น์ทํ๊ฒ clustering๋๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ตฐ์งํ ํ๊ฐ ์งํ
๐ก ์ค๋ฃจ์ฃ ๊ณ์
๊ฐ ๋ฐ์ดํฐ ํฌ์ธํธ์ ์ฃผ์ ๋ฐ์ดํฐ ํฌ์ธํธ๋ค๊ณผ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ(์ ํด๋ฆฌ๋)์ ํตํด ๊ฐ์ ๊ตฌํ๋ฉฐ, ๊ตฐ์ง ์์ ์๋ ๋ฐ์ดํฐ๋ค์ ์ ๋ชจ์ฌ์๋์ง, ๊ตฐ์ง๋ผ๋ฆฌ๋ ์๋ก ์ ๊ตฌ๋ถ๋๋์ง ํด๋ฌ์คํฐ๋ง์ ํ๊ฐํ๋ ์ฒ๋๋ก ํ์ฉ๋๋ค.
- ์ค๋ฃจ์ฃ ๊ณ์๊ฐ 1์ ๊ฐ๊น์ธ์๋ก ๊ทผ์ฒ์ ๊ตฐ์ง๊ณผ ๋ ๋ฉ๋ฆฌ ๋จ์ด์ง๊ณ ,
- 0์ ๊ฐ๊น์ธ ์๋ก ๊ทผ์ฒ ๊ตฐ์ง๊ณผ ๊ฐ๊น์ ์ง๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
์ค์ต - RFM ๊ณ ๊ฐ ์ธ๊ทธ๋ฉํ ์ด์
๐พ ํ์ฉ ๋ฐ์ดํฐ์
retail = pd.read_excel('Online Retail.xlsx')
๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ
๊ฒฐ์ธก์น & ์ด์์น ์ฒ๋ฆฌ
# ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ
# customer id ๊ฒฐ์ธก์น ์ญ์
cond1 = (retail['CustomerID'].notnull())
# invoice๊ฐ c๋ก ์์๋๊ฑฐ๋
cond2 = (retail['InvoiceNo'].astype(str).str[0] != 'C')
# quantity๊ฐ ์์์ด๊ฑฐ๋
cond3 = retail['Quantity']>0
# unit price๊ฐ ์์์ธ ๊ฒ์ ๋ชจ๋ ์ญ์
cond4 = retail['UnitPrice']>0
retail2 = retail[cond1 & cond2 & cond3 & cond4]
- CustomerID ๊ฒฐ์ธก์น ์ญ์
- invoice๊ฐ c๋ก ์์๋๊ฑฐ๋, quantity๊ฐ ์์์ด๊ฑฐ๋, unit price๊ฐ ์์์ธ ๊ฒ์ ๋ชจ๋ ์ญ์
์๊ตญ ๋ฐ์ดํฐ๋ง ์ ํ
cond5 = (retail2['Country']=='United Kingdom')
retail2 = retail2[cond5]
RFM ์ธ๊ทธ๋ฉํ ์ด์
RFM ๊ณ์ฐ ์ค๋น์์
# Recency ๊ณ์ฐํ๊ธฐ
import datetime as dt
# 2011.12.10์ผ ๊ธฐ์ค์ผ๋ก ๊ฐ ๋ ์ง๋ฅผ ๋นผ๊ณ + 1
# ์ถํ CustomerID ๊ธฐ์ค์ผ๋ก Period์ ์ต์์ Period๋ฅผ ๊ตฌํ๋ฉด ๊ทธ๊ฒ์ด Recency
# 1๋ฒ์ฌ๋ 100์ผ์ , 20์ผ์ , 5์ผ์
retail2['Period'] = (dt.datetime(2011,12,10) - retail2['InvoiceDate']).apply(lambda x: x.days+1)
# Amount : Quantity(์๋) * Price(๊ฐ๊ฒฉ)
retail2['Amount'] = retail2['Quantity'] * retail2['UnitPrice']
# Amount๋ฅผ ์ ์ํ์ผ๋ก ๋ณํ
retail2['Amount'] = retail2['Amount'].astype('int')
- Recency(๋ฐฉ๋ฌธ์) ๊ณ์ฐ ์ํด ๊ธฐ์ค์ผ(2011/12/10) Period ๊ณ์ฐ
- Monetary(์ผ๋ง๋ ์ผ๋์ง) ๊ณ์ฐ ์ํด ์ฃผ๋ฌธ๋ณ ์ฌ์ฉ ๊ธ์ก ๊ณ์ฐ ํ ์ด๋ฅผ ์ ์ํ์ผ๋ก ๋ณ๊ฒฝ
RFM ๋ฐ์ดํฐ ํ๋ ์
# customerId ๊ธฐ์ค RFM df ์์ฑ
rfm_retail = retail2.groupby('CustomerID').agg({
'Period': 'min',
'InvoiceNo':'count',
'Amount':'sum'
})
# ์ปฌ๋ผ๋ช
์ R, F, M ์ผ๋ก ์ค์
rfm_retail.columns = ['Recency','Frequency','Monetary']
RFM ๊ฐ๊ฐ์ feature๋ฅผ ๊ทธ๋ํ๋ก ํํํด๋ณด๊ธฐ
plt.figure(figsize = (18,6))
plt.subplot(1,3,1)
sns.histplot(rfm_retail['Recency'])
plt.title('Recency')
plt.subplot(1,3,2)
sns.histplot(rfm_retail['Frequency'])
plt.title('Frequency')
plt.subplot(1,3,3)
sns.histplot(rfm_retail['Monetary'])
plt.title('Monetary')
- ๋ถํฌ๊ฐ ๋ค๋ฅด๋ ์ธ feature ๋ชจ๋ right skewed๋์ด์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- ๋ฐ๋ผ์ ์๋์ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ์ ๊ทํ ํ๋ค.
# ๋ฐ์ดํฐ์ ๊ทํ
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_features = sc.fit_transform(rfm_retail[['Recency','Frequency','Monetary']])
์ค๋ฃจ์ฃ ๊ณ์๋ก ํ๊ฐํ๊ธฐ
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
kmeans = KMeans(n_clusters = 3, random_state = 42)
labels = kmeans.fit_predict(X_features)
rfm_retail['label'] = labels
silhouette_score(X_features, labels)
## 0.592575402996014
→ ์ค๋ฃจ์ฃ ๊ณ์๊ฐ ์ข์ ์์น์ธ์ง ์์๋ณด๊ธฐ ์ํด ์ฌ๋ฌ๊ฐ์ ๊ตฐ์ง ๊ฐ์๋ฅผ list๋ก ์ ๋ ฅ๋ฐ์ ๊ฐ๊ฐ์ ์ค๋ฃจ์ฃ ๊ณ์๋ฅผ ๋ฉด์ ์ผ๋ก ์๊ฐํํด๋ณด์.
๋๋ณด๊ธฐ
### ์ฌ๋ฌ๊ฐ์ ํด๋ฌ์คํฐ๋ง ๊ฐฏ์๋ฅผ List๋ก ์
๋ ฅ ๋ฐ์ ๊ฐ๊ฐ์ ์ค๋ฃจ์ฃ ๊ณ์๋ฅผ ๋ฉด์ ์ผ๋ก ์๊ฐํํ ํจ์ ์์ฑ
def visualize_silhouette(cluster_lists, X_features):
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
# ์
๋ ฅ๊ฐ์ผ๋ก ํด๋ฌ์คํฐ๋ง ๊ฐฏ์๋ค์ ๋ฆฌ์คํธ๋ก ๋ฐ์์, ๊ฐ ๊ฐฏ์๋ณ๋ก ํด๋ฌ์คํฐ๋ง์ ์ ์ฉํ๊ณ ์ค๋ฃจ์ฃ ๊ฐ์๋ฅผ ๊ตฌํจ
n_cols = len(cluster_lists)
# plt.subplots()์ผ๋ก ๋ฆฌ์คํธ์ ๊ธฐ์ฌ๋ ํด๋ฌ์คํฐ๋ง ์๋งํผ์ sub figures๋ฅผ ๊ฐ์ง๋ axs ์์ฑ
fig, axs = plt.subplots(figsize=(4*n_cols, 4), nrows=1, ncols=n_cols)
# ๋ฆฌ์คํธ์ ๊ธฐ์ฌ๋ ํด๋ฌ์คํฐ๋ง ๊ฐฏ์๋ค์ ์ฐจ๋ก๋ก iteration ์ํํ๋ฉด์ ์ค๋ฃจ์ฃ ๊ฐ์ ์๊ฐํ
for ind, n_cluster in enumerate(cluster_lists):
# KMeans ํด๋ฌ์คํฐ๋ง ์ํํ๊ณ , ์ค๋ฃจ์ฃ ์ค์ฝ์ด์ ๊ฐ๋ณ ๋ฐ์ดํฐ์ ์ค๋ฃจ์ฃ ๊ฐ ๊ณ์ฐ.
clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
cluster_labels = clusterer.fit_predict(X_features)
sil_avg = silhouette_score(X_features, cluster_labels)
sil_values = silhouette_samples(X_features, cluster_labels)
y_lower = 10
axs[ind].set_title('Number of Cluster : '+ str(n_cluster)+'\n' \
'Silhouette Score :' + str(round(sil_avg,3)) )
axs[ind].set_xlabel("The silhouette coefficient values")
axs[ind].set_ylabel("Cluster label")
axs[ind].set_xlim([-0.1, 1])
axs[ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
axs[ind].set_yticks([]) # Clear the yaxis labels / ticks
axs[ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])
# ํด๋ฌ์คํฐ๋ง ๊ฐฏ์๋ณ๋ก fill_betweenx( )ํํ์ ๋ง๋ ๊ทธ๋ํ ํํ.
for i in range(n_cluster):
ith_cluster_sil_values = sil_values[cluster_labels==i]
ith_cluster_sil_values.sort()
size_cluster_i = ith_cluster_sil_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i) / n_cluster)
axs[ind].fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_sil_values, \
facecolor=color, edgecolor=color, alpha=0.7)
axs[ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
y_lower = y_upper + 10
axs[ind].axvline(x=sil_avg, color="red", linestyle="--")
from kmeans_visaul import visualize_silhouette
visualize_silhouette([2,3,4,5,6], X_features)
- cluster์ ์๊ฐ 2์ผ๋๋ณด๋ค 5์ผ๋ ์ค๋ฃจ์ฃ ๊ณ์๊ฐ ํฌ๋ค.
- ๊ทธ๋ฌ๋ ์๋ ๋ฉด์ ๊ทธ๋ํ๋ฅผ ๋ณด๋ฉด cluster๊ฐ 5์ผ๋ best๊ฐ ์๋๋ผ๋ ๊ฒ์ ์ ์ ์๋ค.
- cluster = 5์ธ ๊ฒฝ์ฐ 5๊ฐ ๊ตฐ์ง์ ๋ฉด์ ์ด ๊ณ ๋ฅด๊ฒ ๋ถํฌ๋์ง ์์๋ค.
- ์์ 3๊ฐ์ ๊ตฐ์ง์ ๊ฒฝ์ฐ ์์ฃผ ์ ์ ๋ฉด์ ์ ์ฐจ์งํ๊ณ ์์ผ๋ฉฐ, ์ด๋ ์ผ๋ถ ์ด์์น์ ์ํด ๊ฒฐ๊ณผ๊ฐ ์๊ณก๋๊ณ ์์์ ๋ํ๋ด๋ ๊ฒ์ด๋ค.
- ๋ฐ๋ผ์ ์๋์ ๊ฐ์ด log ์ค์ผ์ผ์ ์ด์ฉํด ์ถ๊ฐ ์ ์ฒ๋ฆฌ ๊ณผ์ ์ ์งํํ๋ค.
#log ์ค์ผ์ผ์ ํตํ ์ถ๊ฐ์ ์ฒ๋ฆฌ
import numpy as np
rfm_df['Recency_log'] = np.log1p(rfm_df['Recency'])
rfm_df['Frequency_log'] = np.log1p(rfm_df['Frequency'])
rfm_df['Monetary_log'] = np.log1p(rfm_df['Monetary'])
X_features2 = rfm_df[['Recency_log','Frequency_log','Monetary_log']]
sc2 = StandardScaler()
X_features2_sc = sc2.fit_transform(X_features2)
visualize_silhouette([2,3,4,5,6], X_features2_sc)
- ์ ๊ทํ๋ง ์งํํ์ ๋์ ๋นํด ๋น๊ต์ ๊ณ ๋ฅด๊ฒ cluster๋ณ ๋ฉด์ ์ด ๋๋์ด์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- ์ค๋ฃจ์ฃ ๊ณ์๋ ๋ฎ์์ก์ง๋ง, ๊ตฐ์ง์ด ๋น๊ต์ ๊ณ ๋ฅด๊ฒ ๋๋์๋ค.
'๐ Today I Learn > ๐ Python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋จธ์ ๋ฌ๋์ ์ดํด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ (7) ๋ฅ๋ฌ๋ (1) | 2024.06.13 |
---|---|
๋จธ์ ๋ฌ๋ ํน๊ฐ #1 ๋ถ๋ฅ(Clasification) (0) | 2024.06.12 |
๋จธ์ ๋ฌ๋์ ์ดํด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ (5) ํ๊ท, ๋ถ๋ฅ ๋ชจ๋ธ๋ง ์ฌํ (0) | 2024.06.11 |
ํต๊ณ์ผ ๋์ (4) ์ง๋ํ์ต๊ณผ ๋น์ง๋ํ์ต (1) | 2024.06.11 |
ํต๊ณ์ผ ๋์ (3) ํ๊ท์ ์์ธก (2) | 2024.06.10 |