EDA프로젝트 : Instacart Market

Instacart Market Data Analysis

첫 EDA 프로젝트로 Instacart Market을 선택했다. 식료품 배달 앱인 Instacart의 이전 주문 정보를 바탕으로 재구매를 예측하는 것이 목표이다. 그럼 데이터를 둘러보자!

1. 데이터 불러오기

1) 기본 라이브러리를 추가한다.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
!pip install squarify # treemap으로 표현하기 위해 squarify 설치
import squarify # pip install squarify

2) colab에서 데이터를 불러오는 방법은 여러가지가 있으나, kaggle을 연동하여 다운로드 하는 방법을 사용했다.

!pip install kaggle --upgrade

3) kaggle 로그인 → Account → API에서 'Create New API Token'을 누르면 json파일이 다운로드 되는데 여기서 확인 가능하다.

import os
os.environ['KAGGLE_USERNAME'] = '본인의 kaggle id'
os.environ['KAGGLE_KEY'] = '본인의 kaggle key'
!kaggle -h # 연동이 잘 되었는지 확인한다.

4) Instacart의 데이터를 다운로드한다. 어떤 프로젝트이든 kaggle에서 프로젝트의 data탭에 가면 아래와 같은 링크가 있다.

!kaggle competitions download -c instacart-market-basket-analysis

5) '.zip'형태로 되어있어서 압축을 풀어준다.

!unzip '*.zip'

2. 데이터 살펴보기

1) 바로 파일명으로 데이터를 불러오면 어떤 데이터는 나오고, 어떤 데이터는 없다고 나온다. 데이터를 불러올 때는 꼭 'pd.read_csv'를 사용한다.

departments = pd.read_csv('departments.csv') # ★이렇게 csv를 불러와야 오류가 없음
departments.head()

2) 각 데이터를 불러와서 확인해보면 아래와 같은 그림으로 나타낼 수 있다. 먼저 제품 정보, 주문 정보로 나뉘어진다. 그리고 주문정보는 다시 재구매 정보와 주문 상세정보로 나뉘어진다.

2-1. Dataset 구분

1) order 테이블의 eval_set 컬럼은 prior, train, test로 구분된다. 각 dataset이 어떻게 나뉘어져있는지 확인한다.

cnt_set = orders.eval_set.value_counts() # order 데이터는 prior, train, test으로 구분되어있음
sns.barplot(cnt_set.index, cnt_set.values)
print(cnt_set)

2) eval_set에서 user_id가 같은 사람끼리 묶어서, 각 dataset 당 user 명 수를 구한다.

def get_unique_count(x):
    return len(np.unique(x))
cnt_srs = orders.groupby("eval_set")["user_id"].aggregate(get_unique_count)
cnt_srs

2-2. 주문 정보 분석(orders data) 및 시각화

1) 주문량에 따른 인원수를 구해본다.

# 주문량별로 몇명이 분포하는지 확인하기 위해 user id별로 묶음
cnt_set = orders.groupby('user_id').order_number.aggregate(max).reset_index() 
# 주문량별로 카운트
cnt_set = cnt_set.order_number.value_counts() 
plt.figure(figsize=(12,8))
sns.barplot(cnt_set.index,cnt_set.values)
plt.ylabel('Number of Occurrences', fontsize=12)
plt.xlabel('Maximum order number', fontsize=12)
plt.xticks(rotation='vertical')
plt.show()

user당 재구매 횟수는 4회~100회까지 다양하다. 특이하게 100회 구매한 사람이 많은데, 이건 100회 이상을 전부 100으로 수정한 듯 하다.

2) 요일별 구매를 확인한다. 'order_dow'컬럼을 이용한다.

sns.countplot(data = orders, x='order_dow')
plt.xlabel('Day of week')

0: 토요일 ~ 6: 금요일 이라고 한다. 주말인 토요일, 일요일에 구매를 더 많이 한다.

3) 시간대별 구매를 확인한다.

sns.countplot(data = orders, x='order_hour_of_day')
plt.xlabel('Hour of day')

4) 요일, 시간대 별 구매를 확인한다.

# 요일, 시간별로 묶는다.
grouped = orders.groupby(['order_dow', 'order_hour_of_day']).order_number.aggregate('count')
# povot된 index를 colom으로 사용하기 위해 index를 빼내온다.
grouped = grouped.reset_index()
# 요일을 row로, 시간을 column으로 나타내기 위해 povit사용
grouped = grouped.pivot('order_dow', 'order_hour_of_day', 'order_number')
grouped

아래와 같이 요일을 index로, 시간을 column으로 하는 table을 얻을 수 있다.

이걸 heatmap 형태로 시각화 한다. 주말 낮시간대에 구매가 가장 활발 한 것을 볼 수 있다

sns.heatmap(grouped, center = 30000) # 중간값을 기준으로 파란색, 빨간색으로 표현. 

5) 재구매 기간을 확인한다. 크게보면 0 ~ 7, 30일 째에 재구매가 잘 이루어진다. 그리고 작게는 14, 21, 28일에 한번씩 튀는 현상도 보인다.

sns.countplot(data = orders, x='days_since_prior_order')

2-3. 재구매 비율

1) 재구매 비율를 확인한다. 평균적으로 59%정도가 재구매이다.

  • prior_set 재구매 비율
order_products.reordered.sum() / order_products.shape[00]
> 0.5896974667922161
  • train_set 재구매 비율
order_products_train.reordered.sum() / order_products_train.shape[0]
> 0.5985944127509629

2) 재구매가 되지 않는 제품의 비율을 확인한다. prior_set에서는 12%, train_set에서는 6%이다.

  • prior_set 재구매가 되지 않는 제품 비율
grouped = order_products.groupby('order_id')['reordered'].aggregate('sum').reset_index()
reorder_yes = len(grouped[grouped.reordered >= 1].index)
reorder_no = len(grouped[grouped.reordered == 0].index) # null값 들어간거도 있어서 sum으로 하면 비율이 다르게 나옴
reorder_sum = len(grouped[grouped.reordered >= 0].index)
print('re-ordered =', reorder_yes / reorder_sum)
print('no-re-order =', reorder_no / reorder_sum)
> re-ordered = 0.8791514068669565
> no-re-order = 0.12084859313304347
  • train_set 재구매가 되지 않는 제품 비율
grouped = order_products_train.groupby('order_id')['reordered'].aggregate('sum').reset_index()
reorder_yes = len(grouped[grouped.reordered >= 1].index)
reorder_no = len(grouped[grouped.reordered == 0].index)
reorder_sum = len(grouped[grouped.reordered >= 0].index)
print('re-ordered =', reorder_yes / reorder_sum)
print('no-re-order =', reorder_no / reorder_sum)
> re-ordered = 0.9344404728334185
> no-re-order = 0.06555952716658156

3. 이전 구매 데이터 분석(prior_data)

3-1. merge

1) 제품정보 확인을 위해 'products', 'aisles', 'departments' 3개 데이터를 'order_product'기준으로 결합

order_product_merge = pd.merge(order_products, products, on='product_id', how='left')
order_product_merge = pd.merge(order_product_merge, aisles, on='aisle_id', how='left')
order_product_merge = pd.merge(order_product_merge, departments, on='department_id', how='left')
order_product_merge

2) 제품별 구매 횟수

cnt_set = order_product_merge.product_name.value_counts().reset_index().head(20)
cnt_set.columns = ['product_name', 'frequency_count']
cnt_set.head()

대부분 과일, Organic 제품이다.

3) aisle 별 구매 횟수

cnt_set_aisle_20 = order_product_merge.aisle.value_counts().head(20)
plt.figure(figsize=(12, 8))
sns.barplot(cnt_set_aisle_20.index, cnt_set_aisle_20.values, alpha=0.8, color=color[5])
plt.ylabel('Number of Occurrences', fontsize=12)
plt.xlabel('Aisle', fontsize=12)
plt.xticks(rotation='vertical')
plt.show()

3) departments 별 구매 비율

plt.figure(figsize=(8, 8))
temp_series = order_product_merge.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('Departments distribution', fontsize=15)
plt.show()

4) 재구매 횟수가 가장 많은 제품

  • 제품별
for_treemap_product_20 =  order_product_merge.groupby('product_name').reordered.aggregate('sum').reset_index()
for_treemap_product_20 = for_treemap_product_20.sort_values('reordered', ascending=0).head(20)
fig, ax = plt.subplots(1, figsize = (8, 8))
squarify.plot(label=for_treemap_product_20['product_name'], sizes=for_treemap_product_20['reordered'])

'Banana'가 큰 비율을 차지한다.

  • department 별
for_treemap_department =  order_product_merge.groupby('department').reordered.aggregate('sum').reset_index()
fig, ax = plt.subplots(1, figsize = (8, 8))
squarify.plot(label=for_treemap_department['department'], sizes=for_treemap_department['reordered'], alpha=0.8)
plt.axis('off')
plt.show()

'produce, dairy eggs' 제품이 큰 비율을 차지하는 것을 볼 수 있다.

  • 재구매 상위 10개 항목
for_treemap_fin =  order_product_merge.groupby(['department', 'aisle']).aggregate('sum').reordered.reset_index(drop=False)
for_treemap_fin.sort_values('reordered', ascending=0).head(10)

4. 학습 데이터 분석(train_data)

4-1. merge

1) 'order_product_train'기준으로 'order' 데이터를 결합

order_product_train_merge = pd.merge(order_products_train, orders, on='order_id', how='left')
# 요일별 재구매 비율
order_product_train_merge_week = order_product_train_merge.groupby(['order_dow']).reordered.aggregate('mean').reset_index()
# 시간별 재구매 비율
order_product_train_merge_hour = order_product_train_merge.groupby(['order_hour_of_day']).reordered.aggregate('mean').reset_index()
  • 요일별 구매 비율
sns.barplot(data = order_product_train_merge_week, x='order_dow', y = 'reordered')
plt.xlabel('Day of week')
plt.ylabel('Reorder ratio')
plt.ylim(0.55, 0.66) # 그래프의 y축 범위를 설정해준다.
plt.show()

  • 시간별 구매 비율
sns.barplot(data = order_product_train_merge_hour, x='order_hour_of_day', y = 'reordered')
plt.xlabel('Hour of day')
plt.ylabel('Reorder ratio')
plt.ylim(0.55, 0.66)
plt.show()

  • 요일별 시간별 재구매 비율
# 소수점 2째자리까지만 표시
pd.options.display.float_format = '{:.2f}'.format
# 요일, 시간별로 groupby로 묶는다
order_product_train_merge_map = order_product_train_merge.groupby(['order_dow', 'order_hour_of_day']).reordered.aggregate('mean')
order_product_train_merge_map = order_product_train_merge_map.reset_index()
order_product_train_merge_map = order_product_train_merge_map.pivot('order_dow', 'order_hour_of_day', 'reordered')
order_product_train_merge_map

주말 아침시간, 수요일 아침시간에 재구매 비율이 높은 것을 알 수 있다.

5. 결론

이렇게 Instacart 데이터를 분석해보았다. 재구매가 잘 발생하는 특정 환경을 알아보았으며, 이러한 데이터는 광고에 잘 활용될 것 같다. 또한 재구매율이 높은 제품의 경우는 대량판매하거나, 재구매율이 낮은 제품의 경우 큰 할인율을 적용하여 매출을 향상시킬 수 있을 것 같다.

(본 과제는 아래의 선행 데이터 분석 자료를 참고하였다.)
1. Simple Exploration Notebook - Instacart
https://www.kaggle.com/sudalairajkumar/simple-exploration-notebook-instacart/comments
2. Exploratory Analysis - Instacart
https://www.kaggle.com/philippsp/exploratory-analysis-instacart

좋은 웹페이지 즐겨찾기