일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 앱개발
- 머신러닝
- GYM
- TeachagleMachine
- expo
- Ros
- JavaScript
- coding
- ReactNative
- python
- FirebaseV9
- App
- redux
- 강화학습 기초
- 사이드프로젝트
- 전국국밥
- clone coding
- kaggle
- 딥러닝
- 조코딩
- 클론코딩
- 데이터분석
- React
- Instagrame clone
- 리액트네이티브
- 카트폴
- 강화학습
- pandas
- selenium
- Reinforcement Learning
- Today
- Total
qcoding
[데이터분석실습][데이터전처리]스타벅스 고객 데이터 분석하기 본문
https://www.kaggle.com/code/ishadss/coffee-starbucks-customer-clusters-and-eda/data
Coffee Starbucks-Customer Clusters and EDA
Explore and run machine learning code with Kaggle Notebooks | Using data from Starbucks Customer Data
www.kaggle.com
Data Description
Profile table
profile 데이터는 설문에 참여한 스타벅스 회원에 관련된 정보가 담겨 있습니다.
transcript
이벤트에 참여한 실제 유저들의 응답이 기록되어 있습니다.
portfoilo
이벤트를 운영했던 내역에 관한 정보가 담겨 있습니다.
## 데이터 불러오기
# 데이터 분석 필수 라이브러리 4종 세트 불러오기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import matplotlib as mpl
# Starbucks Customer Data 폴더안에 있는 데이터 3개를 불러오기
transcript = pd.read_csv('./transcript.csv', index_col = 0)
profile = pd.read_csv('./profile.csv', index_col = 0)
portfolio = pd.read_csv('./portfolio.csv', index_col = 0)
##데이터 확인해 보기
print(f"transcript 데이터 : {transcript.shape}")
print(f"profile 데이터 : {profile.shape}")
print(f"portfolio 데이터 : {portfolio.shape}")
## 정보확인
print("----------transcript----------")
display(transcript.info())
print("----------profile----------")
display(profile.info())
print("----------portfolio----------")
display(portfolio.info())
### 데이터 전처리
# 각 데이터에 결측치가 있는지 확인합니다.
## 결측치 확인
print("----------transcript----------")
display(transcript.isnull().sum())
print("----------profile----------")
display(profile.isnull().sum())
print("----------portfolio----------")
display(portfolio.isnull().sum())
transcript 와 portfolio에서는 결측치가 없으며, profile내의 gender와 income 에서 각각 2175 개의 결측치가 포함되어 있음.
# 결측치를 포함하는 데이터들은 어떤 데이터들인지 확인합니다.
## 결측치를 포함하는 profile내의 gender와 income의 데이터를 확인함
## gender 데이터와 income 데이터 확인하기
## gender 데이터는 nominal 데이터로 countplot을 통해서 확인함
## income의 경우는 구간에 따라 달라지므로 histplot 통해서 확인함
mpl.rc('font',size=12)
fig, axes = plt.subplots(nrows=1,ncols=2)
plt.tight_layout()
fig.set_size_inches(11,5)
## gender
sns.countplot(x='gender', data=profile , ax=axes[0])
axes[0].set(title = "Gender")
## income
sns.histplot(x='income', data=profile ,bins=20 ,ax=axes[1])
axes[1].set(title = "Income")
gender 데이터에는 Female , Male 외에 O 라고 하는 값이 존재합니다. income은 수입을 나타내는 데이터로 단위는 $를 나타내는 것으로 보입니다. 20개의 구간으로 나누어 살펴 보았을 때 60,000 ~ 80,000 구간이 제일 많이 나타난 것을 볼수있습니다.
# 결측치를 처리해줍니다. # 평균과 같은 통계량으로 채워주거나, 버립니다.
## 여기서는 결측치가 2175로 매우 많지만, 해당 통계량이 gender / income으로 gender의 경우는 평균이나 임의의 값으로 채우는 것이 쉽지 않으므로
## 결측치가 있는 데이터는 버리는 방법을 선택함.
print(f"결측치 제거 전 data : { profile.shape} ")
profile = profile.dropna(subset=['gender','income'],axis=0)
print(f"결측치 제거 후 data : { profile.shape} ")
## profile 데이터 분석
# profile의 became_member_on 데이터를 시간 정보로 변환해줍니다.
profile.became_member_on = pd.to_datetime(profile.became_member_on.astype(str), format='%Y%m%d')
profile.info()
## 그래프에 퍼센트를 표시 하기위한 함수
def write_percent(ax,total_size):
for patch in ax.patches:
height = patch.get_height()
width = patch.get_width()
# 도형의 왼쪽 테두리
left_coord = patch.get_x()
# 전체에서 비율을 얼마나 차지하는지
percent = height / total_size * 100
# (x,y) 좌표에 텍스트 입력
ax.text(
x=left_coord + width / 2,
y= height + total_size * 0.003,
s=f'{percent:1.1f}%',
# 가운데정렬
ha='center'
)
## 성별에 대한 분석
## 성별에 대한 분석
fig , ax = plt.subplots()
fig.set_size_inches(7,5)
ax=sns.countplot(x='gender' , data=profile )
write_percent(ax,len(profile))
ax.set(title='Gender')
셩별은 남자가 57.2%로 제일 많으며, O 라는 카테고리가 존재합니다
## 나이에 대한 분석
## 나이에 대한 분석
fig , ax = plt.subplots()
fig.set_size_inches(25,5)
ax=sns.countplot(x='age' , data=profile )
# write_percent(ax,len(profile))
ax.set(title='Age')
ax.tick_params(axis='x' , labelrotation=45)
나이는 18 ~ 100살 이상까지 다양하게 분포되어 있으며, 가장 많은 연령층은 40 ~ 50 대로 보여집니다.
## 회원이 된 날짝에 대한 분석
## 회원이 된 날짜에 대한 분석
## 시간데이터는 연속성이 있으므로 lineplot을 통해서 확인함.
## 날짜는 값들이 많이 있으므로 년도만 구분하여 그래프를 통해 표현함.
profile['became_member_on_year']=profile['became_member_on'].dt.year
profile['became_member_on_month']=profile['became_member_on'].dt.month
fig , axes = plt.subplots(nrows=3,ncols=1)
# plt.tight_layout()
fig.set_size_inches(25,25)
plt.subplots_adjust(hspace=0.2)
## 1) 연도별 그리기
axes[0]=sns.countplot(x='became_member_on_year', data=profile ,ax=axes[0])
write_percent(axes[0],len(profile))
axes[0].set(title='Customer by Year')
## 2) 연도별 월별 변화량 그리기
## 필요한 데이터 생성하기
grouped = profile.groupby(['became_member_on_year','became_member_on_month'],as_index=False).agg(
customer = ('became_member_on_month','count')
)
grouped['month'] = grouped['became_member_on_year'].astype('str') +"-"+grouped['became_member_on_month'].astype('str')
## 연도별 월별 변화량 그리기
axes[1]=sns.pointplot(x='became_member_on_month' , y='customer' ,data=grouped ,hue='became_member_on_year',ax=axes[1])
axes[1].set(title='Customer by Year & Month')
## 3) 연도 + 월별 합쳐서 하나로 그래프 그리기
axes[2]=sns.pointplot(x='month' , y='customer' , data=grouped , ax=axes[2])
axes[2].set(title='Customer by Year & Month')
axes[2].tick_params(axis='x' , labelrotation=45)
--> 2017년에는 고객이 크게 증가했지만 2018년에는 고객 수가 감소 했다는 것을 알 수 있습니다.
### 수입에 대한 분석
## income
fig , axes = plt.subplots(nrows=2 , ncols=1)
plt.subplots_adjust(hspace=0.4)
fig.set_size_inches(11,7)
sns.histplot(x='income', data=profile ,bins=20,ax=axes[0])
axes[0].set(title = "Income")
sns.histplot(x='income', data=profile ,bins=20 , hue='gender' , multiple='dodge',shrink=0.8 ,ax=axes[1])
axes[1].set(title = "Income by gender")
--> 대부분의 회원은 50,000 ~ 70,000 달러의 수입을 가지고 있으며, 80,000달러 보다 작은 구간에서는 남자회원들의 소득이 높으며, 그 이후의 구간에서는 여성의 수입이 더 높은 것을 확인할 수 있습니다.
## profile 데이터에 대한 상관 관계 분석
--> profile에서는 age에 따른 수입과 gender에 따른 수입을 비교해 볼 수 있습니다. 일반적으로 age가 낮을 경우 소득이 없다가 높아지면서 소득이 증가할 것이고, 나이가 매우 많이 들면 다시 낮아 질 것을 예상할 수 있습니다.
또한 수입의 경우 위의 그래프 결과에서 80,000달러 보다 작은 경우 남성이 일반적으로 많지만 그 이상이 되면 여성이 많은 것을 볼 수 있습니다. 아래의 boxplot에서 살펴보면, 남자의 경우는 분포가 전반적으로 여자에 비해 낮게 되어있으므로, 120,000달러 근처에서의 수입을 이상치로 판단하고 있음을 알 수 있습니다.
mpl.rc('font',size=13)
fig , axes = plt.subplots(nrows=2 , ncols=1)
plt.subplots_adjust(hspace=0.5)
fig.set_size_inches(11,15)
## age vs income
## ~20 수정
profile['age_fil']=profile['age']
profile.loc[profile['age']=='~20','age_fil'] = 10
profile['age_fil'] = profile['age_fil'].astype('int')
## 그래프생성
profile.loc[ (profile['age_fil']) < 20 ,'age_class'] = '~20'
profile.loc[ (profile['age_fil'] >= 20 ) & (profile['age_fil'] < 40 ),'age_class'] = '20~40'
profile.loc[ (profile['age_fil'] >= 40 ) & (profile['age_fil'] < 60 ),'age_class'] = '40~60'
profile.loc[ (profile['age_fil'] >= 60 ) & (profile['age_fil'] < 80 ),'age_class'] = '60~80'
profile.loc[ (profile['age_fil'] >= 80 ) & (profile['age_fil'] < 100 ),'age_class'] = '80~100'
profile.loc[ (profile['age_fil'] >= 100 ),'age_class'] = '100~'
sns.boxplot(x='age_class', y='income', data=profile ,ax=axes[0], order=['~20','20~40','40~60','60~80','80~100','100~'],)
axes[0].set(title = "Age VS Income")
axes[0].tick_params(axis='x', labelrotation=45)
## gender vs income
sns.boxplot(x='gender', y='income', data=profile ,ax=axes[1])
axes[1].set(title = "Gender VS Income")
### Transciprt 에 대한 분석
## event에 대한 분석
## person 과 values는 분석 대상에서 제외함
## event에 대한 value 값을 확인함
np.round(transcript['event'].value_counts() / transcript['event'].value_counts().sum() * 100,1)
event에 대한 값은 transction(거래)이 45.3%로 매우 많은 값을 나타내며, 그다음으로 offer_receive가 24.9로 많은 양을 나타내는 것을 볼 수 있습니다.
## 데이터 시각화
mpl.rc('font',size=15)
fig , ax = plt.subplots()
fig.set_size_inches(11,7)
ax=sns.countplot(x='event',data=transcript, order=transcript['event'].value_counts().sort_values(ascending=False).index)
write_percent(ax,len(transcript))
ax.set(title='Event Category')
## time에 대한 분석
-> time은 테스트 시작 이후의 시간을 의미한다는 것을 구글링을 통해서 알 수 있엇습니다. 결국 t=0 부터 시작하여 얼마간의 시간이 지났는 지를 의미합니다.
transcript['time'].unique()
## pandas cut을 이용해서 총 8개의 구간으로 시간을 나눠 준다. 이 때 구간은 적절하게 8개로 나누어 준다.
transcript['Timeout'] = pd.cut(x=transcript['time'], bins=[0, 100, 200, 300, 400, 500,600,700,800], include_lowest=True,
labels=['0-100 days', '100-200 days', '200-300 days', '300-400 days', '400-500 days', '500-600 days', '600-700 days', '700-800 days'])
##각각의 비율확인
np.round(transcript['Timeout'].value_counts() / transcript['Timeout'].value_counts().sum() * 100,2)
## 시각화
mpl.rc('font',size=13)
fig, ax = plt.subplots()
fig.set_size_inches(11,10)
ax=sns.countplot(x='Timeout', data=transcript)
ax.set(title='Timeout Starbucks')
ax.tick_params(axis='x', labelrotation=45)
## transcript 상에서 사용자가 접속했을 때의 통계 분석
--> 여기서 분석하려고 하는 것은 transcript 에 들어있는 user의 접속 기록들을 살펴보고 , 어떤 목적으로 접속했는 지에 대한 통계를 보는 것 입니다.
-> 추가로 접속했을 때의 transcript 내의 value에 offer_id 또는 거래 금액에 대한 정보가 있으므로, offer id를 통해서 portpolio 내에 있는 각 offer_id와 비교하여 사용자가 어떤 목적으로 방문을 많이 했는 지를 찾을 수 있습니다.
## data 확인
transcript
# 데이터 확인
portfolio
# str로 되어있는 데이터를 dictionary로 변환
## string으로 형 변환된 것을 eval을 사용해서 코드화를 시킴.
## literal_eval을 사용할 수도 있음
transcript['value'] = transcript['value'].astype('str').apply(lambda x:eval(x))
print(f"type: {type(transcript['value'])}")
# event에 따른 value의 차이 확인
## value 안에 있는 항목을 분류하고, offer_id를 추출하기 위해서 key와 value 값을 분리하여 파생피처를 추가함.
transcript["value_key"] = transcript['value'].apply(lambda x:list(x.keys())[0])
transcript["value_value"] = transcript['value'].apply(lambda x:list(x.values())[0])
transcript
## value category에 대한 분류 값을 확인함
plt.figure(figsize=(8, 6))
sns.countplot(data=transcript, x="value_key")
plt.show()
## transcript 데이터에서 offer_id에 따른 접속목적을 확인하기 위해서 offer_id를 제공한 경우의 데이터를 필터링함
temp = transcript.loc[transcript['value_key'] != "amount", "value_value"]
temp_df = pd.DataFrame({"id" : temp.values})
temp_df
## portpolio 내에 있는 offer_id 정보와 합치기 위해서 아래와 같이 merge를 활용함.
## how는 temp_df에 어느방향으로 붙이는 것이며, on은 어떤 피처를 기준으로 합칠지에 대한 것을 나타냄
temp_portfolio = pd.merge(temp_df, portfolio, how="left", on="id")
temp_portfolio
## 실제 user가 접속할 때 제공받은 offer_id를 통해서 어떤 방법으로 접속했는지를 확인할 수 있음
plt.figure(figsize=(18, 10))
sns.countplot(data=temp_portfolio, x="channels", palette="Set2")
plt.show()
'Python 데이터분석' 카테고리의 다른 글
[데이터분석실습][다중분류_LR/XGB]공부 잘하는 것과 연관 된 연구 (0) | 2022.09.01 |
---|---|
[데이터분석실습][이진분류_LR/XGB]Heart Failure Prediction_kaggle (0) | 2022.08.13 |
[데이터분석 실습][데이터전처리]구글플레이스토어 데이터 분석 (1) | 2022.07.29 |
[데이터 분석실습]타이타닉 데이터 (0) | 2022.07.23 |
[데이터분석실습][회귀-LGBM/XGB] 향후 판매량 예측 _ 회귀 (0) | 2022.07.12 |