Help us understand the problem. What is going on with this article?

kaggleのkernels学習ノート~Exploratory Analysis - Instacart~

More than 1 year has passed since last update.

題名の通りkaggleのkernelsを和訳したものです。自分の勉強の備忘録をまとめていきます。そして、データ分析に携わる誰かのお役に立てれば幸いです。和訳とか得意じゃないので間違っていたらごめんなさい。
今回はPhilipp SpachtholzさんのExploratory Analysis - Instacartを和訳していきます。

Exploratory Analysis - Instacart

Instacart Market Basket Competitionでの皆様の幸運をお祈りします!
これはコンペティションデータセットの最初の探索的データ分析です。Instacartにはレコメンド機能があり、ユーザーに再度購入する可能性がある商品を提案します。ここでの目的は、どの商品が次に注文されるかを予測することです。
データセットは、6つのcsvファイルに分散された約340万件の食料品の注文に関するデータで構成されています。

データを読み込む

R
library(data.table)
library(dplyr)
library(ggplot2)
library(knitr)
library(stringr)
library(DT)

orders <- fread('../input/orders.csv')
products <- fread('../input/products.csv')
order_products <- fread('../input/order_products__train.csv')
order_products_prior <- fread('../input/order_products__prior.csv')
aisles <- fread('../input/aisles.csv')
departments <- fread('../input/departments.csv')

ファイルの内容を見てみましょう。

データを見る

このファイルには、データセット内のすべての注文のリストが含まれます。注文ごとに1行、たとえば、ユーザ1には11個の注文があり、そのうちの1個はtrain set内にあり、そのうち10個は事前注文であることがわかります。orders.csvは、注文された商品については教えてくれません。これはorder_products.csvに含まれています。

R
kable(head(orders,12))
order_id user_id eval_set order_number order_dow order_hour_of_day days_since_prior_order
2539329 1 prior 1 2 8 NA
2398795 1 prior 2 3 7 15
473747 1 prior 3 3 12 21
2254736 1 prior 4 4 7 29
431534 1 prior 5 4 15 28
3367565 1 prior 6 2 7 19
550135 1 prior 7 1 9 20
3108588 1 prior 8 1 14 14
2295261 1 prior 9 1 16 0
2550362 1 prior 10 4 8 30
1187899 1 train 11 4 8 14
2168274 2 prior 1 2 11 NA
R
glimpse(orders)
## Observations: 3,421,083
## Variables: 7
## $ order_id               <int> 2539329, 2398795, 473747, 2254736, 4315...
## $ user_id                <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, ...
## $ eval_set               <chr> "prior", "prior", "prior", "prior", "pr...
## $ order_number           <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2...
## $ order_dow              <int> 2, 3, 3, 4, 4, 2, 1, 1, 1, 4, 4, 2, 5, ...
## $ order_hour_of_day      <int> 8, 7, 12, 7, 15, 7, 9, 14, 16, 8, 8, 11...
## $ days_since_prior_order <dbl> NA, 15, 21, 29, 28, 19, 20, 14, 0, 30, ...

変数を再コーディング

いくつかの変数のデータ型を変更します。文字型をファクタ型に変換する必要があります。

R
orders <- orders %>% mutate(order_hour_of_day = as.numeric(order_hour_of_day), eval_set = as.factor(eval_set))
products <- products %>% mutate(product_name = as.factor(product_name))
aisles <- aisles %>% mutate(aisle = as.factor(aisle))
departments <- departments %>% mutate(department = as.factor(department))

いつ注文するのでしょうか?

ユーザーが食料品をオンラインで購入するときの時間を見てみましょう。

時間帯

注文量には時間帯の影響があります。ほとんどの注文は8.00-18.00の間です。

R
orders %>% 
  ggplot(aes(x=order_hour_of_day)) + 
  geom_histogram(stat="count",fill="red")

unnamed-chunk-10-1.png

曜日

曜日で見ると明確な効果があります。ほとんどの注文は0日目と1日目です。残念ながら、どちらの日がどの値を表しているかについての情報はありませんが、週末であると仮定しておきます。

R
orders %>% 
  ggplot(aes(x=order_dow)) + 
  geom_histogram(stat="count",fill="red")

unnamed-chunk-11-1.png

リピートサイクルは?

だいたい1週間でリピートしていることがわかります。

R
orders %>% 
  ggplot(aes(x=days_since_prior_order)) + 
  geom_histogram(stat="count",fill="red")

unnamed-chunk-12-1.png

先行注文はいくつあるのか?

常に少なくとも3つの先行注文があることがわかります。

R
orders %>% 
 filter(eval_set=="prior") %>%
 count(order_number) %>% 
 ggplot(aes(order_number,n)) + 
 geom_line(color="red", size=1) +
 geom_point(size=2, color="red")

unnamed-chunk-13-1.png

商品をいくつ購入するか?

注文に含まれる商品の数を見てみましょう。だいたい5個程度を注文することがわかります。これらの分布は、訓練セットと先行注文セットとの間で比較可能です。

訓練セット
order_products %>% 
  group_by(order_id) %>% 
  summarize(n_items = last(add_to_cart_order)) %>%
  ggplot(aes(x=n_items))+
  geom_histogram(stat="count",fill="red") + 
  geom_rug()+
  coord_cartesian(xlim=c(0,80))

unnamed-chunk-14-1.png

先行注文セット
order_products_prior %>% 
  group_by(order_id) %>% 
  summarize(n_items = last(add_to_cart_order)) %>%
  ggplot(aes(x=n_items))+
  geom_histogram(stat="count",fill="red") + 
  geom_rug() + 
  coord_cartesian(xlim=c(0,80))

unnamed-chunk-15-1.png

ベストセラーは何か?

最も頻繁に販売される商品を見てみましょう(トップ10)。 明らかにバナナといえます。

R
tmp <- order_products %>% 
  group_by(product_id) %>% 
  summarize(count = n()) %>% 
  top_n(10, wt = count) %>%
  left_join(select(products,product_id,product_name),by="product_id") %>%
  arrange(desc(count)) 
kable(tmp)
product_id count product_name
24852 18726 Banana
13176 15480 Bag of Organic Bananas
21137 10894 Organic Strawberries
21903 9784 Organic Baby Spinach
47626 8135 Large Lemon
47766 7409 Organic Avocado
47209 7293 Organic Hass Avocado
16797 6494 Strawberries
26209 6033 Limes
27966 5546 Organic Raspberries
R
tmp %>% 
  ggplot(aes(x=reorder(product_name,-count), y=count))+
  geom_bar(stat="identity",fill="red")+
  theme(axis.text.x=element_text(angle=90, hjust=1),axis.title.x = element_blank())

unnamed-chunk-16-1.png

どの程度同じ商品を注文しているのか?

59%の商品が再注文されているようです。

R
tmp <- order_products %>% 
  group_by(reordered) %>% 
  summarize(count = n()) %>% 
  mutate(reordered = as.factor(reordered)) %>%
  mutate(proportion = count/sum(count))
kable(tmp)
reordered count proportion
0 555793 0.4014056
1 828824 0.5985944
R
tmp %>% 
  ggplot(aes(x=reordered,y=count,fill=reordered))+
  geom_bar(stat="identity")

unnamed-chunk-17-1.png

最も再注文される商品

これは本当に興味深いものです。これらの10商品は再注文の可能性が最も高いです。

R
tmp <-order_products %>% 
  group_by(product_id) %>% 
  summarize(proportion_reordered = mean(reordered), n=n()) %>% 
  filter(n>40) %>% 
  top_n(10,wt=proportion_reordered) %>% 
  arrange(desc(proportion_reordered)) %>% 
  left_join(products,by="product_id")

kable(tmp)
product_id proportion_reordered n product_name aisle_id department_id
1729 0.934 92 2% Lactose Free Milk 84 16
20940 0.913 368 Organic Low Fat Milk 84 16
12193 0.898 59 100% Florida Orange Juice 98 7
21038 0.888 81 Organic Spelt Tortillas 128 3
31764 0.888 45 Original Sparkling Seltzer Water Cans 115 7
24852 0.884 18726 Banana 24 4
117 0.883 120 Petit Suisse Fruit 2 16
39180 0.881 483 Organic Lowfat 1% Milk 84 16
12384 0.881 269 Organic Lactose Free 1% Lowfat Milk 91 16
24024 0.878 461 1% Lowfat Milk 84 16
R
tmp %>% 
  ggplot(aes(x=reorder(product_name,-proportion_reordered), y=proportion_reordered))+
  geom_bar(stat="identity",fill="red")+
  theme(axis.text.x=element_text(angle=90, hjust=1),axis.title.x = element_blank())+coord_cartesian(ylim=c(0.85,0.95))

unnamed-chunk-18-1.png

どの商品を最初にカートに入れるのか?

ユーザーは多目的タオルをかなり確信が高く思えます。購入した場合は、66%の確率でカートに入れます。

R
tmp <- order_products %>% 
  group_by(product_id, add_to_cart_order) %>% 
  summarize(count = n()) %>% mutate(pct=count/sum(count)) %>% 
  filter(add_to_cart_order == 1, count>10) %>% 
  arrange(desc(pct)) %>% 
  left_join(products,by="product_id") %>% 
  select(product_name, pct, count) %>% 
  ungroup() %>% 
  top_n(10, wt=pct)

kable(tmp)
product_id product_name pct count
45004 White Multifold Towels 0.6610169 39
11885 Sparkling Water, Bottles 0.5942029 41
13128 Purified Alkalkine Water with Minerals pH10 0.5714286 12
4100 Organic Dark Roast 0.5600000 14
1729 2% Lactose Free Milk 0.5217391 48
6729 Cookie Tray 0.4861111 35
9285 Boneless Pork Shoulder Butt 0.4814815 13
6848 Party Tumblers 0.4615385 12
12640 Sport Bottle with Flip Cap Natural Spring Water 0.4615385 12
26405 XL Pick-A-Size Paper Towel Rolls 0.4476190 47
R
tmp %>% 
  ggplot(aes(x=reorder(product_name,-pct), y=pct))+
  geom_bar(stat="identity",fill="red")+
  theme(axis.text.x=element_text(angle=90, hjust=1),axis.title.x = element_blank())+coord_cartesian(ylim=c(0.4,0.7))

unnamed-chunk-19-1.png

最後の注文と再注文確率との関連

興味深いです。ユーザーが同じ日に再び注文すると、同じ商品をより頻繁に注文することがわかります。30日が過ぎると、ユーザーは新しいものを順番に試している傾向があります。

R
order_products %>% 
  left_join(orders,by="order_id") %>% 
  group_by(days_since_prior_order) %>%
  summarize(mean_reorder = mean(reordered)) %>%
  ggplot(aes(x=days_since_prior_order,y=mean_reorder))+
  geom_bar(stat="identity",fill="red")

unnamed-chunk-20-1.png

注文数と注文確率との関連性

当然のことながら、注文数の多い製品は並べ替えが容易です。しかし、天井効果があるようです。

R
order_products %>% 
  group_by(product_id) %>% 
  summarize(proportion_reordered = mean(reordered), n=n()) %>%
  ggplot(aes(x=n,y=proportion_reordered))+
  geom_point()+
  geom_smooth(color="red")+
  coord_cartesian(xlim=c(0,2000))

unnamed-chunk-21-1.png

オーガニックと非オーガニックの商品

オーガニックではないオーダーの割合はいくらでしょうか?

R
products <- products %>% 
    mutate(organic=ifelse(str_detect(str_to_lower(products$product_name),'organic'),"organic","not organic"), organic= as.factor(organic))

tmp <- order_products %>% 
  left_join(products, by="product_id") %>% 
  group_by(organic) %>% 
  summarize(count = n()) %>% 
  mutate(proportion = count/sum(count))
kable(tmp)
organic count proportion
not organic 979000 0.7070547
organic 405617 0.2929453
R
tmp %>% 
  ggplot(aes(x=organic,y=count, fill=organic))+
  geom_bar(stat="identity")

unnamed-chunk-22-1.png

再注文されたオーガニックと非オーガニックの商品

ユーザーはどの程度、オーガニックと非オーガニックの商品を再注文するのでしょうか。

R
tmp <- order_products %>% left_join(products,by="product_id") %>% group_by(organic) %>% summarize(mean_reordered = mean(reordered))
kable(tmp)
organic mean_reordered
not organic 0.5784985
organic 0.6470981
R
tmp %>% 
 ggplot(aes(x=organic,fill=organic,y=mean_reordered))+geom_bar(stat="identity")

unnamed-chunk-23-1.png

商品ポートフォリオの可視化

ここでは、instacartsの商品ポートフォリオの構造を視覚化するために{treemap}パッケージを使用します。合計で134セルを含む21のブロックがあります。

R
library(treemap)

tmp <- products %>% group_by(department_id, aisle_id) %>% summarize(n=n())
tmp <- tmp %>% left_join(departments,by="department_id")
tmp <- tmp %>% left_join(aisles,by="aisle_id")

tmp2<-order_products %>% 
  group_by(product_id) %>% 
  summarize(count=n()) %>% 
  left_join(products,by="product_id") %>% 
  ungroup() %>% 
  group_by(department_id,aisle_id) %>% 
  summarize(sumcount = sum(count)) %>% 
  left_join(tmp, by = c("department_id", "aisle_id")) %>% 
  mutate(onesize = 1)

セルはブロックによって、どのように構成されているのか?

R
treemap(tmp2,index=c("department","aisle"),vSize="onesize",vColor="department",palette="Set3",title="",sortID="-sumcount", border.col="#FFFFFF",type="categorical", fontsize.legend = 0,bg.labels = "#FFFFFF")

unnamed-chunk-25-1.png

ブロック/セルには、いくつのユニークな製品がありますか?

ブロックのサイズは、各カテゴリの商品数を表します。

R
treemap(tmp,index=c("department","aisle"),vSize="n",title="",palette="Set3",border.col="#FFFFFF")

unnamed-chunk-26-1.png

ボックス/セルの商品はどれくらいの頻度で販売されてるか?

ボックスのサイズは売上数を表します。

R
treemap(tmp2,index=c("department","aisle"),vSize="sumcount",title="",palette="Set3",border.col="#FFFFFF")

unnamed-chunk-27-1-1.png

ユーザーの習慣を探索

ここでは、同じ商品をいつも再注文する顧客を探します。検索するために、再注文された商品の割合が正確に1であるすべての注文(最初の注文は除く)を調べます。実際、3,487人のユーザーが存在し、常に再注文しているだけであることがわかります。

再注文のみのユーザー

R
tmp <- order_products_prior %>% 
  group_by(order_id) %>% 
  summarize(m = mean(reordered),n=n()) %>% 
  right_join(filter(orders,order_number>2), by="order_id")

tmp2 <- tmp %>% 
  filter(eval_set =="prior") %>% 
  group_by(user_id) %>% 
  summarize(n_equal = sum(m==1,na.rm=T), percent_equal = n_equal/n()) %>% 
  filter(percent_equal == 1) %>% 
  arrange(desc(n_equal))

datatable(tmp2, class="table-condensed", style="bootstrap", options = list(dom = 'tp'))
user_id n_equal percent_equal
1 99753 97 1
2 55331 49 1
3 106510 49 1
4 111365 47 1
5 74656 46 1
6 170174 45 1
7 12025 43 1
8 164779 37 1
9 37075 34 1
10 110225 33 1

strongest habit(優良的な表現?)をもつ顧客

最もクールなユーザーはid#99753であり、再注文された商品のみを含む97の注文をしています。それは私が強い習慣と呼ぶものです。彼または彼女はオーガニックミルクが好きなようです。

R
uniqueorders <- filter(tmp, user_id == 99753)$order_id
tmp <- order_products_prior %>% 
  filter(order_id %in% uniqueorders) %>% 
  left_join(products, by="product_id")

datatable(select(tmp,-aisle_id,-department_id,-organic), style="bootstrap", class="table-condensed", options = list(dom = 'tp'))
order_id product_id add_to_cart_order reordered product_name
1 46614 27845 1 1 Organic Whole Milk
2 46614 38689 2 1 Organic Reduced Fat Milk
3 67223 27845 1 1 Organic Whole Milk
4 67223 38689 2 1 Organic Reduced Fat Milk
5 214506 27845 1 1 Organic Whole Milk
6 214506 38689 2 1 Organic Reduced Fat Milk
7 240832 27845 1 1 Organic Whole Milk
8 240832 38689 2 1 Organic Reduced Fat Milk
9 260804 27845 1 1 Organic Whole Milk
10 260804 38689 2 1 Organic Reduced Fat Milk

訓練データの中でこのユーザーの注文を見てみましょう。"Organic Whole Milk"と"Organic Reduced Fat Milk"を購入すると思います。

R
tmp <- orders %>% filter(user_id==99753, eval_set == "train")
tmp2 <- order_products %>%  
  filter(order_id == tmp$order_id) %>% 
  left_join(products, by="product_id")

datatable(select(tmp2,-aisle_id,-department_id,-organic), style="bootstrap", class="table-condensed", options = list(dom = 't'))
order_id product_id add_to_cart_order reordered product_name
1 3143182 27845 1 1 Organic Whole Milk
2 3143182 38689 2 1 Organic Reduced Fat Milk

ハハハ…100%の確率で予測成功です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away