Publié par et
Il y a 2 années · 18 minutes · Data

Les outils de la Data Science : Python Data Tools

logo_python.pngSuite de notre série d’articles de présentation des outils de la Data Science, nous présentons aujourd’hui Python. Python est un langage orienté objet bénéficiant d’une syntaxe précise et efficace. Il est couramment utilisé par les Data Scientists grâce à ses librairies d’analyse numérique et de calcul scientifique (numpy, scipy, pandas) et de visualisation (matplotlib), mais surtout grâce à sa puissante librairie dédiée au Machine Learning, scikit-learn.

Comment justifier que Python soit aujourd’hui l’un des langages les plus utilisés en Data Science? La réponse ne repose pas forcément dans la tuyauterie derrière le langage, mais plutôt qu’il soit en fait associé à un certain style de programmation plus proche de ce que recherchent les Ingénieurs de la Donnée, à savoir de pouvoir exprimer dans une syntaxe concise des concepts mathématiques tels que les vecteurs ou les matrices et les opérations associées. Il se rapproche en ce sens des logiciels de calcul scientifique tels que Matlab, mais ne se limite pas qu’à cela et possède des propriétés qui sont indispensables pour une intégration en entreprise, s’interfaçant très bien avec les services web et les bases de données.

Cet article a pour objectif d’introduire le lecteur à la programmation en Python, et à montrer quelques unes de ses possibilités sous l’angle de la Data Science.

Installer Python

Pour installer Python efficacement avec toutes les principales librairies nécessaires, le mieux est de s’orienter vers Anaconda, qui est une distribution gratuite de Python incluant près de 200 packages, et contient des installers à la fois pour Python 2.7 et 3.4.

Plusieurs solutions sont alors à disposition pour utiliser Python:

  • Des éditeurs de texte comme Emacs ou Vim
  • Des IDE comme Spyder ou PyCharm
  • Utiliser IPython Notebook: un environnement de calcul interactif en ligne où vous pouvez combiner l’exécution de code, le texte, les mathématiques (LaTeX), les graphes et les médias riches en un seul document.

Pour lancer le notebook, il suffit de taper les commandes suivantes dans votre console:

ipython notebook 

Bien que les principales librairies soient déjà installées avec Anaconda, il est possible que vous ayez besoin d’installer un package qui ne soit pas encore présent. Pour ce faire, il faut utiliser la commande conda ou pip comme suit:

conda install myPackage
pip install myPackage

Prendre en main Python et ses principales librairies

Nous allons vous montrer les commandes de base en Python, et faire un tour d’horizon des librairies essentielles en Python, notamment dans le cas d’une démarche en Data Science.

Les bases

Une fois dans le notebook, toute commande passée sera évaluée, et le résultat sera affiché

> print 1+1
2

On assigne de manière classique une valeur a une variable  à l’aide de l’opérateur “=”

> a = 45

La gestion des tableaux avec Numpy

Comme il a été expliqué en introduction de l’article, Python est un langage très puissant pour le calcul scientifique, car permettant de modéliser très simplement des outils mathématiques essentiels pour les Ingénieurs de la Donnée. Numpy est un des packages référence en Python pour ces aspects, et est de ce fait très utilisé dans le domaine du Machine Learning. Passons en revue quelques unes des caractéristiques les plus importantes de cette librairie.

Il est nécessaire d’importer au préalable la librairie pour avoir accès à ses fonctionnalités dans la console, souvent via une appellation donnée.

> import numpy as np

On a alors accès à toutes les fonctions de numpy en écrivant une commande du type np.someFunction.

Création de tableaux numpy

La création de tableaux à une ou plusieurs dimensions se fait de manière simple en numpy.

> a = np.array([1.0, 2.0, 3.0]) # Array à une dimension
> print a
[ 1. 2. 3.]

> b = np.array([[1, 2, 3], [4, 5, 6]]) # Array de dimension 2x3
> print b
[[1 2 3]
 [4 5 6]]

La création de tableaux à une ou plusieurs dimensions se fait de manière simple en numpy.

> zeros = np.zeros(5) # Array à une dimension rempli de 0
> print zeros
[ 0.  0.  0.  0.  0.]

> ones = np.ones(shape=(3, 4), dtype=np.int32) # Array de dimension 3x4 rempli de 1
> print ones
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

> random = np.random.randint(0, 10, (3, 4)) # Array de dimension 3x4 rempli d'entier compris entre 0 (inclu) et 10 (exclu)
> print random
[[0 7 2 4]
 [9 1 1 0]
 [3 8 5 7]]

Obtenir des informations sur les tableaux créés

Les méthodes shape et dtype permettent d’obtenir les dimensions et le type des éléments des tableaux.

> print b.shape
(2, 3)

> print a.dtype
float64

Accéder aux éléments d’un tableau

Une fois les arrays numpy créés, il deviens très simple d’accéder à un élément particulier, une ligne ou bien une colonne.

> print b[0, 0] # Accéder à un élément
1

> print b[1, :] # Accéder à une ligne (peut s'abréger en b[1])
[4 5 6]

> print b[:, 1]  # Accéder à une colone
[2 5]

Modifier le contenu d’un tableau

De même que pour l’accession, la modification du contenu d’un tableau peut se faire par élément, ligne ou colonne.

> b[0, 0] = 9 # Modification d’un élément
> print b
[[9 2 3]
 [4 5 6]]

> b[1] = [7,8,9] # Modification d’une ligne
> print b
[[9 2 3]
 [7 8 9]]

> b[:, 1] = [4,5] # Modification d’une colonne
> print b
[[9 4 3]
 [7 5 9]]

Attention cependant à bien respecter les dimensions des arrays pour ne pas provoquer d’erreur.

Calcul de statistiques sur les tableaux

Un des gros intérêts de la librairie numpy est de pouvoir réaliser très simplement de nombreuses statistiques sur les arrays créés. En voici quelques-unes.

> b.sum() # Somme de tous les éléments du tableau
37

> b.mean() # Moyenne de tous les éléments du tableau
6.166666666666667

> b.sum(axis=0) # Somme des colonnes du tableau
array([16,  9, 12])

> b.mean(axis=1) # Moyenne des lignes du tableau
array([ 5.33333333,  7.        ])

Pour aller plus loin concernant le calcul scientifique en Python, des tutoriaux sont disponibles ici.

La visualisation des données avec Matplotlib

Une autre partie importante Data Science est la visualisation des données. Nous allons utiliser pour cela la librairie matplotlib. Il s’agit d’un package extrêmement flexible , mais nous n’allons passer en revue que quelques notions de base ici.

Dans un notebook ipython, nous pouvons activer le mode « IPython inline », qui fera apparaître les graphiques en ligne dans le bloc-notes .

> %matplotlib inline
> import matplotlib.pyplot as plt
> import numpy as np
Une large palette de graphes est réalisable avec matplotlib, visibles ici, avec les codes correspondants. En voici quelques uns.

Courbe

> x = np.linspace(0, 10, 100)
> y = np.cos(x)
> plt.plot(x, y);

Nuage de points

> x = np.random.normal(size=500)
> y = np.random.normal(size=500)
> plt.scatter(x, y);

Histogramme

> mu = 100 # moyenne de la distribution
> sigma = 15 # déviation standard de la distribution
> x = mu + sigma * np.random.randn(10000)
> plt.hist(x, bins=50);

Afficher une image

> x = np.linspace(1, 12, 100)
> y = x[:, np.newaxis]
> im = y * np.sin(x) * np.cos(y)
> plt.imshow(im); # Origine dans le coin supérieur gauche
> plt.contour(im); # Origine dans le coin inférieur gauche

             

3D

Il est aussi possible de faire des figures en 3 dimensions, un peu plus difficiles à paramétrer.

> from mpl_toolkits.mplot3d import Axes3D
> ax = plt.axes(projection='3d')
> xgrid, ygrid = np.meshgrid(x, y.ravel())
> ax.plot_surface(xgrid, ygrid, im, cmap=plt.cm.jet, cstride=2, rstride=2, linewidth=0);

Finalement, si vous souhaitez créer des graphiques interactifs, nous vous conseillons de vous tourner vers la récente librairie bokeh, basée sur de la génération de code en D3.js.

La manipulation des données avec Pandas

Comme on l’a vu, Numpy est un outil efficace pour la manipulation de tableaux, mais reste cependant très bas niveau et peu pratique pour manipuler des données hétérogènes. Dans la pratique, la librairie Pandas est plus adaptée car propose des structures de données et de nombreux outils, faciles à utiliser, pour manipuler ce genre de données en Python. Pandas utilise du Numpy et du Matplotlib dans sa construction.

> import pandas as pd
> import numpy as np
> import matplotlib.pyplot as plt

Series

Une Series est un tableau à une dimension (ie: un vecteur) de variables labélisées de n’importe quel type (integers, strings, floating point numbers, Python objects, etc.). L’axe des labels d’une Series se nomme l’index.

Pandas va créer un index par défaut lors de la création de la Series.

> s = pd.Series([1,3,5,np.nan,6,8])
> s
0     1
1     3
2     5
3   NaN
4     6
5     8
dtype: float64
On peut aussi spécifier les index.
> s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
> s
a    1.373563
b   -0.211365
c   -1.867391
d   -0.168264
e   -1.040205
dtype: float64

DataFrame

Un DataFrame est une structure de données à 2 dimensions avec des colonnes labélisées, potentiellement de différents types. On peut voir un DataFrame comme une feuille de calcul, une table SQL, ou un dictionnaire (ie: une map) d’objets Series. On peut créer un DataFrame à partir de nombreux types de sources.

A partir d’un tableau numpy.

> df = pd.DataFrame(np.random.randint(0, 10, (6,4)),index=('a', 'b', 'c', 'd', 'e', 'f'), columns=('A','B','C','D'))
> df

A partir d’un dictionnaire d’objets pouvant être interprétés comme une Series.

> df2 = pd.DataFrame({ 'A' : 1.,
                     'B' : pd.Timestamp('20130102'),
                     'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
                     'D' : np.array([3] * 4,dtype='int32'),
                     'E' : 'foo' })
> df2

En chargeant un fichier csv.

> data = pd.read_csv('titanic/train.csv') # Attention, chargez un fichier csv disponible !
> data.head() # Affiche les 5 premières lignes

Utilisation des DataFrames

La méthode describe permet d’afficher un résumé des statistiques de vos données.

> df.describe()

  • count indique le nombre de cellules non vides par colonnes
  • mean indique la moyenne par colonnes
  • std indique la déviation standard par colonnes
  • min indique le minimum par colonnes
  • 25% indique la valeur du 25ème centile par colonnes
  • 50% indique la médiane par colonnes
  • 75% indique la valeur du 75ème centile par colonnes
  • max indique le maximum par colonnes

Les méthodes suivantes permettent de récupérer l’index, les colonnes ou les données sous forme d’array numpy.

> print df.index
Index([u'a', u'b', u'c', u'd', u'e', u'f'], dtype='object')

> print df.columns
Index([u'A', u'B', u'C', u'D'], dtype='object')

> print df.values
[[9 3 3 4]
 [7 3 4 3]
 [7 9 7 8]
 [3 5 3 5]
 [7 1 4 3]
 [7 1 0 7]]

Accéder à une colonne sous forme d’une Series (deux possibilités).

> df['A']
> df.A
a    9
b    7
c    7
d    3
e    7
f    7
Name: A, dtype: int64
Sélectionner des colonnes, sous forme de DataFrame.
> df[['A','C']]

Sélection par label.

> df.loc['a'] # la ligne indéxée par 'a' sous forme de Serie
A    9
B    3
C    3
D    4
Name: a, dtype: int64
 
> df.loc['a','A'] # l'élément indexé par 'a' de la colonne 'A'
9

> df.loc[:,['A','B']]  # toutes les lignes des colonnes 'A' et 'B' sous forme de DataFrame
> df.loc['a':'c',['A','B']] # les lignes indexées entre 'a' et 'c' des colonnes 'A' et 'B' sous forme de DataFrame

        

Sélection par position.

> df.iloc[3] # Quatrième ligne
A    3
B    5
C    3
D    5
Name: d, dtype: int64
 
> df.iloc[1,1] # L'élement scalaire de la deuxième ligne, deuxième colonne
3

> df.iloc[3:5,0:2]
> df.iloc[[1,2,3],[0,2]]

Indéxation booléenne.

> df.A > 5 # Créer une Series de type boolean à l'aide d'une expression
a     True
b     True
c     True
d    False
e     True
f     True
Name: A, dtype: bool

> df[df.A > 5] # Classer un DataFrame selon une colonne

Modification des DataFrames

Ajout d’une colonne.

> df['F'] = [1, 2, 3, 4, 5, 6]
> df

Classer un DataFrame selon une colonne.

> df.sort(columns='B')

Le Machine Learning avec scikit-learn

Créé en 2007, Scikit-Learn est l’une des librairies open-source les plus populaires pour le Machine Learning en Python. La librairie est construite à partir de numpy, matplotlib et scipy, et s’interface aussi avec des dataframes pandas.

En plus de contenir et de rendre accessible facilement tous les principaux algorithmes de Machine Learning (classification, clustering, régression), elle contient aussi de nombreux modules pour la réduction de dimension,  le processing des données et l’évaluation des modèles.

Une excellente documentation

Que l’on débute dans la Data Science ou bien que l’on soit un utilisateur expérimenté, la documentation attachée à scikit-learn est d’un recours très efficace. Toutes les méthodes sont bien documentées, et l’on peut trouver de très nombreux exemples d’utilisation pour tous types de tâches.

La documentation fournit même des conseils quant à l’utilisation de tel ou tel modèle de Machine Learning en fonction de vos besoins et de vos données disponibles, sous forme d’un schéma global facile à utiliser.

 

 

 

Utilisation simple des algorithmes grâce à une API consistante

La plupart des algorithmes de scikit-learn utilisent des jeux de données sous forme de tableaux (ou de matrices) à deux dimensions. Ces tableaux vont être soit du type numpy.ndarray de la librairie numpy que nous verrons par la suite ou de type scipy.sparse de la librairie scipy. La dimension de cette matrice sera [n_samples, n_features], avec:

  • n_samples: Le nombre d’échantillons de données ou d’observations. Un échantillon peut représenter un document, une image, un son, une vidéo, un objet, une ligne dans une base de données ou un fichier csv
  • n_features: Le nombre de caractéristiques qui décrivent une observation de manière quantitative. Ces données doivent être des nombres (réels ou entiers)

Dans le cadre d’un apprentissage supervisé, on represente les données sous la forme d’une feature matrix et d’un label vector:

             

L’interface

La plupart des opérations vont être réalisées à l’aide d’objets de type estimator. Un algorithme de Machine Learning correspond à une classe de type estimator:

> from sklearn.linear_model import LinearRegression
> model = LinearRegression(normalize=True)
> print model
LinearRegression(copy_X=True, fit_intercept=True, normalize=True)

scikit-learn s’efforce d’avoir une interface uniforme pour tous les algorithmes, ce qui est une de ses plus grandes forces. Étant donné un objet estimator model, vous pouvez utiliser les méthodes suivantes:

  • Pour tous les estimators
    • model.fit() : lance le mécanisme d’apprentissage.
      • model.fit(X, y) pour les algorithmes supervisés (X les observations d’entraînement, y leurs labels)
      • model.fit(X) pour les algorithmes non-supervisés
  • Les estimators supervisés
    • model.predict(X_new) : prédit et retourne les labels d’un nouveau jeu de données X_new
    • model.predict_proba(X_new) : pour les algorithmes de classification, prédit et retourne les probabilités d’appartenance à une classe d’un nouveau jeu de données X_new
    • model.score(X_test, y_test) : Retourne un score de performance du modèle entre 0 (mauvais) et 1 (idéal mais suspicieux)
  • Les estimators non-supervisés
    • model.transform(X_new) : transforme un jeu de données selon le modèle
    • model.fit_transform(X) : apprend ses paramètres grâce à un jeu de données et transforme celui-ci.

Mise en situation

Tout comme dans le précédent article présentant R, nous allons utiliser le dataset Iris pour présenter l’utilisation d’un algorithme de Machine Learning en Python.

scikit-learn embarque ce jeu de données et propose des fonctions pour charger celles-ci dans des tableaux numpy.

> from sklearn.datasets import load_iris
> iris = load_iris()

Les données disponibles sont les suivantes:

  • Les features de l’Iris dataset:
    1. longueur d’un sépale en cm
    2. largeur d’un sépale en cm
    3. longueur d’un pétale en cm
    4. largeur d’un pétale en cm
  • Les classes qu’il faudra prédire:
    1. Iris Setosa
    2. Iris Versicolour
    3. Iris Virginica
iris est un objet de type Bunch (spécifique aux jeux de données dans scikit-learn). Les features de chaque fleurs sont stockées dans l’attribut data de notre dataset, les types cibles dans l’attribut target et leurs noms dans l’attribut target_names:
> n_samples, n_features = iris.data.shape
> print n_samples
150

> print n_features
4

> print iris.data[0]
[ 5.1  3.5  1.4  0.2]

> print iris.target
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

> print iris.target_names
['setosa' 'versicolor' 'virginica']
Observons les données en utilisant uniquement deux features de notre dataset:
> x_index = 0
> y_index = 1
> plt.scatter(iris.data[:, x_index], iris.data[:, y_index], c=iris.target)
> plt.xlabel(iris.feature_names[x_index])
> plt.ylabel(iris.feature_names[y_index])

Notre objectif ici va être de créer un modèle de prédiction de la classe d’appartenance des iris. Pour cela, nous allons utiliser un algorithme classique (et simple) de Machine Learning: Les K-Nearest Neighbors (K-NN). Pour faire une prédiction sur une nouvelle donnée, cet algorithme va trouver les K points les plus proches, et retourner la classe la plus représentée comme résultat. Pour plus d’informations sur cet algorithme et son utilisation dans scikit-learn, vous pouvez vous référer à la documentation suivante.

Afin de tester nos performances en prédiction, nous allons au préalable séparer notre dataset en deux : Un premier set que l’on va appeler train set, qui va constituer notre base d’apprentissage (les données dont on connaît la classe), et un deuxième appelé test set, sur lequel on va tester les performances de l’algorithme (on fait donc comme si on ne connaissait pas la classe, puis on peut comparer la prédiction à la classe réelle).

La séparation peut être faite de manière très simple en scikit-learn :

> from sklearn.cross_validation import train_test_split
> X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.4)

Ici, nous avons retiré 40% de notre dataset initial pour en faire notre test set. Nous pouvons maintenant construire notre modèle sur le train set, en spécifiant le nombre K de voisins que l’on souhaite étudier à chaque fois (il y a d’autres paramètres qu’il est possible de donner, tels que la distance utilisée, voir la documentation pour plus d’informations).

> from sklearn.neighbors import KNeighborsClassifier
> knn = KNeighborsClassifier(n_neighbors=5)
> knn.fit(X_train, y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_neighbors=5, p=2, weights='uniform')
On peut alors calculer la prédiction pour les données présentes dans le test set, et construire ce que l’on appelle une confusion matrix, qui est une matrice contenant le nombre de bonnes classifications sur la diagonale, et le nombre de mauvaise classification pour chaque classe dans les autres éléments.
> from sklearn.metrics import confusion_matrix
> y_pred = knn.predict(X_test)
> confusion_matrix(y_test, y_pred)
array([[23,  0,  0],
       [ 0, 19,  0],
       [ 0,  1, 17]])
Le score global de classification peut être calculé de la manière suivante:
> knn.score(X_test, y_test)
0.98333333333333328
On obtient un score de 98,3%, ce qui est un très bon résultat, qui peut éventuellement être amélioré en changeant le nombre K de voisins ou les autres paramètres disponibles pour ce modèle.

Pour aller plus loin

Comme on l’a dit précédemment, de nombreux algorithmes de Machine Learning sont implémentés dans scikit-learn, ce qui en fait une de ses plus grandes forces. Il est alors très simple de tester différents algorithmes pour un problème donné.

De plus, afin de trouver les meilleurs paramètres à utiliser pour un modèle donné, il est possible d’utiliser directement un Grid Search, qui va tester toutes les combinaisons possibles des paramètres que l’on a rentré. C’est en pratique une très bonne méthode pour obtenir les meilleurs résultats possibles pour un modèle donné. Vous trouverez la documentation correspondante ici.

Conclusion

Python est un langage très couramment utilisé par les Data Scientists, nous avons vu pourquoi grâce à ses différentes librairies. Notamment avec la librairie scikit-learn, tout est mis en place pour faciliter le travail de l’utilisateur lors de la mise en place des modèles. De plus, pour des problématiques de Big Data, le projet Spark (très en vogue en ce moment) propose une API en Python, appelée PySpark, montrant l’importance de ce langage dans le monde de la Data Science.

Sources

Cet article s’inspire fortement des présentations suivantes (en anglais) :

– PyCon 2014 scikit-learn tutorial par Jake Vanderplas
– Tutorial on scikit-learn and IPython for parallel machine learning par Olivier Grisel

Vous pouvez également retrouver le notebook ipython correspondant à cet article ici :

https://github.com/mblanc/hands-on-scikit-learn

Yoann Benoit
Yoann est Data Scientist chez Xebia depuis près de deux ans. Il intervient sur de nombreux sujets autour de la Data Science et du Big Data, allant de la collecte, du traitement et de l'analyse des données jusqu'à la mise en production de pipelines complets de Machine Learning. Speaker et rédacteur à la fois sur les concepts et les technologies liées à la Data Science, il travaille principalement avec Python, Scala et Spark. Il intervient de plus en tant que formateur sur l'Analyse de Données et le Machine Learning sur Spark.

2 réflexions au sujet de « Les outils de la Data Science : Python Data Tools »

  1. Publié par Hermann Gaétan, Il y a 1 année

    Merci pour ce tutoriel, il est bien détaillé et donne vraiment les bases sur la Data science avec Python.
    Ne serait il pas possible de concevoir des exerces ou cas pratriques, qui nous permettront de mieux appréhender le domaine?

    Merci une fois de plus!

  2. Publié par dieme, Il y a 4 mois

    bonjour,

    je vous remercie pour tutoriel je viens de lire. c’est instructif je suis débutant. merci

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *