목차
1. 개요
2. Data 설명
3. EDA
4. 결론
5. 참고 url
# 개요
https://www.kaggle.com/c/instacart-market-basket-analysis
당신이 꼼꼼하게 계획된 식료품 리스트를 기반으로 쇼핑을 하든, 충독적으로 쇼핑하든, 우리의 음식구매패턴은 우리가 누구인지 정의한다. 식료품 주문 및 배달 앱인 Instacart는 필요할 때 냉장고와 선반안에 당신이 가장 좋아하는 것으로 쉽게 채울 수 있도록 하는 것을 목표로 한다. 인스타카트 앱을 통해 상품을 고른 후, 자신의 장바구니를 검토하고 구매한다.
Instacart의 데이터 분석팀은 이 즐거운 쇼핑 경험을 제공하는 데 큰 역할을 한다. 현재 그들은 사용자가 어떤 제품을 다시 구매할지 예측하거나, 처음 구매하거나, 다음에 장바구니에 추가할지를 예측하는 모델을 개발하기 위해 트랜잭션 데이터를 사용한다. 최근에, Instacart는 300만 개의 데이터를 오픈했다.
이 경쟁에서, Instacart는 kaggle 에서 어떤 제품이 사용자의 다음 구매에 포함될 것인지를 예측하기 위한 데이터분석 모델을 찾고 있다.
# Data 설명
Data | Data Column |
|
|
# EDA
Step1 . 라이브러리 / DataSet 불러오기
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import seaborn as sns
color = sns.color_palette()
%matplotlib inline
pd.options.mode.chained_assignment = None
# matplotlib 한글 폰트 깨짐 방지
from matplotlib import font_manager, rc
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
order_products_train_df = pd.read_csv(r'파일저장 경로\order_products__train.csv')
order_products_prior_df = pd.read_csv(r'파일저장 경로\order_products__prior.csv')
orders_df = pd.read_csv(r'파일저장 경로\orders.csv')
products_df = pd.read_csv(r'파일저장 경로\products.csv')
aisles_df = pd.read_csv(r'파일저장 경로\aisles.csv')
departments_df = pd.read_csv(r'파일저장 경로\departments.csv')
Step 2 . EDA
- 각 그룹군 그래프로 나타내기
cnt_srs = orders_df.eval_set.value_counts()
plt.figure(figsize=(12,8))
sns.barplot(cnt_srs.index, cnt_srs.values, alpha=0.8, color=color[1])
plt.ylabel('총 갯수', fontsize=12)
plt.xlabel('고객 Type 군', fontsize=12)
plt.title('각 고객군의 수', fontsize=15)
plt.show()
def get_unique_count(x):
return len(np.unique(x))
cnt_srs = orders_df.groupby("eval_set")["user_id"].aggregate(get_unique_count)
cnt_srs
- 각 고객별로 가장 많이 주문한 개수를 그래프로 나타내기
cnt_srs = orders_df.groupby("user_id")["order_number"].aggregate(np.max).reset_index()
cnt_srs = cnt_srs.order_number.value_counts()
plt.figure(figsize=(12,8))
sns.barplot(cnt_srs.index, cnt_srs.values, alpha=0.8, color=color[2])
plt.ylabel('구매 발생 횟수', fontsize=12)
plt.xlabel('Maximum 구매 갯수', fontsize=12)
plt.xticks(rotation='vertical')
plt.show()
- 요일별 구매량 추이 확인
plt.figure(figsize=(20,15))
sns.countplot(x="order_dow", data=orders_df, color=color[0]) # order_dow 는 요일을 의미
plt.xlabel('요일', fontsize=12)
plt.ylabel('구매량', fontsize=12)
plt.xticks([2,3,4,5,6,0,1],['월','화','수','목','금','토','일'])
plt.title("요일별 구매량", fontsize=15)
plt.show()
- 각 시간대별로 구매개수 그래프로 나타내기
orders_df
order_id user_id eval_set order_number order_dow order_hour_of_day days_since_prior_order
0 | 2539329 | 1 | prior | 1 | 2 | 8 | NaN |
1 | 2398795 | 1 | prior | 2 | 3 | 7 | 15.0 |
2 | 473747 | 1 | prior | 3 | 3 | 12 | 21.0 |
3 | 2254736 | 1 | prior | 4 | 4 | 7 | 29.0 |
4 | 431534 | 1 | prior | 5 | 4 | 15 | 28.0 |
... | ... | ... | ... | ... | ... | ... | ... |
3421078 | 2266710 | 206209 | prior | 10 | 5 | 18 | 29.0 |
3421079 | 1854736 | 206209 | prior | 11 | 4 | 10 | 30.0 |
3421080 | 626363 | 206209 | prior | 12 | 1 | 12 | 18.0 |
3421081 | 2977660 | 206209 | prior | 13 | 1 | 12 | 7.0 |
3421082 | 272231 | 206209 | train | 14 | 6 | 14 | 30.0 |
plt.figure(figsize=(12,8))
sns.countplot(x="order_hour_of_day", data=orders_df, color=color[1])
plt.ylabel('구매량', fontsize=12)
plt.xlabel('하루 중 시간', fontsize=12)
plt.title("하루 중 구매량", fontsize=15)
plt.show()
- 요일별/ 시간대별 구매 추이 확인
grouped_df = orders_df.groupby(['order_dow','order_hour_of_day'])['order_number'].aggregate('count').reset_index()
grouped_df = grouped_df.pivot('order_dow','order_hour_of_day','order_number')
plt.figure(figsize = (18,9))
sns.heatmap(grouped_df)
plt.title('요일별/시간별 구매량')
plt.yticks([2,3,4,5,6,0,1],['월','화','수','목','금','토','일'])
plt.show()
- prior 고객군 대상 분석
plt.figure(figsize=(12,8))
sns.countplot(x='days_since_prior_order', data= orders_df, color=color[3])
plt.ylabel('판매량',fontsize=12)
plt.xlabel('prior 주문 일수', fontsize = 12)
plt.xticks(rotation='vertical')
plt.title('prior 구매의 일별 빈도분포')
#판매량이 가장 높은 요일은 30일, 낮은 요일은 25일 이다. 1일~7일까지는 증가추세이고, 8일~29일까지는 감소추세이다.
# prior 고객군의 재주문율
order_products_prior_df.reordered.sum() / order_products_prior_df.shape[0]
0.5896974667922161
# train 고객군의 재주문율
order_products_train_df.reordered.sum() / order_products_train_df.shape[0]
0.5985944127509629
# prior 고객들 중 재주문한 경험이 있을 경우 1, 없을 경우 0 으로 데이터를 정제한다.
grouped_df = order_products_prior_df.groupby('order_id')['reordered'].aggregate('sum').reset_index()
grouped_df['reordered'].ix[grouped_df['reordered'] > 1] = 1
grouped_df.reordered.value_counts() / grouped_df.shape[0]
1 0.879151
0 0.120849
해석 ) prior 고객들 중 재주문한 경험이 있는 경우는 약 88% prior 고객들 중 재주문한 경험이 없는 경우는 약 12%
# train 고객들 중 재주문한 경험이 있을 경우 1, 없을 경우 0 으로 데이터를 정제한다.
grouped_df = order_products_train_df.groupby('order_id')['reordered'].aggregate('sum').reset_index()
grouped_df['reordered'].ix[grouped_df['reordered'] > 1] = 1
grouped_df.reordered.value_counts() / grouped_df.shape[0]
1 0.93444
0 0.06556
해석 ) prior 고객들 중 재주문한 경험이 있는 경우는 약 93% prior 고객들 중 재주문한 경험이 없는 경우는 약 7%
# grouped_df 은 구매자별로 add_to_cart_order 에 담았던 제품의 총 개수
grouped_df = order_products_train_df.groupby('order_id')['add_to_cart_order'].aggregate('max').reset_index()
# cnt_srs 는 add_to_cart_order 에 담긴 각각의 값이 나온 개수
cnt_srs = grouped_df['add_to_cart_order'].value_counts()
plt.figure(figsize=(12,8))
sns.barplot(cnt_srs.index, cnt_srs.values, alpha=0.8)
plt.ylabel('발생 건수', fontsize = 12)
plt.xlabel('add_to_cart_order 에 담긴 제품의 개수', fontsize = 12)
plt.xticks(rotation='vertical')
plt.show()
order_products_prior_df.head()
order_id product_id add_to_cart_order reordered
0 | 2 | 33120 | 1 | 1 |
1 | 2 | 28985 | 2 | 1 |
2 | 2 | 9327 | 3 | 0 |
3 | 2 | 45918 | 4 | 1 |
4 | 2 | 30035 | 5 | 0 |
order_products_prior_df.tail()
order_id product_id add_to_cart_order reordered
32434484 | 3421083 | 39678 | 6 | 1 |
32434485 | 3421083 | 11352 | 7 | 0 |
32434486 | 3421083 | 4600 | 8 | 0 |
32434487 | 3421083 | 24852 | 9 | 1 |
32434488 | 3421083 | 5020 | 10 | 1 |
order_products_prior_df = pd.merge(order_products_prior_df, products_df, on= "product_id" , how="left")
order_products_prior_df = pd.merge(order_products_prior_df, aisles_df, on='aisle_id', how='left')
order_products_prior_df = pd.merge(order_products_prior_df, departments_df, on='department_id', how='left')
order_products_prior_df.head()
order_id product_id add_to_cart_order reordered product_name aisle_id department_id aisle department
0 | 2 | 33120 | 1 | 1 | Organic Egg Whites | 86 | 16 | eggs | dairy eggs |
1 | 2 | 28985 | 2 | 1 | Michigan Organic Kale | 83 | 4 | fresh vegetables | produce |
2 | 2 | 9327 | 3 | 0 | Garlic Powder | 104 | 13 | spices seasonings | pantry |
3 | 2 | 45918 | 4 | 1 | Coconut Butter | 19 | 13 | oils vinegars | pantry |
4 | 2 | 30035 | 5 | 0 | Natural Sweetener | 17 | 13 | baking ingredients | pantry |
- 판매개수 높은 제품 확인
cnt_srs = order_products_prior_df['product_name'].value_counts().sort_values(ascending=False).reset_index().head(20)
cnt_srs.columns = ['제품 이름','판매 갯수']
cnt_srs
# organic 제품이 대다수의 상위권을 차지한 것을 알 수 있다
제품 이름 판매 갯수
0 | Banana | 472565 |
1 | Bag of Organic Bananas | 379450 |
2 | Organic Strawberries | 264683 |
3 | Organic Baby Spinach | 241921 |
4 | Organic Hass Avocado | 213584 |
5 | Organic Avocado | 176815 |
6 | Large Lemon | 152657 |
7 | Strawberries | 142951 |
8 | Limes | 140627 |
9 | Organic Whole Milk | 137905 |
10 | Organic Raspberries | 137057 |
11 | Organic Yellow Onion | 113426 |
12 | Organic Garlic | 109778 |
13 | Organic Zucchini | 104823 |
14 | Organic Blueberries | 100060 |
15 | Cucumber Kirby | 97315 |
16 | Organic Fuji Apple | 89632 |
17 | Organic Lemon | 87746 |
18 | Apple Honeycrisp Organic | 85020 |
19 | Organic Grape Tomatoes | 84255 |
- 제품의 각 상세 카테고리별 판매량
cnt_srs = order_products_prior_df['aisle'].value_counts().head(20)
plt.figure(figsize=(12,8))
sns.barplot(cnt_srs.index, cnt_srs)
plt.xlabel('제품 상세 카테고리' , fontsize= 15)
plt.ylabel('구매량', fontsize= 15)
plt.xticks(fontsize = 15, rotation='vertical')
plt.show()
plt.figure(figsize=(10,10))
temp_series = order_products_prior_df['department'].value_counts()
labels = np.array(temp_series.index)
sizes = np.array((temp_series / temp_series.sum())* 100)
plt.pie(sizes, labels=labels, autopct='%1.1f%%' , startangle= 200)
plt.title('제품 카테고리 분포', fontsize= 15)
plt.show()
# produce(29.2%) 제품군 > dairy eggs(16.7%) > snacks(8.9%) > beverages(8.3%)제품군이 가장 많이 판매됬음을 알 수 있다
- 제품 카테고리 별 재주문 현황
grouped_df = order_products_prior_df.groupby(['department'])['reordered'].aggregate('mean').reset_index()
plt.figure(figsize=(12,8))
sns.pointplot(grouped_df['department'].values,grouped_df['reordered'].values, alpha = 0.8 , color= color[2])
plt.xlabel('제품 카테고리', fontsize = 18)
plt.ylabel('재주문율' , fontsize= 18)
plt.xticks(rotation = 'vertical', fontsize = 15)
plt.yticks(fontsize = 15)
plt.title('제품 카테고리의 재주문율 ')
plt.show()
# dairy eggs 제품군의 재주문율이 가장 높다 personal care 제품군의 재주문율이 가장 낮다.
grouped_df = order_products_prior_df.groupby(['department_id', 'aisle'])['reordered'].aggregate('mean').reset_index()
fig, ax = plt.subplots(figsize=(15,20))
ax.scatter(grouped_df.reordered.values, grouped_df.department_id.values)
for i, txt in enumerate(grouped_df.aisle.values):
ax.annotate(txt, (grouped_df.reordered.values[i],grouped_df.department_id.values[i]), rotation=45 , ha='center',va='center', color='green')
plt.xlabel('재주문율',fontsize = 20)
plt.ylabel('제품 카테고리 id',fontsize = 20)
plt.title('다른 제품 카테고리의 재주문율' , fontsize =20)
plt.show()
- 장바구니에 추가와 재주문율의 상관관계에 대해 알아보기
order_products_prior_df['add_to_cart_order_mod'] = order_products_prior_df['add_to_cart_order'].copy()
order_products_prior_df['add_to_cart_order_mod'].ix[order_products_prior_df['add_to_cart_order_mod'] > 70] = 70
grouped_df = order_products_prior_df.groupby(['add_to_cart_order_mod'])['reordered'].aggregate('mean').reset_index()
plt.figure(figsize=(12,8))
sns.pointplot(grouped_df['add_to_cart_order_mod'].values, grouped_df['reordered'].values, alpha=0.8, color=color[2])
plt.xlabel('장바구니에 추가' , fontsize = 15)
plt.ylabel('재주문율', fontsize= 15)
plt.title('장바구니 추가와 재주문율 관계', fontsize=15)
plt.xticks(rotation= 'vertical')
plt.show()
# 제일 처음 장바구니에 추가된 제품이 나중에 추가된 제품에 비해 다시 주문될 가능성이 높다.
#이를 통해, 소비자들이 자주 사용하는 제품 먼저 주문 후 새로운 제품을 찾는 경향을 가지고 있음을 알 수 있다.
- 요일별 재주문 추이
order_products_train_df = pd.merge(order_products_train_df,orders_df,on='order_id',how='left')
grouped_df = order_products_train_df.groupby(['order_dow'])['reordered'].aggregate('mean').reset_index()
plt.figure(figsize=(12,8))
sns.barplot(grouped_df['order_dow'].values, grouped_df['reordered'].values,alpha=0.8, color = color[3])
plt.xlabel('요일', fontsize = 15)
plt.ylabel('재주문율',fontsize =15)
plt.xticks(rotation='vertical')
plt.ylim(0.5,0.7)
plt.show()
- 일일 시간대별 재주문율 추이
grouped_df= order_products_train_df.groupby('order_hour_of_day')['reordered'].aggregate('mean').reset_index()
plt.figure(figsize=(12,8))
sns.barplot(grouped_df['order_hour_of_day'].values, grouped_df['reordered'].values, alpha=0.8,color=color[4])
plt.xlabel('하루 중 시간', fontsize =15)
plt.ylabel('재주문율', fontsize =15)
plt.title('일별 재주문율', fontsize = 15)
plt.ylim(0.5,0.7)
plt.show()
- 요일별/ 일일 시간대별 재주문율 현황확인
order_products_train_df
order_id product_id add_to_cart_order reordered user_id eval_set order_number order_dow order_hour_of_day days_since_prior_order
0 | 1 | 49302 | 1 | 1 | 112108 | train | 4 | 4 | 10 | 9.0 |
1 | 1 | 11109 | 2 | 1 | 112108 | train | 4 | 4 | 10 | 9.0 |
2 | 1 | 10246 | 3 | 0 | 112108 | train | 4 | 4 | 10 | 9.0 |
3 | 1 | 49683 | 4 | 0 | 112108 | train | 4 | 4 | 10 | 9.0 |
4 | 1 | 43633 | 5 | 1 | 112108 | train | 4 | 4 | 10 | 9.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1384612 | 3421063 | 14233 | 3 | 1 | 169679 | train | 30 | 0 | 10 | 4.0 |
1384613 | 3421063 | 35548 | 4 | 1 | 169679 | train | 30 | 0 | 10 | 4.0 |
1384614 | 3421070 | 35951 | 1 | 1 | 139822 | train | 15 | 6 | 10 | 8.0 |
1384615 | 3421070 | 16953 | 2 | 1 | 139822 | train | 15 | 6 | 10 | 8.0 |
1384616 | 3421070 | 4724 | 3 | 1 | 139822 | train | 15 | 6 | 10 | 8.0 |
grouped_df = order_products_train_df.groupby(['order_dow', 'order_hour_of_day'])['reordered'].aggregate('mean').reset_index()
grouped_df = grouped_df.pivot(values = 'reordered', columns= 'order_hour_of_day',index='order_dow')
plt.figure(figsize=(12,8))
sns.heatmap(grouped_df)
plt.title('요일별 재주문율 vs 일일별 재주문율 ')
plt.xlabel('하루 중 구매시간')
plt.ylabel('요일')
plt.yticks([2,3,4,5,6,0,1],['월','화','수','목','금','토','일'])
plt.show()
# 결과
prior 고객군 insight
- prior 고객군의 최대 구매시간은 토요일 오후 1~3시 와 일요일 10시이다.
train 고객군 insight
- train 고객군의 최대 구매시간은 수요일과 토요일 아침 6~7시간대이다.
- train 고객군은 하루 중 6,7,8시에 재주문율이 가장 높고 9시 ~12시까지 주문율이 감소하는 경향을 보인다.
종합 insight
- 시간별 판매량 : 아침 9시에 판매량이 가장 높고, 새벽 3시에 판매량이 가장 낮다.아침 9시~ 17시까지이 판매량의 70% 를 차지한다.
- 요일별 판매량 : 판매량이 가장 높은 요일은 30일, 낮은 요일은 25일 이다. 1일~7일까지는 증가추세이고, 8일~29일까지는 감소추세이다.
- 제품군에 따른 주문율 :produce(29.2%) 제품군 > dairy eggs(16.7%) > snacks(8.9%) > beverages(8.3%)제품군이 가장 많이 판매됬음을 알 수 있다
- 상세 제품군에 따른 주문율 : organic 제품이 대다수의 판매 상위권을 차지한 것을 알 수 있다
- 상세 제품군에 따른 재주문율 : dairy eggs 제품군의 재주문율이 가장 높다 personal care 제품군의 재주문율이 가장 낮다.
- 장바구니와 관련된 구매성향 : 제일 처음 장바구니에 추가된 제품이 나중에 추가된 제품에 비해 다시 주문될 가능성이 높다. 이를 통해, 소비자들이 자주 사용하는 제품 먼저 주문 후 새로운 제품을 찾는 경향을 가지고 있음을 알 수 있다.
# 필사 참고 URL
https://www.kaggle.com/sudalairajkumar/simple-exploration-notebook-instacart
'Kaggle' 카테고리의 다른 글
[ Kaggle ] 초간단 Kaggle 에서 API로 데이터셋 다운받기 (0) | 2020.03.30 |
---|