파이썬 빅데이터 분석 Day 15

2023. 10. 26. 15:55·데이터분석실습/데이터 과학 기반의 파이썬 빅데이터 분석

15. 데이터 분석하기판매 데이터 분석(22.07.25)

[K-평균 군집화 분석 + 그래프]

목표: 판매 데이터를 분석하여, 소비자 군집을 구성하기.

 

비지도 학습이란?: 훈련데이터에 타깃값이 없는 상태에서 학습을 진행.

 

훈련데이터 학습 -> 모델 생성 -> 유사한 특성을 가지는 데이터를 클러스터로 구성-> 새로운 데이터의 특성을 분석하여 클러스터 예측

 

군집화란?: 데이터를 군집으로 구성하는 작업.

군집에 대한 정보를 가지고 있지 않기 때문에 비지도 학습을 수행하여, 데이터의 관계를 분석하고 이에 따라 유사한 데이터를 군집으로 구성. -> K-평균, 계층적 군집

 

K-평균 군집이란?: k개의 클러스터를 구성하기 위한 것.

k개의 임의의 중심점을 잡고 그 점을 기준으로 가까이 있는 데이터를 두 사이의  평균지점으로 중심점을 이동, 반복.

가장 많이 하는 군집화 알고리즘이지만, 클러스터의 수를 나타내는 k를 직접 지정해야 하는 문제가 있다.

  • > 엘보 방법, 실루엣 방법

엘보우 방법이란?: 클러스터의 중심점과 클러스터내의 데이터 거리 차이의 제곱값 합을 왜곡이라고 하고 이 왜곡을 이용해 최적의 k를 찾음.

왜곡의 변화의 그래프를 그렸을 때, 그래프가 꺽이는 지점을 최적의 k로 설정.

 

실루엣 분석이란?: 클러스터에 있는 데이터가 얼마나 조밀하게 모여있는지를 측정하는 그래프 도구 (-1 ~ 1)범위이며 1에 가까울수록 좋음

 

클러스터 응집력: 데이터 i가 클러스터 내의 데이터와 얼마나 가까운가를 나타내는 수치.

클러스터 분리도: 가장 가까운 다른 클러스터 내의 데이터와 얼마나 떨어져있는가를 나타내는 수치.

1. 데이터 수집

 

UCI Machine Learning Repository

Welcome to the UC Irvine Machine Learning Repository We currently maintain 657 datasets as a service to the machine learning community. Here, you can donate and find datasets used by millions of people all around the world!

archive.ics.uci.edu

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가 가장 높다. 이런식의 분석을 통해 다양한 마케팅 전략을 세울 수 있다.

728x90

'데이터분석실습 > 데이터 과학 기반의 파이썬 빅데이터 분석' 카테고리의 다른 글

파이썬 빅데이터 분석 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
'데이터분석실습/데이터 과학 기반의 파이썬 빅데이터 분석' 카테고리의 다른 글
  • 파이썬 빅데이터 분석 Day 17
  • 파이썬 빅데이터 분석 Day 16
  • 파이썬 빅데이터 분석 Day 14
  • 파이썬 빅데이터 분석 Day 13
창빵맨
창빵맨
  • 창빵맨
    Let's be Developers
    창빵맨
    로그인/로그아웃
  • 전체
    오늘
    어제
    • 분류 전체보기 (471)
      • 알쓸신잡 (79)
      • ML & DL (85)
        • Computer v.. (22)
        • NLP (22)
        • 파이썬 머신러닝 완.. (3)
        • 개념정리 (38)
      • 리눅스 (21)
      • 프로젝트 (29)
        • 산불 발생 예측 (6)
        • 음성비서 (12)
        • pdf 병합 프로그.. (0)
        • 수위 예측 (5)
        • 가짜 뉴스 분류 (5)
        • 전력사용량 예측 (1)
      • 코딩테스트 (217)
        • 프로그래머스[Pyt.. (17)
        • 프로그래머스[Fai.. (3)
        • 백준[Python] (160)
        • 이것이취업을위한코딩.. (18)
        • 파이썬 알고리즘 (19)
      • 데이터분석실습 (25)
        • 데이터 과학 기반의.. (18)
        • 헬로 데이터 과학 (7)
      • 메모장 (0)
      • 잡담 (4)
  • Personal

    GITHUB
    Instagram
  • 공지사항

  • 인기 글

  • 태그

    파이썬
    그리디
    이것이취업을위한코딩테스트다
    dp
    DFS
    BFS
    백준
    이분탐색
    나동빈
    이코테
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3

HOME

HOME

상단으로

티스토리툴바