15. 데이터 분석하기판매 데이터 분석(22.07.25)
[K-평균 군집화 분석 + 그래프]
목표: 판매 데이터를 분석하여, 소비자 군집을 구성하기.
비지도 학습이란?: 훈련데이터에 타깃값이 없는 상태에서 학습을 진행.
훈련데이터 학습 -> 모델 생성 -> 유사한 특성을 가지는 데이터를 클러스터로 구성-> 새로운 데이터의 특성을 분석하여 클러스터 예측
군집화란?: 데이터를 군집으로 구성하는 작업.
군집에 대한 정보를 가지고 있지 않기 때문에 비지도 학습을 수행하여, 데이터의 관계를 분석하고 이에 따라 유사한 데이터를 군집으로 구성. -> K-평균, 계층적 군집
K-평균 군집이란?: k개의 클러스터를 구성하기 위한 것.
k개의 임의의 중심점을 잡고 그 점을 기준으로 가까이 있는 데이터를 두 사이의 평균지점으로 중심점을 이동, 반복.
가장 많이 하는 군집화 알고리즘이지만, 클러스터의 수를 나타내는 k를 직접 지정해야 하는 문제가 있다.
- > 엘보 방법, 실루엣 방법
엘보우 방법이란?: 클러스터의 중심점과 클러스터내의 데이터 거리 차이의 제곱값 합을 왜곡이라고 하고 이 왜곡을 이용해 최적의 k를 찾음.
왜곡의 변화의 그래프를 그렸을 때, 그래프가 꺽이는 지점을 최적의 k로 설정.
실루엣 분석이란?: 클러스터에 있는 데이터가 얼마나 조밀하게 모여있는지를 측정하는 그래프 도구 (-1 ~ 1)범위이며 1에 가까울수록 좋음
클러스터 응집력: 데이터 i가 클러스터 내의 데이터와 얼마나 가까운가를 나타내는 수치.
클러스터 분리도: 가장 가까운 다른 클러스터 내의 데이터와 얼마나 떨어져있는가를 나타내는 수치.
1. 데이터 수집
UCI Machine Learning Repository 접속 -> online retail 검색 -> 검색목록 중 첫번째 클릭 -> data folder클릭 -> Online Retail.xlsx 다운
retail_df=pd.read_excel('data/Retail/Online_Retail.xlsx')
retail_df.head()
2.데이터 준비 및 탐색
retail_df.info()
데이터의 정보를 봤을 때, CustomerID의 자료형이 실수이므로, 정수형으로 바꿔줘야 하고, 또한 null값이 있으므로, CustomerID가 없는 데이터는 제거한다. 추가로 Quantity와 UnitPrice가 음수인 것을 제거한다.
retail_df=retail_df[retail_df['Quantity']>0]
retail_df=retail_df[retail_df['UnitPrice']>0]
retail_df=retail_df[retail_df['CustomerID'].notnull()]
retail_df['CustomerID']=retail_df['CustomerID'].astype(int)
retail_df.info()
print(retail_df.isnull().sum())
print(retail_df.shape)
데이터 탐색을 위해 기본 정보들을 알아보자.
pd.DataFrame([{'Product':len(retail_df['StockCode'].value_counts()),'Transaction':len(retail_df['InvoiceNo'].value_counts()),
'Customer':len(retail_df['CustomerID'].value_counts())}],columns=['Product','Transaction','Customer'],index=['counts'])
데이터 탐색을 위해 제품, 거래, 고객 수를 알아보고 고객의 국적을 확인해봤다.
retail_df['SaleAmount']=retail_df['UnitPrice']*retail_df['Quantity']
retail_df.head()
고객정보에 대한 데이터만 모아서 새로운 데이터프레임을 만든다.
(ElapsedDays는 마지막 주문일로부터 며칠이 지났는지에 대한 값을 나타낸다.)
aggregations={
'InvoiceNo':'count',
'SaleAmount':'sum',
'InvoiceDate':'max'
}
customer_df=retail_df.groupby('CustomerID').agg(aggregations)
customer_df=customer_df.reset_index()
customer_df=customer_df.rename(columns={'InvoiceNo':'Freq','InvoiceDate':'ElapsedDays'})
customer_df.head()
import datetime
customer_df['ElapsedDays']=datetime.datetime(2011,12,10)-customer_df['ElapsedDays']
customer_df['ElapsedDays']=customer_df['ElapsedDays'].apply(lambda x: x.days+1)
customer_df.head()
다음으로 데이터의 분포를 시각화를 통해 알아보자.
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax=plt.subplots()
ax.boxplot([customer_df['Freq'],customer_df['SaleAmount'],customer_df['ElapsedDays']],sym='bo')
plt.xticks([1,2,3],['Freq','SaleAmount','ElapsedDays'])
plt.show()
박스플롯에 표시된 아웃레이어값을 보면 현재 데이터가 불균형하다는 것을 볼 수 있다. 값이 한 쪽으로 치우쳐져있는 것을 조정하기위해 로그함수를 씌워준다.
customer_df['Freq_log']=np.log1p(customer_df['Freq'])
customer_df['SaleAmount_log']=np.log1p(customer_df['SaleAmount'])
customer_df['ElapsedDays_log']=np.log1p(customer_df['ElapsedDays'])
customer_df.head()
fig, ax=plt.subplots()
ax.boxplot([customer_df['Freq_log'],customer_df['SaleAmount_log'],customer_df['ElapsedDays_log']],sym='bo')
plt.xticks([1,2,3],['Freq_log','SaleAmount_log','ElapsedDays_log'])
plt.show()
확인해보면 이전보다 균형잡힌 모습을 볼 수 있다.
2.분석 모델 구축
k-평균 군집화 모델을 이용해보자.
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score, silhouette_samples
from sklearn.preprocessing import StandardScaler
x_features=customer_df[['Freq_log','SaleAmount_log','ElapsedDays_log']].values
x_features_scaled=StandardScaler().fit_transform(x_features)
[01~03행] :sklearn 패키지에서 kmeans, 실루엣점수, 실루엣샘플, 정규분포스케일링을 import
[04,05행]: 모델에 사용할 값을 정규화하여 저장.
distortions=[]
for i in range(1,11):
kmeans_i=KMeans(n_clusters=i,random_state=0)
kmeans_i.fit(x_features_scaled)
distortions.append(kmeans_i.inertia_)
plt.plot(range(1,11),distortions,marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('Distortion')
plt.show()
클러스터 개수를 1~11까지 변화시키면서 왜곡의 크기를 엘보우 기법을 사용해서 찾는다. 꺽이는 지점을 찾아보면 적절한 클러스터의 갯수는 3,4,5가 될 수 있고 여기서는 3을 사용해 볼 것이다.
kmeans=KMeans(n_clusters=3,random_state=0)
y_labels=kmeans.fit_predict(x_features_scaled)
customer_df['ClusterLabel']=y_labels
customer_df.head()
분류를 하고 새로운 column을 추가하여 군집을 확인해보면 0,1,2 이렇게 세 군집으로 나뉜것을 볼 수 있다.
3. 결과 분석 및 시각화
from matplotlib import cm
def silhouetteViz(n_cluster,x_features):
kmeans=KMeans(n_clusters=n_cluster,random_state=0)
y_labels=kmeans.fit_predict(x_features)
silhouette_values=silhouette_samples(x_features,y_labels,metric='euclidean')
y_ax_lower,y_ax_upper=0,0
y_ticks=[]
for c in range(n_cluster):
c_silhouettes=silhouette_values[y_labels==c]
c_silhouettes.sort()
y_ax_upper+=len(c_silhouettes)
color=cm.jet(float(c)/n_cluster)
plt.barh(range(y_ax_lower,y_ax_upper),c_silhouettes,height=1.0,edgecolor='none',color=color)
y_ticks.append((y_ax_lower+y_ax_upper)/2.)
y_ax_lower+=len(c_silhouettes)
silhouette_avg=np.mean(silhouette_values)
plt.axvline(silhouette_avg,color='red',linestyle='--')
plt.title('Number of Cluster: '+str(n_cluster)+'\n' +'Silhouette Score: '+str(round(silhouette_avg,3)))
plt.yticks(y_ticks,range(n_cluster))
plt.ylabel('Cluster')
plt.xlabel('Silhouette coefficient')
plt.tight_layout()
plt.rc('axes', unicode_minus=False)
plt.show()
실루엣 계수를 구하고, 각 클러스터의 비중을 barh로 시각화하기 위한 함수를 구성한다.군집의 수가 3,4,5,6일 때를 시각화를 통해서 비교해보자.
silhouetteViz(3,x_features_scaled)
silhouetteViz(4,x_features_scaled)
silhouetteViz(5,x_features_scaled)
silhouetteViz(6,x_features_scaled)
위 결과를 통해서 클러스터의 비중이 한쪽으로 치우치지 않고 비슷하면서 실루엣 계수가 높은 것은 군집의 갯수를 4로 정했을 때이다.
다음으로는 클러스터의 데이터 분포를 확인하기 위헤 스캐터 차트로 시각화한다.
def clusterScatter(n_cluster, x_features):
c_colors = []
kmeans = KMeans(n_clusters=n_cluster, random_state=0)
y_labels = kmeans.fit_predict(x_features)
for i in range(n_cluster):
c_color = cm.jet(float(i) / n_cluster)#클러스터의 색상 설정
c_colors.append(c_color)
#클러스터의 데이터 분포를 동그라미로 시각화
plt.scatter(x_features[y_labels == i,0], x_features[y_labels == i,1],marker='o', color=c_color, edgecolor='black', s=50, label='cluster '+ str(i))
#각 클러스터의 중심점을 삼각형으로 표시for i in range(n_cluster):
plt.scatter(kmeans.cluster_centers_[i,0], kmeans.cluster_centers_[i,1], marker='^', color=c_colors[i], edgecolor='w', s=200)
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
clusterScatter(3,x_features_scaled)
clusterScatter(4,x_features_scaled)
clusterScatter(5,x_features_scaled)
clusterScatter(6,x_features_scaled)
위 결과를 통해서 데이터가 섞이지 않고 클러스터끼리 모여있는 형태를 찾으면 군집의수가 3개일 때와 4개일 때가 좋아보이는데, 실루엣 시각화를 해봤을 때 4개로 군집했을 때가 좋았으므로 최종적으로 군집의 수는 4로 결정한다.
군집의 수를 4개로 결정하고 분류된 군집을 라벨링한다.
best_cluster = 4
kmeans = KMeans(n_clusters=best_cluster, random_state=0)
y_labels = kmeans.fit_predict(x_features_scaled)
customer_df['ClusterLabel'] = y_labels
customer_df.head()
마지막으로 클러스터의 특징을 살펴보기 위해서 먼저 ClusterLabel을 기준으로 그룹을 만든다.
customer_df.groupby('ClusterLabel')['CustomerID'].count()
고객 클러스터에서 정보를 추출해보자.
customer_cluster_df = customer_df.drop(['Freq_log', 'SaleAmount_log', 'ElapsedDays_log'],axis=1, inplace=False)
# 주문 1회당 평균 구매금액 : SaleAmountAvg
customer_cluster_df['SaleAmountAvg'] = customer_cluster_df['SaleAmount']/customer_cluster_df['Freq']
customer_cluster_df.head()
# 클러스터별 분석
customer_cluster_df.drop(['CustomerID'],axis=1, inplace=False).groupby('ClusterLabel').mean()
위 결과를 통해서 클러스터 0는 구매횟수도 다른 군집보다 월등히 높지만, 구매당 평균 금액(SaleAmountAvg)는 두번째이다.그리고 구매당 평균 금액은 군집 2가 가장 높다. 이런식의 분석을 통해 다양한 마케팅 전략을 세울 수 있다.
'데이터분석실습 > 데이터 과학 기반의 파이썬 빅데이터 분석' 카테고리의 다른 글
파이썬 빅데이터 분석 Day 17 (1) | 2023.11.02 |
---|---|
파이썬 빅데이터 분석 Day 16 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 14 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 13 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 12 (1) | 2023.10.26 |