Estimation raisonnable du prix de Mercari par apprentissage automatique

introduction

Il peut être difficile de savoir ce qui en vaut vraiment la peine. Moins de détails peuvent faire une grande différence de prix. Par exemple, l'un de ces chandails coûte 335 $ et l'autre 9,99 $. Pouvez-vous deviner lequel est lequel?

スクリーンショット 2019-12-25 1.52.54.png

Compte tenu du nombre de produits vendus en ligne, la tarification des produits est encore plus difficile. Le prix des vêtements a de fortes tendances saisonnières de prix et est fortement influencé par le nom de la marque, mais le prix des appareils électroniques fluctue en fonction des spécifications du produit.

La plus grande application d'achat communautaire du Japon est profondément consciente de ce problème. Il est difficile de proposer une bonne offre de prix au vendeur, car le vendeur peut mettre n'importe quoi ou n'importe quoi sur le marché Mercari.

À propos du défi de suggestion de prix Mercari

スクリーンショット 2019-12-25 1.49.29.png

Le Mercari Price Suggestion Challenge est un concours qui évalue le «prix raisonnable» d'un produit à partir des données produit réellement mises en vente. Les données produit incluent le nom du produit, la description du produit, l'état du produit, le nom de la marque, le nom de la catégorie, etc., et sur cette base, l'apprentissage automatique est utilisé pour prédire le prix de vente.

L'ensemble de données produit est publié par la version nord-américaine de Mercari, donc tout le monde peut l'obtenir. https://www.kaggle.com/c/mercari-price-suggestion-challenge/data

Cette fois, j'aimerais utiliser ces données pour estimer le prix approprié.

Type de données

スクリーンショット 2019-12-23 20.58.11.png

train.tsv a les données de 1,5 million d'articles actuellement répertoriés. Toutes les notations sont en anglais en raison de la version nord-américaine des données Mercari. Le produit est décrit à partir de 8 colonnes.

colonne La description
train_id ID de publication de l'utilisateur
name Nom du produit
item_condition_id État du produit
category_name Catégorie de produit
brand_name marque
price Prix de vente (dollar)
shipping Frais de port (exposant ou acheteur)
item_description Description du produit

Ces données sont divisées en train et test, et le prix de vente est prédit par l'apprentissage automatique.

Configuration du système

  1. Acquisition de données
  2. trian.tsv (fichier de données)
  3. Prétraitement des données
  4. Traitement des défauts et conversion de type
  5. Vectorisation basée sur le nombre d'occurrences du nom du produit et du nom de la catégorie
  6. Extraction des caractéristiques de la description du produit
  7. Étiquetage du nom de marque
  8. Variation quantitative de l'état du produit et des frais d'expédition
  9. Construction de modèles
  10. Optimisation des hyper paramètres 2. Ridge + LightGBM
  11. Évaluation du modèle
  12. Trame de données
  13. Visualisation
  14. Évaluation globale

L'environnement d'exécution est sur Google Colaboratory. Étant donné que le nombre de données est extrêmement important, cela prendra du temps à moins que ce ne soit dans un environnement GPU.

Veuillez vous référer ici pour Goggle Colboratory Présentation et instructions de Google Colaboratory (TensorFlow et GPU peuvent être utilisés)

Méthode d'évaluation de la précision

スクリーンショット 2019-12-25 1.05.18.png

RSMLE est utilisé lorsque vous souhaitez exprimer la distribution proche de la ** distribution log normale ** et de l'erreur ** entre la valeur mesurée et la valeur prédite sous forme de rapport ou de rapport ** au lieu d'une largeur.

En regardant la figure ci-dessus, l'histogramme des prix du produit ressemble à une distribution normale logarithmique. Aussi, par exemple Les largeurs d'erreur de (1000, 5000) et (100000, 104000) sont égales à 4000, mais les taux d'erreur sont différents et cette différence est importante.

A partir de là, le prix estimé semble convenir à la méthode d'évaluation par RMSLE.

Prétraitement des données

Non seulement train.tsv mais aussi test.tsv sont publiés, mais comme il n'a pas d'étiquette de réponse correcte, les données obtenues en supprimant environ 10000 éléments de train.tsv sont utilisées comme données de test.

Données globales (* 1482535, 8 ) -> (train_df ( 1472535, 8 ), test_df ( 10000, 7 *))

Conversion de type et manquante

Il existe de nombreux espaces dans les catégories, les marques et les descriptions de produits. En apprentissage automatique, il est normal de traiter les défauts, alors remplissez les espaces avec la fonction suivante. En raison de l'absence, la marque «manquante» représentait 42% du total.

def handle_missing_inplace(dataset):
    dataset['category_name'].fillna(value="Other", inplace=True)
    dataset['brand_name'].fillna(value='missing', inplace=True)
    dataset['item_description'].fillna(value='None', inplace=True)

La marque est coupée avant la conversion de type. Puisqu'il existe environ 5000 types de marques, les noms de marque qui apparaissent très peu de fois ne sont pas très utiles pour l'apprentissage, alors entrez le même «manquant» que le blanc.

pop_brands = df["brand_name"].value_counts().index[:NUM_BRANDS]
df.loc[~df["brand_name"].isin(pop_brands), "brand_name"] = "missing"

Après avoir coupé environ la moitié, le nombre minimum d'apparitions était de 4 fois.

スクリーンショット 2019-12-23 21.47.14.png

Convertit les données texte en type de catégorie. En effet, des variables factices sont créées lors du traitement ultérieur.

def to_categorical(dataset):
    dataset['category_name'] = dataset['category_name'].astype('category')
    dataset['brand_name'] = dataset['brand_name'].astype('category')
    dataset['item_condition_id'] = dataset['item_condition_id'].astype('category')

Extraction d'entités de texte avec Count Vectrizer

Applique CountVectorizer aux noms de produits et aux noms de catégories. Pour faire simple, CountVectorizer est vectorisé en fonction du nombre d'occurrences. Par exemple, si vous exécutez Count Vectorizer sur les trois noms de produit «MLB Cincinnati Reds T Shirt Size XL», «AVA-VIV Blouse» et «Leather Horse Statues», ils seront vectorisés comme suit.

スクリーンショット 2019-12-23 22.23.43.png

De plus, comme le nom du produit est saisi par le vendeur, il peut y avoir des erreurs typographiques dans le mot ou des mots fixes ou des chiffres qui n'apparaissent que dans des phrases spécifiques. Dans cet esprit, ajoutez l'option min_df à CountVectorizer. min_df signifie exclure les mots qui apparaissent moins que min_df%.

count_name = CountVectorizer(min_df=NAME_MIN_DF)
X_name = count_name.fit_transform(df["name"])

count_category = CountVectorizer()
X_category = count_category.fit_transform(df["category_name"])

Extraction de fonctionnalités de texte avec TfidfVectorizer

Contrairement à CountVectorizer, TfidfVectorizer considère non seulement le nombre d'occurrences d'un mot mais également la rareté du mot. Par exemple, les mots qui existent dans chaque phrase tels que «desu» et «masu», et les acronymes tels que «a» et «the» apparaissent fréquemment en anglais et sont fortement entraînés par ces mots dans Count Vectorizer. Au lieu de cela, il est utilisé lorsque vous souhaitez effectuer une vectorisation en se concentrant sur l'importance des mots.

En d'autres termes, TfidfVecotrizer signifie "pondérer les mots qui apparaissent fréquemment dans un document et rarement dans un autre document de grande importance".

A partir des points ci-dessus, la description du produit sera vectorisée par TfidfVectorizer.

スクリーンショット 2019-12-18 15.28.04.png

Ensuite, le tableau est comme indiqué ci-dessus et la valeur tfidf est fortement attachée à l'acronyme et au connectif. Spécifiez stop_word = 'english' car ces mots n'ont toujours pas de sens dans l'apprentissage.

Ensuite, la figure de gauche montre les 10 dernières valeurs tfidf. Si la valeur tfidf est extrêmement petite, cela n'a pas beaucoup de sens, alors supprimez-la. Aussi, au lieu de prendre tfidf pour un mot, prenez tfidf pour des mots consécutifs. Par exemple, définissons n-gramme avec le dicton "une pomme par jour éloigne le médecin" (une pomme par jour sans médecin).

n-gram(1, 2)

{'an': 0, 'apple': 2, 'day': 5, 'keeps': 9, 'the': 11,'doctor':7,'away': 4,
 'an apple': 1, 'apple day': 3, 'day keeps': 6, 'keeps the': 10,
 'the doctor': 12, 'doctor away': 8}

n-gram(1, 3)

{'an': 0, 'apple': 3, 'day': 7, 'keeps': 12, 'the': 15, 'doctor': 10,'away': 6,
 'an apple': 1, 'apple day': 4, 'day keeps': 8, 'keeps the': 13,'the doctor': 16,
 'doctor away': 11, 'an apple day': 2, 'apple day keeps': 5, 'day keeps the': 9,
 'keeps the doctor': 14, 'the doctor away': 17}

De cette manière, à mesure que la plage de n grammes augmente, les caractéristiques du texte sont capturées plus en détail et des données utiles sont acquises. Avec l'ajout d'options, cela ressemble à la figure de droite.

スクリーンショット 2019-12-24 15.14.11.png

Le tfidf final ressemblera à la figure ci-dessous. Celui avec la valeur tfidf la plus élevée est "description", qui peut être vu comme étant influencé par "Pas encore de description". Vous pouvez voir que les articles neufs et d'occasion tels que «neuf» et «utilisé» affectent également le prix.

スクリーンショット 2019-12-18 16.44.05.png

tfidf_descp = TfidfVectorizer(max_features = MAX_FEAT_DESCP,
                              ngram_range = (1,3),
                              stop_words = "english")
X_descp = tfidf_descp.fit_transform(df["item_description"])

Binarisation avec Label Binarizer

Comme je l'ai mentionné plus tôt, il existe environ 5 000 types de marques et, à la suite du processus de découpe, il existe environ 2 500 types de marques. Marquez-les avec 0 ou 1. Comme il y a beaucoup de données, définissez sparse_output = True et exécutez.

label_brand = LabelBinarizer(sparse_output=True)
X_brand = label_brand.fit_transform(df["brand_name"])

Variable muette

Les variables factices sont une technique permettant de convertir des données non numériques en nombres. Plus précisément, il convertit les données non numériques en une séquence de nombres avec seulement «0» et «1». Ici, des variables factices sont créées pour l'état du produit et les frais d'expédition.

X_dummies = scipy.sparse.csr_matrix(pd.get_dummies(df[[
    "item_condition_id", "shipping"]], sparse = True).values, dtype=int)

Maintenant que nous avons traité toutes les colonnes, nous allons combiner toutes les séquences et les appliquer au modèle.

X = scipy.sparse.hstack((X_dummies,
                         X_descp,
                         X_brand,
                         X_category,
                         X_name)).tocsr()

Apprentissage de modèle

Description des paramètres

Comme tous les paramètres ne peuvent pas être expliqués, certains paramètres sont résumés brièvement.

Paramètre Ridge

option desc
alpha Degré de normalisation pour éviter le surapprentissage
max_iter Nombre maximum d'itérations d'apprentissage
tol Sous réserve d'une augmentation du score de tol ou plus

alpha

Il est possible de construire un modèle qui s'adapte excessivement aux données données et provoque une petite erreur pour les données d'entraînement données, mais il est appelé "** surentraînement " qu'il n'est pas possible de faire une prédiction appropriée pour des données inconnues. dire. Par conséquent, le surapprentissage peut être évité en définissant des restrictions sur l'apprentissage des paramètres. Une telle limitation est appelée " normalisation **".

Paramètres LightGBM

option description
n_esimators Nombre d'arbres déterminés
learning_rate Poids de chaque arbre
max_depth Profondeur maximale de chaque arbre
num_leaves Nombre de feuilles
min_child_samples Nombre minimum de données contenues dans le nœud final
n_jobs Nombre de processus parallèles

learning_rate

n_estimatiors

Optimisation des hyper paramètres

Ridge

Commencez par rechercher la valeur optimale de alpha. Déplacez alpha dans la plage de 0,05 à 75 pour visualiser l'effet sur la précision

スクリーンショット 2019-12-20 1.26.15.png

D'après la figure, la valeur minimale * RMSLE 0,4745938085035464 * a été obtenue lorsque alpha = 3,0.

Ensuite, suite à la vérification du nombre maximum de recherches max_iter dans toutes les plages, aucune amélioration de la précision n'a été obtenue. De plus, plus la valeur tol est élevée, moins elle est précise.

スクリーンショット 2019-12-20 3.06.27.png

D'après ce qui précède, le paramètre Ridge est modélisé avec alpha = 3.

LGBM Pour le réglage des paramètres LGBM, je me suis référé aux documents. https://lightgbm.readthedocs.io/en/latest/Parameters-Tuning.html

Il semble être une pratique courante de commencer par définir learning_rate et n_estimatiors comme première étape dans l'ajustement des paramètres de LGBM. Pour améliorer la précision, il semble que learning_rate soit petit et n_estimatiors soit grand. Déplacez learning_rate dans la plage de 0,05 à 0,7 pour ajuster n_estimatiors.

Ensuite, après avoir défini learning_rate et n_estimatiors, déplacez num_leaves.

(num_leaves = 20) RMSLE 0.4620242411418184        ↓ (num = 31) RMSLE 0.4569169142862856        ↓ (num = 40) RMSLE 0.45587232757584967

Dans l'ensemble, nous avons constaté que l'augmentation de num_leaves améliorait également la précision. Globalement ici signifie même lorsque d'autres paramètres sont ajustés.

Cependant, lors de l'ajustement de chaque paramètre, si num_leaves était trop élevé, un ** sur-appariement ** se produirait et, dans certains cas, un bon score ne pourrait pas être obtenu. J'ai dû bien l'ajuster avec d'autres paramètres.

Lorsque learning_rate = 0,7 max_depth = 15, num_leaves = 30 RMSLE 44.650714399639845

Le modèle final LGBM ressemble à ceci:

lgbm_params = {'n_estimators': 1000, 'learning_rate': 0.4, 'max_depth': 15,
               'num_leaves': 40, 'subsample': 0.9, 'colsample_bytree': 0.8,
               'min_child_samples': 50, 'n_jobs': 4}

Évaluation du modèle

Rideg + LGBM est utilisé pour calculer la valeur prédite. LGBM a un meilleur score que Ridge, mais en combinant les deux modèles, vous pouvez améliorer la précision. Ridge RMSL error on dev set: 0.47459370995217937

LGBM RMSL error on dev set: 0.45317097672035855

Ridge + LGBM RMSL error on dev set: 0.4433081424824549

Cette précision correspond à une plage d'erreur estimée de 18,89 à 47,29 pour un produit à 30 $.

price est la valeur prédite par Ridge + LGBM, et real_price est la valeur mesurée. Sur les 10 000 données de test, il y en avait environ 7553 avec des erreurs de moins de 10 $.

スクリーンショット 2019-12-19 17.51.00.png


Tracé résiduel avec journal スクリーンショット 2019-12-15 16.16.47.png


Répartition des prix réels et estimés スクリーンショット 2019-12-20 4.28.56.png


J'ai simplement pris la différence, mais il y a environ 90 produits qui ont une différence de 100 dollars ou plus entre la valeur prévue et la valeur mesurée. Étant donné que cet ensemble de données est des données d'il y a deux ans, on peut voir que le nombre de données est petit et qu'il n'est pas possible de bien prévoir car Apple Watch etc. sont des produits relativement nouveaux. C'est aussi Mercari. C'est bien, mais tout ne peut pas être bien prédit à cause du prix basé sur des valeurs personnelles. Le sac d'entraîneur a en fait été vendu pour environ 9 $ ...

スクリーンショット 2019-12-20 5.04.42.png

Code complété

import numpy as np
import pandas as pd
import scipy

from sklearn.linear_model import Ridge
from lightgbm import LGBMRegressor
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.preprocessing import LabelBinarizer

NUM_BRANDS = 2500
NAME_MIN_DF = 10
MAX_FEAT_DESCP = 10000

print("Reading in Data")
df = pd.read_csv('train.tsv', sep='\t')

print('Formatting Data')
shape = df.shape[0]
train_df = df[:shape-10000]
test_df = df[shape-10000:]

target = test_df.loc[:, 'price'].values
target = np.log1p(target)

print("Concatenate data")
df = pd.concat([train_df, test_df], 0)

nrow_train = train_df.shape[0]
y_train = np.log1p(train_df["price"])

def handle_missing_inplace(dataset):
    dataset['category_name'].fillna(value="Othe", inplace=True)
    dataset['brand_name'].fillna(value='missing', inplace=True)
    dataset['item_description'].fillna(value='None', inplace=True)

print('Handle missing')
handle_missing_inplace(df)

def to_categorical(dataset):
    dataset['category_name'] = dataset['category_name'].astype('category')
    dataset['brand_name'] = dataset['brand_name'].astype('category')
    dataset['item_condition_id'] = dataset['item_condition_id'].astype('category')

print('Convert categorical')
to_categorical(df)

print('Cut')
pop_brands = df["brand_name"].value_counts().index[:NUM_BRANDS]
df.loc[~df["brand_name"].isin(pop_brands), "brand_name"] = "missing"

print("Name Encoders")
count_name = CountVectorizer(min_df=NAME_MIN_DF)
X_name = count_name.fit_transform(df["name"])

print("Category Encoders")
count_category = CountVectorizer()
X_category = count_category.fit_transform(df["category_name"])

print("Descp encoders")
tfidf_descp = TfidfVectorizer(max_features = MAX_FEAT_DESCP,
                              ngram_range = (1,3),
                              stop_words = "english")
X_descp = tfidf_descp.fit_transform(df["item_description"])

print("Brand encoders")
label_brand = LabelBinarizer(sparse_output=True)
X_brand = label_brand.fit_transform(df["brand_name"])

print("Dummy Encoders")
X_dummies = scipy.sparse.csr_matrix(pd.get_dummies(df[[
    "item_condition_id", "shipping"]], sparse = True).values, dtype=int)

X = scipy.sparse.hstack((X_dummies,
                         X_descp,
                         X_brand,
                         X_category,
                         X_name)).tocsr()

print("Finished to create sparse merge")

X_train = X[:nrow_train]
X_test = X[nrow_train:]

model = Ridge(solver='auto', fit_intercept=True, alpha=3)

print("Fitting Rige")
model.fit(X_train, y_train)

print("Predicting price Ridge")
preds1 = model.predict(X_test)

def rmsle(Y, Y_pred):
    assert Y.shape == Y_pred.shape
    return np.sqrt(np.mean(np.square(Y_pred - Y )))

print("Ridge RMSL error on dev set:", rmsle(target, preds1))

def rmsle_lgb(labels, preds):
    return 'rmsle', rmsle(preds, labels), False

train_X, valid_X, train_y, valid_y = train_test_split(X_train, y_train, test_size=0.3, random_state=42)

lgbm_params = {'n_estimators': 1000, 'learning_rate': 0.4, 'max_depth': 15,
               'num_leaves': 40, 'subsample': 0.9, 'colsample_bytree': 0.8,
               'min_child_samples': 50, 'n_jobs': 4}

model = LGBMRegressor(**lgbm_params)
print('Fitting LGBM')
model.fit(train_X, train_y,
          eval_set=[(valid_X, valid_y)],
          eval_metric=rmsle_lgb,
          early_stopping_rounds=100,
          verbose=True)

print("Predict price LGBM")
preds2 = model.predict(X_test)

print("LGBM RMSL error on dev set:", rmsle(target, preds2))

preds = (preds1 + preds2) / 2

print("Ridge + LGBM RMSL error on dev set:", rmsle(target, preds))

test_df["price1"] = np.expm1(preds1)
test_df['price2']=np.exp(preds2)
test_df['price']= np.expm1(preds)
test_df['real_price'] = np.expm1(target)

Résumé

Suite à l'estimation du juste prix, nous avons obtenu un meilleur score que prévu. Je pense que la précision se serait améliorée un peu plus si la valeur min_df, le réglage de la plage de n-grammes, etc. avaient été modifiés dans la partie de pré-traitement, et si le texte n'était pas seulement appliqué à tfidf mais apportait des corrections plus détaillées. .. De plus, les valeurs des produits sont différentes pour chaque personne, vous ne pouvez donc prévoir que dans une certaine mesure. Si vous le trouvez utile, veuillez me donner un bon bouton!

Recommended Posts

Estimation raisonnable du prix de Mercari par apprentissage automatique
Classification des images de guitare par apprentissage automatique Partie 1
Prévision du cours de l'action par machine learning Numerai Signals
[Français] scikit-learn 0.18 Introduction de l'apprentissage automatique par le didacticiel scikit-learn
Classification des images de guitare par apprentissage automatique, partie 2
Importance des ensembles de données d'apprentissage automatique
4 [/] Quatre arithmétiques par apprentissage automatique
Prédire la présence ou l'absence d'infidélité par l'apprentissage automatique
Compréhension de base de l'estimation de la profondeur par caméra mono (Deep Learning)
Prévisions du cours des actions par apprentissage automatique Commençons Numerai
Importance de l'apprentissage automatique et de l'apprentissage par mini-lots
Résumé de l'apprentissage automatique par les débutants de Python
Apprentissage automatique ③ Résumé de l'arbre de décision
Les prévisions du cours des actions par apprentissage automatique sont si vraies Signaux Numerai
Mémorandum of scraping & machine learning [technique de développement] par Python (chapitre 4)
Mémorandum of scraping & machine learning [technique de développement] par Python (chapitre 5)
Algorithme d'apprentissage automatique (généralisation de la régression linéaire)
Prévision du cours des actions à l'aide de l'apprentissage automatique (scikit-learn)
Faire le contrôle d'un homme sandwich par l'apprentissage automatique ver4
[Mémo d'apprentissage] Bases de la classe par python
[Échec] Trouvez Maki Horikita par apprentissage automatique
Quatre règles de fonctionnement avec l'apprentissage automatique 6 [Commercial]
Apprentissage automatique
Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)
[Apprentissage automatique] Apprentissage supervisé utilisant l'estimation de la densité du noyau
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer Chapitre 13 Bases du réseau neuronal
Prévision du cours des actions à l'aide de l'apprentissage automatique (édition de retour)
[Apprentissage automatique] Liste des packages fréquemment utilisés
Mémo d'étude Python & Machine Learning ④: Machine Learning par rétro-propagation
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer jusqu'à la fin du chapitre 2
Déterminez l'authenticité des articles publiés par machine learning (API Google Prediction).
Apprentissage automatique: reconnaissance d'image de MNIST à l'aide de PCA et de Gaussian Native Bayes
Est-il possible de manger avec les prévisions de cours de bourse par apprentissage automatique [Plan de mise en œuvre]
Mise en place d'un modèle de prédiction des taux de change (taux dollar-yen) par machine learning
Prédire les travaux de courte durée de Weekly Shonen Jump par apprentissage automatique (Partie 1: Analyse des données)
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 1
Début de l'apprentissage automatique (matériel didactique / informations recommandés)
Essayez de prédire la demande de puissance par l'apprentissage automatique
Mémo d'étude Python & Machine Learning ⑤: Classification d'Ayame
Tournoi Numerai - Fusion de quants traditionnels et apprentissage automatique -
Mémo d'étude Python & Machine Learning ②: Introduction de la bibliothèque
Divulgation complète des méthodes utilisées dans l'apprentissage automatique
[Apprentissage automatique] Apprentissage supervisé utilisant l'estimation de la densité du noyau Partie 2
Compréhension de base de l'estimation de la profondeur stéréo (Deep Learning)
[Apprentissage automatique] Apprentissage supervisé utilisant l'estimation de la densité du noyau Partie 3
Liste des liens que les débutants en apprentissage automatique apprennent
Apprentissage parallèle du deep learning par Keras et Kubernetes
Vue d'ensemble des techniques d'apprentissage automatique apprises grâce à scikit-learn
À propos du contenu de développement de l'apprentissage automatique (exemple)
Résumé des fonctions d'évaluation utilisées dans l'apprentissage automatique
Classer les informations liées à l'apprentissage automatique par modèle de sujet
Amélioration de la metrix de performance par modèle d'apprentissage en 2 étapes
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 2
Touchons une partie de l'apprentissage automatique avec Python
Mémo d'étude Python & Machine Learning ⑦: Prévision du cours de l'action
Apprentissage profond appris par mise en œuvre (segmentation) ~ Mise en œuvre de SegNet ~
Essayez d'utiliser le bloc-notes Jupyter à partir d'Azure Machine Learning
Histoire de l'analyse de données par apprentissage automatique
Disposition des éléments auto-mentionnés liés à l'apprentissage automatique
Raisonnement causal utilisant l'apprentissage automatique (organisation des méthodes de raisonnement causal)