Régression linéaire TensorFlow avec facette et terme d'interaction

Dans ce didacticiel, vous apprendrez à vérifier les données et à les préparer pour créer une tâche de régression linéaire simple.

Ce tutoriel est divisé en deux parties :

  • Recherchez l'interaction
  • Tester le modèle

Dans le précédent tutoriel, vous avez utilisé l'ensemble de données de Boston pour estimer le prix médian d'une maison. L'ensemble de données de Boston est de petite taille, avec seulement 506 observations. Cet ensemble de données est considéré comme une référence pour essayer de nouveaux algorithmes de régression linéaire.

L'ensemble de données est composé de :

Variable Description
zn La proportion de terrains résidentiels zonés pour des lots de plus de 25,000 pieds carrés.
indus La proportion de superficies commerciales non commerciales par ville.
nox concentration d'oxyde nitrique
rm nombre moyen de pièces par logement
âge la proportion de logements occupés par leur propriétaire construits avant 1940
DIS distances pondérées jusqu'à cinq centres d'emploi de Boston
impôt taux de taxe foncière pleine valeur par dollar 10,000
ptratio le ratio élèves/enseignant par ville
avec V La valeur médiane des maisons occupées par leur propriétaire en milliers de dollars
crime taux de criminalité par habitant par ville
Chas Variable muette de Charles River (1 si limite la rivière ; 0 sinon)
B la proportion de noirs par ville

Dans ce didacticiel, nous estimerons le prix médian à l'aide d'un régresseur linéaire, mais l'accent est mis sur un processus particulier de machine learning: "préparation des données."

Un modèle généralise le modèle dans les données. Pour capturer un tel modèle, vous devez d’abord le trouver. Une bonne pratique consiste à effectuer une analyse des données avant d’exécuter un algorithme d’apprentissage automatique.

Choisir les bonnes fonctionnalités fait toute la différence dans le succès de votre modèle. Imaginez que vous essayiez d'estimer le salaire d'un peuple, si vous n'incluez pas le sexe comme covariable, vous vous retrouvez avec une mauvaise estimation.

Une autre façon d’améliorer le modèle consiste à examiner la corrélation entre la variable indépendante. Pour revenir à l’exemple, vous pouvez considérer l’éducation comme un excellent candidat pour prédire le salaire mais aussi la profession. Il est juste de dire que le métier dépend du niveau d’éducation, à savoir que l’enseignement supérieur mène souvent à un meilleur métier. Si nous généralisons cette idée, nous pouvons dire que la corrélation entre la variable dépendante et une variable explicative peut être amplifiée par une autre variable explicative.

Pour rendre compte de l’effet limité de l’éducation sur la profession, nous pouvons utiliser un terme d’interaction.

Terme d'interaction

Si vous regardez l’équation des salaires, cela devient :

Terme d'interaction

If Terme d'interaction est positif, cela implique qu’un niveau d’éducation supplémentaire entraîne une augmentation plus élevée de la valeur médiane d’une maison pour un niveau d’occupation élevé. En d’autres termes, il existe un effet d’interaction entre l’éducation et la profession.

Dans ce didacticiel, nous essaierons de voir quelles variables peuvent être de bonnes candidates pour les termes d'interaction. Nous testerons si l’ajout de ce type d’informations conduit à une meilleure prévision des prix.

Statistiques sommaires

Vous pouvez suivre quelques étapes avant de passer au modèle. Comme mentionné précédemment, le modèle est une généralisation des données. La meilleure pratique consiste à comprendre les données et à faire une prédiction. Si vous ne connaissez pas vos données, vous avez peu de chances d'améliorer votre modèle.

Dans un premier temps, chargez les données en tant que dataframe pandas et créez un ensemble de formation et un ensemble de tests.

Conseils : Pour ce didacticiel, vous devez avoir installé matplotlit et seaborn dans Python. Vous pouvez installer Python colis à la volée avec Jupyter. Vous Ne devrait pas faire cela

!conda install -- yes matplotlib

mais

import sys
!{sys.executable} -m pip install matplotlib # Already installed
!{sys.executable} -m pip install seaborn 

Notez que cette étape n’est pas nécessaire si matplotlib et seaborn sont installés.

Matplotlib est la bibliothèque pour créer un graphique dans Python. Seaborn est une bibliothèque de visualisation statistique construite sur matplotlib. Il offre des parcelles attrayantes et belles.

Le code ci-dessous importe les bibliothèques nécessaires.

import pandas as pd
from sklearn import datasets
import tensorflow as tf
from sklearn.datasets import load_boston
import numpy as np

La bibliothèque sklearn inclut l'ensemble de données Boston. Vous pouvez appeler son API pour importer les données.

boston = load_boston()
df = pd.DataFrame(boston.data)

Les noms de fonctionnalités sont stockés dans l'objet feature_names dans un tableau.

boston.feature_names

Sortie

array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')

Vous pouvez renommer les colonnes.

df.columns = boston.feature_names
df['PRICE'] = boston.target
df.head(2)

Régression linéaire avec facette et terme d'interaction

Vous convertissez la variable CHAS en variable chaîne et l'étiquetez avec oui si CHAS = 1 et non si CHAS = 0

df['CHAS'] = df['CHAS'].map({1:'yes', 0:'no'})
df['CHAS'].head(5)
0    no
1    no
2    no
3    no
4    no
Name: CHAS, dtype: object

Avec les pandas, il est simple de diviser l'ensemble de données. Vous divisez aléatoirement l'ensemble de données avec 80 % d'ensemble de formation et 20 % d'ensemble de test. Pandas avoir une fonction de coût intégrée pour diviser un échantillon de trame de données.

Le premier paramètre frac est une valeur comprise entre 0 et 1. Vous le définissez sur 0.8 pour sélectionner de manière aléatoire 80 % de la trame de données.

Random_state permet de renvoyer la même trame de données pour tout le monde.

### Create train/test set
df_train=df.sample(frac=0.8,random_state=200)
df_test=df.drop(df_train.index)

Vous pouvez obtenir la forme des données. Ça devrait être:

  • Coffret : 506*0.8 = 405
  • Ensemble de tests : 506*0.2 = 101
print(df_train.shape, df_test.shape)

Sortie

(405, 14) (101, 14)
df_test.head(5)

Sortie

CRIM ZN INDUS CHAS NOX RM L'âge DIS RAD TAXE PTRATIO B LSTAT PRIX
0 0.00632 18.0 2.31 aucune 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 aucune 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
3 0.03237 0.0 2.18 aucune 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
6 0.08829 12.5 7.87 aucune 0.524 6.012 66.6 5.5605 5.0 311.0 15.2 395.60 12.43 22.9
7 0.14455 12.5 7.87 aucune 0.524 6.172 96.1 5.9505 5.0 311.0 15.2 396.90 19.15 27.1

Les données sont compliquées ; il est souvent déséquilibré et parsemé de valeurs aberrantes qui perturbent la formation en analyse et en apprentissage automatique.

La première étape pour nettoyer l’ensemble de données consiste à comprendre où il doit être nettoyé. Nettoyer un ensemble de données peut être délicat à réaliser, surtout de manière généralisable

L'équipe de recherche Google a développé un outil pour ce travail appelé Facettes qui aident à visualiser les données et à les découper de toutes sortes de manières. C'est un bon point de départ pour comprendre comment l'ensemble de données est présenté.

Les facettes vous permettent de trouver les endroits où les données ne correspondent pas tout à fait à ce que vous pensez.

À l'exception de son application Web, Google facilite l'intégration de la boîte à outils dans un Jupyter carnet.

Facettes comporte deux parties :

  • Présentation des facettes
  • Analyse approfondie des facettes

Présentation des facettes

Facets Overview donne un aperçu de l’ensemble de données. L'aperçu des facettes divise les colonnes de données en lignes d'informations importantes montrant

  1. le pourcentage d'observation manquante
  2. valeurs min et max
  3. des statistiques comme la moyenne, la médiane et l’écart type.
  4. Il ajoute également une colonne qui affiche le pourcentage de valeurs qui sont des zéros, ce qui est utile lorsque la plupart des valeurs sont des zéros.
  5. Il est possible de voir ces distributions sur l'ensemble de données de test ainsi que l'ensemble d'entraînement pour chaque fonctionnalité. Cela signifie que vous pouvez vérifier que le test a une distribution similaire à celle des données d'entraînement.

C’est au moins le minimum à faire avant toute tâche de machine learning. Avec cet outil, vous ne manquez pas cette étape cruciale, et il met en évidence certaines anomalies.

Analyse approfondie des facettes

Facets Deep Dive est un outil sympa. Cela permet d'avoir une certaine clarté sur votre ensemble de données et de zoomer complètement pour voir une donnée individuelle. Cela signifie que vous pouvez diviser les données par ligne et colonne sur n'importe quelle fonctionnalité de l'ensemble de données.

Nous utiliserons ces deux outils avec l'ensemble de données de Boston.

Notes: Vous ne pouvez pas utiliser Facets Overview et Facets Deep Dive en même temps. Vous devez d'abord effacer le bloc-notes pour changer d'outil.

Installer la facette

Vous pouvez utiliser l'application Web Facet pour la plupart des analyses. Dans ce tutoriel, vous verrez comment l'utiliser au sein d'un Jupyter Carnet.

Tout d'abord, vous devez installer nbextensions. C'est chose faite avec ce code. Vous copiez et collez le code suivant dans le terminal de votre machine.

pip install jupyter_contrib_nbextensions

Juste après cela, vous devez cloner les référentiels sur votre ordinateur. Vous avez deux choix :

Option 1) Copiez et collez ce code dans le terminal (Recommandé)

Si Git n'est pas installé sur votre machine, veuillez accéder à cette URL https://git-scm.com/download/win et suivez les instructions. Une fois que vous avez terminé, vous pouvez utiliser la commande git dans le terminal pour les utilisateurs Mac ou l'invite Anaconda pour Windows utilisateur

git clone https://github.com/PAIR-code/facets

Option 2) Cliquez sur https://github.com/PAIR-code/facets et téléchargez les référentiels.

Installer la facette

Si vous choisissez la première option, le fichier se retrouve dans votre fichier de téléchargement. Vous pouvez soit laisser le fichier en téléchargement, soit le faire glisser vers un autre chemin.

Vous pouvez vérifier où Facets est stocké avec cette ligne de commande :

echo `pwd`/`ls facets`

Maintenant que vous avez localisé Facets, vous devez l'installer dans Jupyter Carnet de notes. Vous devez définir le répertoire de travail sur le chemin où se trouvent les facettes.

Votre répertoire de travail actuel et l’emplacement du zip Facets doivent être les mêmes.

Installer la facette

Vous devez pointer le répertoire de travail vers Facet :

cd facets

Pour installer Facets dans Jupyter, vous avez deux options. Si vous avez installé Jupyter avec Conda pour tous les utilisateurs, copiez ce code :

peut utiliser jupyter nbextension installer facettes-dist/

jupyter nbextension install facets-dist/

Sinon, utilisez:

jupyter nbextension install facets-dist/ --user

Très bien, vous êtes prêt. Ouvrons l'aperçu des facettes.

Aperçu

La vue d'ensemble utilise un Python script pour calculer les statistiques. Vous devez importer le script appelé generic_feature_statistics_generator pour Jupyter. Ne t'inquiète pas; le script se trouve dans les fichiers de facettes.

Vous devez localiser son chemin. C’est facile à faire. Vous ouvrez les facettes, ouvrez le fichier facettes_overview puis python. Copiez le chemin

Facette de présentation

Après cela, retournez à Jupyteret écrivez le code suivant. Remplacez le chemin '/Users/Thomas/facets/facets_overview/python' par votre chemin.

# Add the facets overview python code to the python path# Add t 
import sys
sys.path.append('/Users/Thomas/facets/facets_overview/python')

Vous pouvez importer le script avec le code ci-dessous.

from generic_feature_statistics_generator import 
GenericFeatureStatisticsGenerator

Sous Windows, le même code devient

import sys
sys.path.append(r"C:\Users\Admin\Anaconda3\facets-master\facets_overview\python")

from generic_feature_statistics_generator import GenericFeatureStatisticsGenerator

Pour calculer les statistiques des fonctionnalités, vous devez utiliser la fonction GenericFeatureStatisticsGenerator(), et vous utilisez l'objet ProtoFromDataFrames. Vous pouvez transmettre le bloc de données dans un dictionnaire. Par exemple, si nous voulons créer une statistique récapitulative pour la rame, nous pouvons stocker les informations dans un dictionnaire et les utiliser dans l'objet « ProtoFromDataFrames ».

  • 'name': 'train', 'table': df_train

Nom est le nom de la table affichée et vous utilisez le nom de la table dont vous souhaitez calculer le résumé. Dans votre exemple, la table contenant les données est df_train

# Calculate the feature statistics proto from the datasets and stringify it for use in facets overview
import base64

gfsg = GenericFeatureStatisticsGenerator()

proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': df_train},
                                  {'name': 'test', 'table': df_test}])

#proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': df_train}])
protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")

Enfin, il vous suffit de copier et coller le code ci-dessous. Le code vient directement de GitHub. Vous devriez pouvoir voir ceci :

Facette de présentation

# Display the facets overview visualization for this data# Displ 
from IPython.core.display import display, HTML

HTML_TEMPLATE = """<link rel="import" href="/fr/nbextensions/facets-dist/facets-jupyter.html" >
        <facets-overview id="elem"></facets-overview>
        <script>
          document.querySelector("#elem").protoInput = "{protostr}";
        </script>"""
html = HTML_TEMPLATE.format(protostr=protostr)
display(HTML(html))

Graphique

Après avoir vérifié les données et leur distribution, vous pouvez tracer une matrice de corrélation. La matrice de corrélation calcule le coefficient de Pearson. Ce coefficient est compris entre -1 et 1, une valeur positive indique une corrélation positive et une valeur négative une corrélation négative.

Vous souhaitez savoir quelles variables peuvent être de bonnes candidates pour les termes d'interaction.

## Choose important feature and further check with Dive
%matplotlib inline  
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks")
# Compute the correlation matrix
corr = df.corr('pearson')
# Generate a mask for the upper triangle
mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True
# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(11, 9))

# Generate a custom diverging colormap
cmap = sns.diverging_palette(220, 10, as_cmap=True)

# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,annot=True,
            square=True, linewidths=.5, cbar_kws={"shrink": .5})

Sortie

<matplotlib.axes._subplots.AxesSubplot at 0x1a184d6518>

png

Graphique à facettes

De la matrice, vous pouvez voir :

  • LSTAT
  • RM

Sont fortement corrélés avec PRIX. Une autre caractéristique intéressante est la forte corrélation positive entre NOX et INDUS, ce qui signifie que ces deux variables évoluent dans la même direction. En outre, ils sont également corrélés au PRIX. DIS est également fortement corrélé avec IND et NOX.

Vous avez un premier indice selon lequel IND et NOX peuvent être de bons candidats pour le terme d'interception et DIS pourrait également être intéressant sur lequel se concentrer.

Vous pouvez aller un peu plus loin en traçant une grille de paires. Il illustrera plus en détail la carte de corrélation que vous avez tracée auparavant.

La grille de paires que nous sommes composée comme suit :

  • Partie supérieure : Nuage de points avec ligne ajustée
  • Diagonale : tracé de la densité du noyau
  • Partie inférieure : tracé de densité de noyau multivarié

Vous choisissez de vous concentrer sur quatre variables indépendantes. Le choix correspond aux variables à forte corrélation avec PRIX

  • INDUS
  • NOX
  • RM
  • LSTAT

de plus, le PRIX.

Notes que l'erreur standard est ajoutée par défaut au nuage de points.

attributes = ["PRICE", "INDUS", "NOX", "RM", "LSTAT"]

g = sns.PairGrid(df[attributes])
g = g.map_upper(sns.regplot, color="g")
g = g.map_lower(sns.kdeplot,cmap="Reds", shade=True, shade_lowest=False)
g = g.map_diag(sns.kdeplot)

Sortie

Graphique à facettes

Commençons par la partie supérieure :

  • Le prix est négativement corrélé avec INDUS, NOX et LSTAT ; positivement corrélé avec RM.
  • Il y a une légère non-linéarité avec LSTAT et PRICE
  • Il y a comme une ligne droite lorsque le prix est égal à 50. D'après la description du jeu de données, PRICE a été tronqué à la valeur de 50.

Diagonale

  • NOX semble avoir deux clusters, un autour de 0.5 et un autour de 0.85.

Pour en savoir plus, vous pouvez regarder la partie inférieure. La densité de noyau multivariée est intéressante dans le sens où elle colore l'endroit où se trouvent la plupart des points. La différence avec le nuage de points dessine une densité de probabilité, même s'il n'y a aucun point dans l'ensemble de données pour une coordonnée donnée. Lorsque la couleur est plus forte, cela indique une forte concentration de points autour de cette zone.

Si vous vérifiez la densité multivariée pour INDUS et NOX, vous pouvez voir la corrélation positive et les deux clusters. Lorsque la part de l’industrie est supérieure à 18, la concentration d’oxyde nitrique est supérieure à 0.6.

Vous pouvez penser à ajouter une interaction entre INDUS et NOX dans la relation linéaire.

Enfin, vous pouvez utiliser le deuxième outil créé par Google, Facets Deep Dive. L'interface est divisée en quatre sections principales. La zone centrale au centre est un affichage zoomable des données. En haut du panneau se trouve le menu déroulant dans lequel vous pouvez modifier la disposition des données pour contrôler les facettes, le positionnement et la couleur. Sur la droite, vous trouverez une vue détaillée d'une ligne de données spécifique. Cela signifie que vous pouvez cliquer sur n'importe quel point de données dans la visualisation centrale pour voir les détails de ce point de données particulier.

Lors de l'étape de visualisation des données, vous souhaitez rechercher la corrélation par paire entre la variable indépendante sur le prix de la maison. Cependant, cela implique au moins trois variables et les tracés 3D sont compliqués à utiliser.

Une façon de résoudre ce problème consiste à créer une variable catégorielle. Autrement dit, nous pouvons créer un tracé 2D et colorer le point. Vous pouvez diviser la variable PRIX en quatre catégories, chaque catégorie étant un quartile (c'est-à-dire 0.25, 0.5, 0.75). Vous appelez cette nouvelle variable Q_PRICE.

## Check non linearity with important features
df['Q_PRICE'] =  pd.qcut(df['PRICE'], 4, labels=["Lowest", "Low", "Upper", "upper_plus"])
## Show non linearity between RM and LSTAT
ax = sns.lmplot(x="DIS", y="INDUS", hue="Q_PRICE", data=df, fit_reg = False,palette="Set3")

Graphique à facettes

Analyse approfondie des facettes

Pour ouvrir Deep Dive, vous devez transformer les données au format json. Les pandas comme objet pour cela. Vous pouvez utiliser to_json après l'ensemble de données Pandas.

La première ligne de code gère la taille de l'ensemble de données.

df['Q_PRICE'] =  pd.qcut(df['PRICE'], 4, labels=["Lowest", "Low", "Upper", "upper_plus"])
sprite_size = 32 if len(df.index)>50000 else 64
jsonstr = df.to_json(orient='records')

Le code ci-dessous provient de Google GitHub. Après avoir exécuté le code, vous devriez pouvoir voir ceci :

Analyse approfondie des facettes

# Display thde Dive visualization for this data
from IPython.core.display import display, HTML

# Create Facets template  
HTML_TEMPLATE = """<link rel="import" href="/fr/nbextensions/facets-dist/facets-jupyter.html">
        <facets-dive sprite-image-width="{sprite_size}" sprite-image-height="{sprite_size}" id="elem" height="600"></facets-dive>
        <script>
          document.querySelector("#elem").data = {jsonstr};
        </script>"""

# Load the json dataset and the sprite_size into the template
html = HTML_TEMPLATE.format(jsonstr=jsonstr, sprite_size=sprite_size)

# Display the template
display(HTML(html))

Vous souhaitez voir s'il existe un lien entre le taux de l'industrie, la concentration d'oxydes, la distance jusqu'au centre d'emploi et le prix de la maison.

Pour cela, vous divisez d'abord les données par gamme d'industries et par couleur avec le quartile de prix :

  • Sélectionnez facettage X et choisissez INDUS.
  • Sélectionnez Affichage et choisissez DIS. Il colorera les points avec le quartile du prix de l'immobilier

ici, les couleurs plus foncées signifient que la distance jusqu'au premier centre d'emploi est longue.

Jusqu’à présent, cela montre à nouveau ce que vous savez, un taux industriel plus bas, un prix plus élevé. Vous pouvez maintenant regarder la répartition par INDUX, par NOX.

  • Sélectionnez la facette Y et choisissez NOX.

Vous pouvez désormais constater que les maisons situées loin du premier centre d'emploi ont la plus faible part de l'industrie et donc la plus faible concentration d'oxydes. Si vous choisissez d'afficher le type avec Q_PRICE et de zoomer sur le coin inférieur gauche, vous pouvez voir de quel type de prix il s'agit.

Vous avez un autre indice selon lequel l'interaction entre IND, NOX et DIS peut être de bons candidats pour améliorer le modèle.

TensorFlow

Dans cette section, vous allez estimer le classificateur linéaire avec l'API des estimateurs TensorFlow. Vous procéderez comme suit :

  • Préparer les données
  • Estimer un modèle de référence : Aucune interaction
  • Estimer un modèle avec interaction

N'oubliez pas que l'objectif de l'apprentissage automatique est de minimiser l'erreur. Dans ce cas, le modèle avec l’erreur quadratique moyenne la plus faible l’emportera. L'estimateur TensorFlow calcule automatiquement cette métrique.

Données de préparation

Dans la plupart des cas, vous devez transformer vos données. C’est pourquoi Facets Overview est fascinant. D’après les statistiques récapitulatives, vous avez constaté qu’il existe des valeurs aberrantes. Ces valeurs affectent les estimations car elles ne ressemblent pas à la population que vous analysez. Les valeurs aberrantes biaisent généralement les résultats. Par exemple, une valeur aberrante positive a tendance à surestimer le coefficient.

Une bonne solution pour résoudre ce problème consiste à standardiser la variable. La normalisation signifie un écart type de un et une moyenne de zéro. Le processus de normalisation comporte deux étapes. Tout d’abord, il soustrait la valeur moyenne de la variable. Deuxièmement, il divise par l’écart type afin que la distribution ait un écart type unitaire.

La bibliothèque sklearn est utile pour standardiser les variables. Vous pouvez utiliser le module de prétraitement avec l'échelle d'objet à cet effet.

Vous pouvez utiliser la fonction ci-dessous pour mettre à l'échelle un ensemble de données. Notez que vous ne mettez pas à l'échelle la colonne d'étiquette et les variables catégorielles.

from sklearn import preprocessing
def standardize_data(df): 
    X_scaled = preprocessing.scale(df[['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT']])
    X_scaled_df = pd.DataFrame(X_scaled, columns = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'])
    df_scale = pd.concat([X_scaled_df,
                       df['CHAS'],
                       df['PRICE']],axis=1, join='inner')
    return df_scale

Vous pouvez utiliser la fonction pour construire l'ensemble de train/test mis à l'échelle.

df_train_scale = standardize_data(df_train)
df_test_scale = standardize_data(df_test)

Régression de base : benchmark

Tout d’abord, vous entraînez et testez un modèle sans interaction. Le but est de voir la métrique de performance du modèle.

La façon de former le modèle est exactement comme le didacticiel sur API de haut niveau. Vous utiliserez l'estimateur TensorFlow LinearRegressor.

Pour rappel, vous devez choisir :

  • les fonctionnalités à mettre dans le modèle
  • transformer les fonctionnalités
  • construire le régresseur linéaire
  • construire la fonction input_fn
  • entraîner le modèle
  • tester le modèle

Vous utilisez toutes les variables de l'ensemble de données pour entraîner le modèle. Au total, il y a des variables continues de niveau et une variable catégorielle

## Add features to the bucket: 
### Define continuous list
CONTI_FEATURES  = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT']
CATE_FEATURES = ['CHAS']

Vous convertissez les fonctionnalités en colonne numérique ou en colonne catégorielle

continuous_features = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES]
#categorical_features = tf.feature_column.categorical_column_with_hash_bucket(CATE_FEATURES, hash_bucket_size=1000)
categorical_features = [tf.feature_column.categorical_column_with_vocabulary_list('CHAS', ['yes','no'])]

Vous créez le modèle avec le LinearRegressor. Vous stockez le modèle dans le dossier train_Boston

model = tf.estimator.LinearRegressor(    
	model_dir="train_Boston",     
    feature_columns=categorical_features + continuous_features)

Sortie

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train_Boston', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a19e76ac8>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

Chaque colonne des données de train ou de test est convertie en Tensor avec la fonction get_input_fn

FEATURES = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT', 'CHAS']
LABEL= 'PRICE'
def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
       x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
       y = pd.Series(data_set[LABEL].values),
       batch_size=n_batch,   
       num_epochs=num_epochs,
       shuffle=shuffle)

Vous estimez le modèle sur les données du train.

model.train(input_fn=get_input_fn(df_train_scale, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

Sortie

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train_Boston/model.ckpt.
INFO:tensorflow:loss = 56417.703, step = 1
INFO:tensorflow:global_step/sec: 144.457
INFO:tensorflow:loss = 76982.734, step = 101 (0.697 sec)
INFO:tensorflow:global_step/sec: 258.392
INFO:tensorflow:loss = 21246.334, step = 201 (0.383 sec)
INFO:tensorflow:global_step/sec: 227.998
INFO:tensorflow:loss = 30534.78, step = 301 (0.439 sec)
INFO:tensorflow:global_step/sec: 210.739
INFO:tensorflow:loss = 36794.5, step = 401 (0.477 sec)
INFO:tensorflow:global_step/sec: 234.237
INFO:tensorflow:loss = 8562.981, step = 501 (0.425 sec)
INFO:tensorflow:global_step/sec: 238.1
INFO:tensorflow:loss = 34465.08, step = 601 (0.420 sec)
INFO:tensorflow:global_step/sec: 237.934
INFO:tensorflow:loss = 12241.709, step = 701 (0.420 sec)
INFO:tensorflow:global_step/sec: 220.687
INFO:tensorflow:loss = 11019.228, step = 801 (0.453 sec)
INFO:tensorflow:global_step/sec: 232.702
INFO:tensorflow:loss = 24049.678, step = 901 (0.432 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train_Boston/model.ckpt.
INFO:tensorflow:Loss for final step: 23228.568.


<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a19e76320>

Enfin, vous estimez les performances du modèle sur l'ensemble de test

model.evaluate(input_fn=get_input_fn(df_test_scale, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

Sortie

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-29-02:40:43
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train_Boston/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-29-02:40:43
INFO:tensorflow:Saving dict for global step 1000: average_loss = 86.89361, global_step = 1000, loss = 1650.9785


{'average_loss': 86.89361, 'global_step': 1000, 'loss': 1650.9785}

La perte du modèle est de 1650. C'est la métrique à battre dans la section suivante

Améliorer le modèle : terme d'interaction

Lors de la première partie du didacticiel, vous avez constaté une relation intéressante entre les variables. Les différentes techniques de visualisation ont révélé qu'INDUS et NOS sont liés entre eux et ont pour effet d'amplifier l'effet sur le prix. Non seulement l’interaction entre INDUS et NOS affecte le prix, mais cet effet est également plus fort lorsqu’il interagit avec DIS.

Il est temps de généraliser cette idée et de voir si vous pouvez améliorer le modèle prédit.

Vous devez ajouter deux nouvelles colonnes à chaque ensemble de données : train + test. Pour cela, vous créez une fonction pour calculer le terme d’interaction et une autre pour calculer le terme d’interaction triple. Chaque fonction produit une seule colonne. Une fois les nouvelles variables créées, vous pouvez les concaténer à l’ensemble de données d’entraînement et à l’ensemble de données de test.

Tout d'abord, vous devez créer une nouvelle variable pour l'interaction entre INDUS et NOX.

La fonction ci-dessous renvoie deux dataframes, train et test, avec l'interaction entre var_1 et var_2, dans votre cas INDUS et NOX.

def interaction_term(var_1, var_2, name):
    t_train = df_train_scale[var_1]*df_train_scale[var_2]
    train = t_train.rename(name)
    t_test = df_test_scale[var_1]*df_test_scale[var_2]
    test = t_test.rename(name)
    return train, test

Vous stockez les deux nouvelles colonnes

interation_ind_ns_train, interation_ind_ns_test= interaction_term('INDUS', 'NOX', 'INDUS_NOS')
interation_ind_ns_train.shape
(325,)

Deuxièmement, vous créez une deuxième fonction pour calculer le terme de triple interaction.

def triple_interaction_term(var_1, var_2,var_3, name):
    t_train = df_train_scale[var_1]*df_train_scale[var_2]*df_train_scale[var_3]
    train = t_train.rename(name)
    t_test = df_test_scale[var_1]*df_test_scale[var_2]*df_test_scale[var_3]
    test = t_test.rename(name)
    return train, test
interation_ind_ns_dis_train, interation_ind_ns_dis_test= triple_interaction_term('INDUS', 'NOX', 'DIS','INDUS_NOS_DIS')

Maintenant que vous disposez de toutes les colonnes nécessaires, vous pouvez les ajouter à l’ensemble de données d’entraînement et de test. Vous nommez ces deux nouvelles trames de données :

  • df_train_new
  • df_test_new
df_train_new = pd.concat([df_train_scale,
                          interation_ind_ns_train,
                          interation_ind_ns_dis_train],
                         axis=1, join='inner')
df_test_new = pd.concat([df_test_scale,
                         interation_ind_ns_test,
                         interation_ind_ns_dis_test],
                         axis=1, join='inner')
df_train_new.head(5)

Sortie

Améliorer le terme d'interaction du modèle

C'est ça; vous pouvez estimer le nouveau modèle avec les termes d'interaction et voir quelle est la mesure des performances.

CONTI_FEATURES_NEW  = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT',
                       'INDUS_NOS', 'INDUS_NOS_DIS']
### Define categorical list
continuous_features_new = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES_NEW]
model = tf.estimator.LinearRegressor(
    model_dir="train_Boston_1", 
    feature_columns= categorical_features + continuous_features_new)

Sortie

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train_Boston_1', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a1a5d5860>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

CODE

FEATURES = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT','INDUS_NOS', 'INDUS_NOS_DIS','CHAS']
LABEL= 'PRICE'
def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
       x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
       y = pd.Series(data_set[LABEL].values),
       batch_size=n_batch,   
       num_epochs=num_epochs,
       shuffle=shuffle)
model.train(input_fn=get_input_fn(df_train_new, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

Sortie

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train_Boston_1/model.ckpt.
INFO:tensorflow:loss = 56417.703, step = 1
INFO:tensorflow:global_step/sec: 124.844
INFO:tensorflow:loss = 65522.3, step = 101 (0.803 sec)
INFO:tensorflow:global_step/sec: 182.704
INFO:tensorflow:loss = 15384.148, step = 201 (0.549 sec)
INFO:tensorflow:global_step/sec: 208.189
INFO:tensorflow:loss = 22020.305, step = 301 (0.482 sec)
INFO:tensorflow:global_step/sec: 213.855
INFO:tensorflow:loss = 28208.812, step = 401 (0.468 sec)
INFO:tensorflow:global_step/sec: 209.758
INFO:tensorflow:loss = 7606.877, step = 501 (0.473 sec)
INFO:tensorflow:global_step/sec: 196.618
INFO:tensorflow:loss = 26679.76, step = 601 (0.514 sec)
INFO:tensorflow:global_step/sec: 196.472
INFO:tensorflow:loss = 11377.163, step = 701 (0.504 sec)
INFO:tensorflow:global_step/sec: 172.82
INFO:tensorflow:loss = 8592.07, step = 801 (0.578 sec)
INFO:tensorflow:global_step/sec: 168.916
INFO:tensorflow:loss = 19878.56, step = 901 (0.592 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train_Boston_1/model.ckpt.
INFO:tensorflow:Loss for final step: 19598.387.


<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a1a5d5e10>
model.evaluate(input_fn=get_input_fn(df_test_new, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

Sortie

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-29-02:41:14
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train_Boston_1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-29-02:41:14
INFO:tensorflow:Saving dict for global step 1000: average_loss = 79.78876, global_step = 1000, loss = 1515.9863


{'average_loss': 79.78876, 'global_step': 1000, 'loss': 1515.9863}

La nouvelle perte est de 1515 . En ajoutant simplement deux nouvelles variables, vous avez pu diminuer la perte. Cela signifie que vous pouvez faire une meilleure prédiction qu’avec le modèle de référence.