[PYTHON] Résumé de Kaggle: Analyse du panier de marché Instacart

1.Tout d'abord

Nous mettrons à jour les informations de Kaggle qui a participé dans le passé. Ici, nous reprendrons l'introduction des données de Analyse du panier de marché Instacart et les discussions de premier plan dans le forum. Je présenterai l'approche du gagnant dans un autre article. Puisque le code du notebook est introduit, veuillez changer% matplotlib inline etc. selon le cas.

2. Arrière plan

スクリーンショット 2017-07-20 16.54.52.png

L'équipe de science des données d'Instacart fait beaucoup de développement. Par exemple, créer un modèle prédictif d'un utilisateur qui rachète un article, un nouvel utilisateur ou un article à ajouter ensuite au panier. Plus récemment, Instacart a même rendu publiques des informations détaillées sur les transactions. Dans ce concours, nous concourrons pour l'exactitude du modèle de prédiction utilisant ces données ouvertes. Le contenu de la prévision est "Prédire le prochain produit que l'utilisateur commandera à partir du produit précédemment acheté". De plus, bien que n'étant pas directement lié à la concurrence, Instacart recherche actuellement d'excellents ingénieurs en apprentissage automatique. Si vous êtes intéressé, veuillez le vérifier.

Instacart utilise XGBoost et word2vec pour prédire ce que les utilisateurs achèteront ensuite. -représentations-de-mots-et-phrases-et-leur-composition.pdf), et Annoy. Recommander un produit similaire à celui que vous avez acheté avec "acheter à nouveau"

1-LNpbMMzWBsKqKyNvNH2APA.png

De plus, nous recommandons les résultats prédits par le modèle créé.

1-tf40kqB8rRajbRn6A_0Jcw.png

En utilisant ces données accessibles au public, Instacart offre aux consommateurs la possibilité de découvrir de nouvelles épiceries.

Les caractéristiques de ce temps sont les suivantes.

3. Indice d'évaluation

Cet index d'évaluation utilise le [score F1] général (http://ibisforest.org/index.php?F%E5%80%A4) comme index pour les problèmes de classification binaire. スクリーンショット 2017-07-20 17.23.05.png

4. Présentation des données

Veuillez télécharger les données depuis ce lien.

Il existe 7 types de données cette fois. Jordan Tremoureux visualise l'association de données relationnelles.

instacart_Files.png

AISLES.csv et DEPARTMENTS.csv sont des informations sur les catégories de produits, respectivement, et sont des informations telles que les légumes, la viande et les sucreries. PRODUCTS.csv montre l'association spécifique entre le nom du produit et ces informations de catégorie. ORDER_PRODUCTS_ {PRIOR, TRAIN} .csv sont les principales données d'entraînement. PRIOR correspond aux informations de la commande précédente et TRAIN correspond aux informations de la commande en cours. Ces données incluent un indicateur 0-1 appelé réorganisé, et s'il s'agit de 1, vous achetez le même article. L'explication ici est un peu compliquée, nous allons donc l'examiner en détail dans la prochaine EDA. SAMPLE_SUBMISSION.csv est un fichier de démonstration montrant le format de soumission. Enfin, ORDERS.csv contient des informations de séries temporelles associées à ORDER_PRODUCTS__ {PRIOR, TRAIN} .csv. Même s'il s'agit d'une série chronologique, ce n'est pas un horodatage mais des informations de décalage horaire telles que "jusqu'au prochain achat? Jour".

En ce qui concerne les données dans leur ensemble, plus de 200 000 articles pour un mois d'historique d'achat des utilisateurs sont organisés de manière soignée et organisée. En exprimant le temps comme un décalage horaire, une analyse complexe comme vue dans d'autres compétitions peut être omise.

5. Informations sur l'analyse des données

Deux informations d'analyse

  1. Bloc-notes SRK
  2. Informations d'analyse publiées par Instacart sur le blog Je vais présenter environ.

Bien que cela ne soit pas présenté ici, le résultat de l'analyse de Philipp Spachtholz écrit en R est également merveilleux. Le contenu est presque le même que celui de l'analyse en 1), mais les informations sont organisées dans un treemap pour qu'elles soient faciles à voir, veuillez donc la vérifier si vous êtes intéressé.

unnamed-chunk-26-1.png

5.1. Ordinateur portable SRK

5.1.1. Organisation des données

Tout d'abord, importez la bibliothèque

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  # default='warn'

L'avertissement qui apparaît plusieurs fois est désactivé dans le dernier paramètre d'option. Veuillez changer cette zone comme passe-temps. Vérifions la disposition des données.

from subprocess import check_output
print(check_output(["ls", "../input"]).decode("utf8"))

#aisles.csv
#departments.csv
#order_products__prior.csv
#order_products__train.csv
#orders.csv
#products.csv
#sample_submission.csv

On suppose que les données sont installées dans le dossier d'entrée dans la hiérarchie immédiatement supérieure où le bloc-notes est ouvert. S'il est affiché comme # ~, c'est normal.

Importez ensuite les données.

order_products_train_df = pd.read_csv("../input/order_products__train.csv")
order_products_prior_df = pd.read_csv("../input/order_products__prior.csv")
orders_df = pd.read_csv("../input/orders.csv")
products_df = pd.read_csv("../input/products.csv")
aisles_df = pd.read_csv("../input/aisles.csv")
departments_df = pd.read_csv("../input/departments.csv")

Vérifiez le contenu lu et voyez.

orders_df.head()
スクリーンショット 2017-07-20 18.26.37.png
order_products_prior_df.head()
スクリーンショット 2017-07-20 18.26.43.png
order_products_train_df.head()
スクリーンショット 2017-07-20 18.26.49.png

Il semble que orders_df contienne presque toutes les informations. order_products_prior_df et order_products_train_df ont exactement les mêmes colonnes. Quelle est la différence entre les deux fichiers? Cette fois, nous prédirons le prochain achat à partir de l'historique des achats passés. En d'autres termes, le fichier précédent contient l'historique des achats du train et du test, et order_products_train_df est les données de réponse correctes pour la formation. DBEN l'explique dans un diagramme facile à comprendre.

train_user.png test_user.png

Par exemple, dans orders_df, il y a 10 données user_id = 1 dans eval_set = prior, 1 dans eval_set = train et 0 dans eval_set = test. D'autre part, il y a 5 données de user_id = 4 dans eval_set = prior, 0 dans eval_set = train et 1 dans eval_set = test. Ce "réorganisé" de eval_set = test est la cible à prédire cette fois, et il est estimé si user_id = 4 a racheté l'article acheté précédemment.

Pour confirmation, regardons le nombre de priors, de trains et de tests contenus dans orders_df.

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('Number of Occurrences', fontsize=12)
plt.xlabel('Eval set type', fontsize=12)
plt.title('Count of rows in each dataset', fontsize=15)
plt.xticks(rotation='vertical')
plt.show()

__results___10_0.png

Puisque l'entraînement et le test sont prédits à partir de plusieurs priors, nous pouvons voir qu'il existe une très grande majorité de priors.

5.1.2. Visualisation des commandes, order_products__ {avant, train}

À partir du contenu de 5.1.1., Vous pouvez voir que quelque chose peut être analysé en visualisant avec eval_set et réorganisé.

Tout d'abord, voyons combien d'utilisateurs sont dans chacune des étapes précédentes, entraînées et testées. Regroupez orders_df avec eval_set et comptez les user_ids dans chaque groupe sans duplication.

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

L'agrégat est une méthode qui applique diverses fonctions à un groupe par groupe.

eval_set
prior    206209
test      75000
train    131209
Name: user_id, dtype: int64

Vous pouvez voir qu'il y a au total 206 209 personnes, dont 131 209 dans le train et 75 000 en test. Combien de fois l'utilisateur apparaît-il?

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('Number of Occurrences', fontsize=12)
plt.xlabel('Maximum order number', fontsize=12)
plt.xticks(rotation='vertical')
plt.show()

__results___13_0.png

J'ai acheté le produit au minimum 4 fois et au maximum 100 fois.

Il y a probablement de nombreuses commandes le week-end. Divisons le nombre de commandes par les informations du jour. Les informations du jour sont "Order_dow".

plt.figure(figsize=(12,8))
sns.countplot(x="order_dow", data=orders_df, color=color[0])
plt.ylabel('Count', fontsize=12)
plt.xlabel('Day of week', fontsize=12)
plt.xticks(rotation='vertical')
plt.title("Frequency of order by week day", fontsize=15)
plt.show()

__results___15_0.png

Comme vous pouvez le voir, le jour de la semaine = 0 et 1 semble atteindre samedi et dimanche, respectivement. Il y a une légère différence dans le nombre de commandes en semaine. De même, regardons le nombre de commandes par heure.

plt.figure(figsize=(12,8))
sns.countplot(x="order_hour_of_day", data=orders_df, color=color[1])
plt.ylabel('Count', fontsize=12)
plt.xlabel('Hour of day', fontsize=12)
plt.xticks(rotation='vertical')
plt.title("Frequency of order by hour of day", fontsize=15)
plt.show()

__results___17_0.png

Peut-être parce que nous vérifions les samedis et dimanches, l'heure la plus commandée est la journée (10 h et 15 h). Il y a peu de commandes le matin, et le nombre de commandes diminue à mesure que le temps se fait tard dans la soirée.

La relation entre le nombre de commandes pour la journée et l'heure semble profonde. Visualisons-les avec une carte thermique.

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=(12,6))
sns.heatmap(grouped_df)
plt.title("Frequency of Day of week Vs Hour of day")
plt.show()

__results___19_0.png

pivot se concentre uniquement sur les deux axes du DataFrame et crée un nouveau cadre.

Il y a une nette différence entre les jours de semaine et les jours fériés. En semaine, il n'y a pas beaucoup de différence entre les jours et les commandes sont élevées de 9 h à 16 h. Les jours fériés varient considérablement les samedis et dimanches. Les commandes sont le plus souvent passées l'après-midi le samedi et les commandes se poursuivent jusqu'à tard. Les dimanches ont le plus de commandes le matin.

Ensuite, regardons l'intervalle de temps de la commande.

plt.figure(figsize=(12,8))
sns.countplot(x="days_since_prior_order", data=orders_df, color=color[3])
plt.ylabel('Count', fontsize=12)
plt.xlabel('Days since prior order', fontsize=12)
plt.xticks(rotation='vertical')
plt.title("Frequency distribution by days since prior order", fontsize=15)
plt.show()

__results___21_0.png

Le nombre de jours entre la commande précédente et la commande suivante est indiqué par "jours_since_prior_ordre". Le pic est de 7 jours et 30 jours, et après 7 jours, il y a une périodicité tous les 14 jours, 21 jours, 28 jours et ainsi de suite.

Maintenant que la relation entre le temps et le nombre de commandes est claire, jetons un coup d'œil aux rachats prévisibles dans cette compétition.

print(order_products_prior_df.reordered.sum() / order_products_prior_df.shape[0])
print(order_products_train_df.reordered.sum() / order_products_train_df.shape[0])
0.589697466792
0.598594412751

On peut voir que le taux de rachat à la fois pour le train et le train est d'environ 59%. Près des 40% restants étaient des ordres de non-rachat, il contient donc probablement un ordre (order_id) qui n'inclut pas de rachat.

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
Name: reordered, dtype: float64

12% des commandes n'ont pas été rachetées auparavant.

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
Name: reordered, dtype: float64

Les commandes qui n'ont pas été rachetées dans le train sont de 6%, soit la moitié de la priorité.

Combien commandez-vous en une seule commande? Faisons un histogramme.

grouped_df = order_products_train_df.groupby("order_id")["add_to_cart_order"].aggregate("max").reset_index()
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('Number of Occurrences', fontsize=12)
plt.xlabel('Number of products in the given order', fontsize=12)
plt.xticks(rotation='vertical')
plt.show()

__results___29_0.png

SRK ne compte pas order_id, mais calcule le nombre de commandes à la fois à partir de la valeur maximale de add_to_cart_order. Le plus courant est 5 ordres simultanés, ce qui montre une diminution de la distribution queue droite comme la distribution de Poisson.

5.1.3. Analyse détaillée

Les données sur les produits sont réparties entre les produits, les allées et les départements. Tout d'abord, nous combinerons ces informations.

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()
スクリーンショット 2017-07-21 12.16.03.png

Ces données ont été combinées en utilisant product_id, aisle_id et department_id comme clés.

** Analyse par nom de produit ** Quel est le nom de produit le plus commandé?

cnt_srs = order_products_prior_df['product_name'].value_counts().reset_index().head(20)
cnt_srs.columns = ['product_name', 'frequency_count']
cnt_srs
スクリーンショット 2017-07-21 12.18.15.png

Les bananes sont sur le dessus et après cela, diverses épiceries sont alignées, centrées sur les fruits. De plus, presque tous les produits sont des produits biologiques.

** Analyse par catégorie de produits (allée) ** Quels types de produits sont alignés? Des informations sur le type de produit peuvent être trouvées dans l'allée.

cnt_srs = order_products_prior_df['aisle'].value_counts().head(20)
plt.figure(figsize=(12,8))
sns.barplot(cnt_srs.index, cnt_srs.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()

__results___38_0.png

Les deux plus courants sont les fruits frais et les légumes frais.

** Analyse par département **

Jetons un coup d'œil au département des produits.

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("Departments distribution", fontsize=15)
plt.show()

__results___40_0.png

Produire est le département le plus courant.

** Ratio de rachat par département **

Quels départements sont susceptibles d'être rachetés?

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.ylabel('Reorder ratio', fontsize=12)
plt.xlabel('Department', fontsize=12)
plt.title("Department wise reorder ratio", fontsize=15)
plt.xticks(rotation='vertical')
plt.show()

__results___42_0.png

Les soins personnels sont les moins rachetés et les œufs quotidiens sont les plus rachetés.

** Ratio de rachat par catégorie de produit ** Regardons le département et la catégorie de produit (allée) par ratio de rachat.

grouped_df = order_products_prior_df.groupby(["department_id", "aisle"])["reordered"].aggregate("mean").reset_index()

fig, ax = plt.subplots(figsize=(12,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('Reorder Ratio')
plt.ylabel('department_id')
plt.title("Reorder ratio of different aisles", fontsize=15)
plt.show()

__results___44_0.png

L'axe vertical est le département et l'axe horizontal est le ratio de rachat. Les points à la même hauteur sont des produits de différentes catégories dans la même catégorie.

** Commande à ajouter au panier - Taux de rachat **

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.ylabel('Reorder ratio', fontsize=12)
plt.xlabel('Add to cart order', fontsize=12)
plt.title("Add to cart order - Reorder ratio", fontsize=15)
plt.xticks(rotation='vertical')
plt.show()

__results___46_0.png

En parlant bien sûr, c'est naturel, mais plus vous mettez de produits dans le panier au début, plus vous en rachetez. Vous pouvez voir que les articles que vous achetez constamment sont mis en premier dans le panier.

** Taux de Time-Repurchase ** Regardons le taux de rachat pour le jour et l'heure de la journée. Créez les trois graphiques créés en 5.1.2 en utilisant la valeur moyenne de réorganisé comme index.

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.ylabel('Reorder ratio', fontsize=12)
plt.xlabel('Day of week', fontsize=12)
plt.title("Reorder ratio across day of week", fontsize=15)
plt.xticks(rotation='vertical')
plt.ylim(0.5, 0.7)
plt.show()

__results___48_0.png

Il semble que le taux de rachat n'augmente pas ou ne diminue pas un jour donné.

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.ylabel('Reorder ratio', fontsize=12)
plt.xlabel('Hour of day', fontsize=12)
plt.title("Reorder ratio across hour of day", fontsize=15)
plt.xticks(rotation='vertical')
plt.ylim(0.5, 0.7)
plt.show()

__results___49_0.png

Les articles commandés le matin sont susceptibles d'être rachetés.

grouped_df = order_products_train_df.groupby(["order_dow", "order_hour_of_day"])["reordered"].aggregate("mean").reset_index()
grouped_df = grouped_df.pivot('order_dow', 'order_hour_of_day', 'reordered')

plt.figure(figsize=(12,6))
sns.heatmap(grouped_df)
plt.title("Reorder ratio of Day of week Vs Hour of day")
plt.show()

__results___50_0.png

Dans l'ensemble, le taux de rachat du matin est élevé. Il est particulièrement élevé à 6-8 heures le week-end et à 5-6 heures les mardis et mercredis. En 5.1.2., Il y avait beaucoup de commandes le samedi et dimanche matin et après-midi. Cependant, en termes de rachat, j'ai constaté qu'il y en avait beaucoup tôt le matin indépendamment des jours de semaine et des jours fériés.

5.2. Analyse des informations publiées par Instacart sur le blog

Dans l'article de Medium, Instacart présente les données ouvertes. Les données utilisées dans l'article semblent être les mêmes que les données traitées dans ce concours. En plus de présenter les données, certains résultats d'analyse sont également affichés. Ici, je vais vous expliquer les deux chiffres introduits dans l'article.

1-jwDcKJTXV8D1DK0KOlUJAQ.png

Ce chiffre est un diagramme de dispersion représentant le nombre d'achats et le taux de rachat par allée. Les fruits frais ont un taux de rachat plus élevé que les légumes frais. Les légumes sont plus destinés aux recettes que les fruits et peuvent être le résultat d'achats intermittents. De plus, les produits d'épicerie tels que les ingrédients pour la soupe et la pâte à pain ont les taux de rachat les plus bas. Probablement parce que la fréquence de la demande est faible en premier lieu.

1-wKfV6OV-_1Ipwrl7AjjSuw (1).png

Des collations saines et des aliments principaux sont souvent achetés le matin, et de la crème glacée (en particulier Half Baked, The Tonight Dough) est souvent achetée le soir. Des 25 articles les plus récemment commandés (en soirée), 24 étaient de la crème glacée et 25 des pizzas surgelées.

Chippy reproduit la seconde moitié de la figure. Ce chiffre est écrit en R et a un volume d'environ 300 lignes. Si vous êtes intéressé, veuillez le vérifier.

5.3. Benchmark utilisant le GBM léger

(Je l'ajouterai plus tard.)

Recommended Posts

Résumé de Kaggle: Analyse du panier de marché Instacart
Résumé de Kaggle: Outbrain # 1
Résumé lié à Kaggle
Résumé de Kaggle: Redhat (Partie 1)
Analyse du panier avec Spark (1)
Kaggle ~ Analyse du logement ③ ~ Part1
Résumé de Kaggle: BOSCH (noyaux)
Résumé Kaggle: BOSCH (gagnant)
Résumé de Kaggle: Redhat (partie 2)
Résumé de la méthode du noyau de Kaggle [Image]
Apprentissage d'ensemble et analyse de paniers