Instacart Market Basket Analysis

Instacart Market Basket Analysis

kaggle賽題鏈接

數據理解

比賽使用的數據僅包含交易數據,不包含瀏覽數據。主要由以下幾張表構成:

  1. 訂單表 orders(訂單ID,用戶ID,所屬數據集,該用戶的訂單序號,訂單下單在星期幾,訂單下單所在小時,距離上一次下單過去的天數):數據粒度爲一個訂單事實。其中,所屬數據集包含三類:a) 先驗集:所有用戶在歷史一段時間內產生的所有訂單;b) 訓練集:從所有用戶中抽出一部分訓練用戶,在考察週期內產生的所有訂單;c) 測試集:除去訓練用戶外剩下的用戶,在考察週期內產生的所有訂單。先驗集中,每個用戶可能包含多個訂單。而對於訓練集和測試集,兩者的用戶無交集,且每個用戶在各自集合內也只會有一個訂單。

  2. 商品表 products(商品ID,商品名稱,通道ID,分類ID):數據粒度爲一件商品。

  3. 通道表 aisles(通道ID,通道名稱):數據粒度爲一個通道。這裏的通道,就是超市裏的通道/走道,每一個通道兩側的商品,通常是一個類別的,而走道上方,往往會有一個標識牌。

  4. 分類表 departments(分類ID,分類名稱):數據粒度爲一個分類。是比通道更大的分類概念,但二者相互沒有確定的包含關係。

  5. 先驗集訂單商品表 order_products_prior(訂單ID,商品ID,加入購物車的次序,是否復購):注意先驗集包含所有的用戶,這裏的數據粒度是歷史一段時期內,所有用戶購買的所有商品記錄。

  6. 訓練集訂單商品表 order_products_train(訂單ID,商品ID,加入購物車次序,是否復購):這裏是訓練集用戶,在考察期內,購買的所有商品記錄。上面提過,這個數據集裏的每個用戶,只會有一個訂單,其中包含若干個商品,可能包含也可能不包含復購的商品。

    如果不使用NLP的方法對名稱類字段進行處理的話,商品名稱、通道名稱、分類名稱這幾個字段是沒有用的。在實際項目中,也沒有進行相關處理,所以後面這幾個字段將略過不談。

    最終產出的數據,是訂單表的測試集中,每個訂單所包含的復購商品,也即僅包含復購的測試集訂單商品表。由於上面提到了,訓練集和測試集實際上是按照用戶劃分的,所以最終提交的數據,也是測試用戶在考察期間內,復購的所有商品。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YaJd25yG-1593220408221)(/home/gavin/Machine/MachineProject/顧客行爲預測/數據分析報告/數據分析表.dio (1)].png)

數據加載

prducts_df = pd.read_csv("./data/products.csv")
aisles_df = pd.read_csv("data/aisles.csv")
departments = pd.read_csv("data/departments.csv")
order_products_prior_df = pd.read_csv('data/order_products__prior.csv')
order_products_train_df = pd.read_csv("data/order_products__train.csv")
orders_df = pd.read_csv("data/orders.csv")

統計不同加購訂單順序下的復購率情況

order_products_prior_df["add_to_cart_order_mod"] = order_products_prior_df.add_to_cart_order

# 設置加購件數到達70件以上,則表示爲70件
order_products_prior_df.add_to_cart_order_mod[order_products_prior_df.add_to_cart_order_mod>70]=70

### 對加購順序進行groupy並,計算復購率
groupby_df = order_products_prior_df.groupby(by="add_to_cart_order_mod")["reordered"]
groupby_df = groupby_df.aggregate("mean")
# 可視化
plt.figure(figsize=(12, 6))
groupby_df.plot(c="r", linestyle="dashdot")
plt.ylabel("reordered ratio", fontsize=11)
plt.xlabel("add to cart order", fontsize=11)
plt.title("The recorder ratio of in different order numbers")
plt.grid()
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nK9lOhIm-1593220408223)(output_12_0.png)]

結論:首先放入加購的商品,再一次購買的可能較大(復購率高),越是後面加購的商品,其再一次購買的可能較少。

用戶不同大小訂單數量分佈趨勢

# 在訂單表中單個用戶擁有不止一個訂單
orders_df.head()
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
groupby_df = orders_df.groupby(by="user_id")["order_number"].aggregate(np.max)

# 統計不同訂單次數下的購買次數
cnt_srs = cnt_srs.order_number.value_counts()

plt.figure(figsize=(18, 6))
sns.barplot(cnt_srs.index, cnt_srs.values
            , color='red'
            , alpha=0.6
           )

plt.xticks(rotation="90")
plt.ylabel("counts", fontsize=12)
plt.xlabel("order numbers", fontsize=12)
plt.title("The counts of different order numbers", fontsize=14)
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-j4H1HDTj-1593220408226)(output_19_0.png)]

結論:大多數用戶趨向較少的訂單,集中處於區間[4, 8]

分析每一筆訂單購買商品數據量的分佈情況

# 此張表中每一個用戶只有一個訂單,但訂單內可以有很多種商品
order_products_train_df.head()

# 統計一個訂單中的商品數量
group_df = order_products_train_df.groupby("order_id")["add_to_cart_order"].aggregate("max").reset_index()
cnt_srs = group_df.add_to_cart_order.value_counts()

plt.figure(figsize=(20, 10))
sns.barplot(cnt_srs.index, cnt_srs.values, color="green", alpha=0.5)
plt.xlabel("Number of products in given order", fontsize=12)
plt.ylabel("Frequency", fontsize= 12)
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YNNOrSP6-1593220408230)(output_25_0.png)]

結論:從圖中可以看出大多數用戶的訂單內的商品都集中在區間[4, 7], 且集中以一個訂單5個商品居多.

統計用戶在不同時間點(一週內)的購物習慣

plt.figure(figsize=(12, 6))
sns.countplot(x="order_dow", data=orders_df)
plt.xlabel("Day of week")
plt.xticks([i for i in range(7)], ["Sat.", "Sun.", "Mons", "Tues.", "wed.", "Thur.", "Fri."])
plt.title("The frequency in differen day of week")
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Or9dvt3N-1593220408235)(output_29_0.png)]

結論:用戶一般習慣集中在週末進行購物,而在週三出現購物的低谷。

研究用戶在不同時間點(一天內)的購物習慣

plt.figure(figsize=(12, 6))
sns.countplot(x="order_hour_of_day", data=orders_df, color="blue", alpha=0.6)
plt.xlabel("hour of day")
plt.title("The frequency of order in differen hour of day")
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IzSG1uz5-1593220408237)(output_32_0.png)]

結論:大多數用戶偏向與在中午和下午進行購物,也即主要是在白天進行購物

統計用戶相隔多長時間加購訂單的情況

plt.figure(figsize=(18, 6))
sns.countplot(x="days_since_prior_order", data=orders_df, color="red", alpha=0.5)
plt.ylabel("Count", fontsize=12)
plt.xlabel("day", fontsize=12)
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vf4mbT8m-1593220408240)(output_36_0.png)]

結論:大多數用戶在上一次訂單之後會在一週之後明顯的增加浮動,而在一個月以後出現一個訂單回購的小高峯.

不同商品的購買情況

# 商品表
prducts_df.head()
product_id product_name aisle_id department_id
0 1 Chocolate Sandwich Cookies 61 19
1 2 All-Seasons Salt 104 13
2 3 Robust Golden Unsweetened Oolong Tea 94 7
3 4 Smart Ones Classic Favorites Mini Rigatoni Wit... 38 1
4 5 Green Chile Anytime Sauce 5 13
# 通道表
aisles_df.head()
aisle_id aisle
0 1 prepared soups salads
1 2 specialty cheeses
2 3 energy granola bars
3 4 instant foods
4 5 marinades meat preparation
# 分類表
departments.head()
department_id department
0 1 frozen
1 2 other
2 3 bakery
3 4 produce
4 5 alcohol
# 訂單商品表
order_products_prior_df.head()
order_id product_id add_to_cart_order reordered add_to_cart_order_mod
0 2 33120 1 1 1
1 2 28985 2 1 2
2 2 9327 3 0 3
3 2 45918 4 1 4
4 2 30035 5 0 5
order_products_prior_df = pd.merge(order_products_prior_df
                                   , prducts_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
                                   , on="department_id"
                                   , how = "left"
                                  )

查看不同的商品對於的銷售量

cnt_srs = order_products_prior_df.groupby(by="product_name").count()["add_to_cart_order_mod"].reset_index()
cnt_srs.sort_values(by="add_to_cart_order_mod", ascending=False).head(20)
product_name add_to_cart_order_mod
3676 Banana 472565
3471 Bag of Organic Bananas 379450
31920 Organic Strawberries 264683
28840 Organic Baby Spinach 241921
30297 Organic Hass Avocado 213584
28804 Organic Avocado 176815
22413 Large Lemon 152657
42904 Strawberries 142951
23420 Limes 140627
32478 Organic Whole Milk 137905
31363 Organic Raspberries 137057
32565 Organic Yellow Onion 113426
30000 Organic Garlic 109778
32605 Organic Zucchini 104823
29008 Organic Blueberries 100060
11630 Cucumber Kirby 97315
29980 Organic Fuji Apple 89632
30577 Organic Lemon 87746
2628 Apple Honeycrisp Organic 85020
30139 Organic Grape Tomatoes 84255
# 繪製不同通道下的品類的情況
cnt_srs = order_products_prior_df.aisle.value_counts()

plt.figure(figsize=(12, 6))
sns.barplot(cnt_srs.head(20).index, cnt_srs.head(20).values
            , alpha=0.5
            , color="blue"
           )

plt.xticks(rotation="90")
plt.ylabel("Count")
plt.xlabel("Aisle name")
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bjp8hpkB-1593220408242)(output_52_0.png)]

結論:從圖中可以看出購買新鮮蔬菜和水果的訂單量較大

繪製不同產品類別之間的所佔分數

temp = order_products_prior_df.department.value_counts()
temp.head()
produce       9479291
dairy eggs    5414016
snacks        2887550
beverages     2690129
frozen        2236432
Name: department, dtype: int64
plt.figure(figsize=(8, 8))
plt.pie(temp
        , labels=temp.index
        , autopct="%1.1f%%"
        , startangle=200
       )
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KzS86eFr-1593220408244)(output_56_0.png)]

結論:通過觀察可以看出產品和奶製品和雞蛋類的所佔比重較大,可以看出用戶偏向與這類商品。

查看不同的大類別下的復購率情況

group_df = order_products_prior_df.groupby("department")["reordered"].mean()
group_df = group_df.reset_index()
group_df.head()
department reordered
0 alcohol 0.569924
1 babies 0.578971
2 bakery 0.628141
3 beverages 0.653460
4 breakfast 0.560922
plt.figure(figsize=(12, 5))
sns.barplot(group_df.department
            , group_df.reordered
            , alpha=0.8
            , color="blue")

plt.ylabel("reordered ratio", fontsize=12)
plt.title("The reordered ratio in differfent departments", fontsize=13)
plt.xlabel("department", fontsize=12)
plt.xticks(rotation=90)
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1FJBp9HX-1593220408245)(output_62_0.png)]

不同部門下不同通道的復購率情況

group_df = order_products_prior_df.groupby(["department_id", "aisle"])["reordered"].mean()
group_df = group_df.reset_index()
group_df
department_id aisle reordered
0 1 frozen appetizers sides 0.525557
1 1 frozen breads doughs 0.539992
2 1 frozen breakfast 0.626221
3 1 frozen dessert 0.420777
4 1 frozen juice 0.450855
... ... ... ...
129 20 lunch meat 0.606517
130 20 prepared meals 0.619759
131 20 prepared soups salads 0.596597
132 20 tofu meat alternatives 0.607775
133 21 missing 0.395849

134 rows × 3 columns

fig, ax = plt.subplots(figsize=(14, 14))
ax.scatter(group_df.reordered, group_df.department_id, alpha=0.8, color="red")
plt.plot([0.6]*23, np.arange(0, 23), color="red", linestyle="--")

for i, txt in enumerate(group_df.aisle.values):
    ax.annotate(txt, (group_df.reordered[i], group_df.department_id[i])
                , rotation=45
                , color="green"
               )
    plt.xlabel("reordered ratio", fontsize=14)

plt.ylabel("department", fontsize=14)
plt.title("Reorder ration of different aisles", fontsize=20)
plt.yticks(np.arange(1, 22), departments.department)
plt.ylim([0, 22])
plt.xlim([0, 0.9])
plt.grid()
plt.show()

png

結論:通過設置最低的復購率準線,可以查看到每一個部門下的下分類別的復購率情況

用戶在不同時間(周內)的復購率情況

order_products_prior_df = pd.merge(order_products_prior_df, orders_df, on="order_id", how="left")

group_df = order_products_prior_df.groupby(by="order_dow")["reordered"].mean()
sns.barplot(group_df.index, group_df.values, color="b", alpha=0.5)
plt.xticks([i for i in range(7)], ["Sat.", "Sun.", "Mons", "Tues.", "wed.", "Thur.", "Fri."])
plt.ylabel("reordered ratio")
plt.xlabel("week")
plt.title("The reordered ratio of different week")
plt.ylim([0.5, 0.7])
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KoDJdAu2-1593220408246)(output_70_0.png)]

用戶在不同時間(周內)的復購率情況

group_df = order_products_prior_df.groupby(by="order_hour_of_day")["reordered"].mean()
plt.figure(figsize=(12, 6))
sns.barplot(group_df.index, group_df.values, color="b", alpha=0.8)
plt.ylabel("reordered ratio")
plt.xlabel("hour")
plt.title("The reordered ratio of different hour")
plt.ylim([0.5, 0.7])
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vqUQcMzW-1593220408248)(output_72_0.png)]

group_df= order_products_prior_df.groupby(["order_dow", "order_hour_of_day"])["reordered"].mean().reset_index()
group_df = group_df.pivot("order_dow", "order_hour_of_day", "reordered")
plt.figure(figsize=(12, 6))
sns.heatmap(group_df)
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AEycxavg-1593220408249)(output_75_0.png)]

參考

Kaggle Instacart復購預測競賽回顧

Kaggle案例:基於Python分析Instacart用戶行爲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章