Vous êtes sur la page 1sur 13

Cours Cnam RCP208

P R É C É D E N T | S U I VA N T | I N D E X

T A B L E DE S M A T I È R E S
Travaux pratiques - Introduction à Scikit-learn
Préambule
(correspond à 1 séance de TP) Installation de scikit-learn
Références externes utiles :
Cours - Introduction

◾ Documentation NumPy Travaux pratiques - Introduction à


◾ Documentation SciPy Python
◾ Documentation Matplotlib Travaux pratiques - Introduction à
◾ Site scikit-learn Scikit-learn
◾ Site du langage python
Librairies indispensables

Calculs avec NumPy et SciPy


Librairies indispensables
Visualisation avec Matplotlib

Calculs avec NumPy et SciPy Introduction à Scikit-learn

Charger et sauvegarder des


NumPy et SciPy sont des librairies très utiles dans la résolution de problèmes de modélisation
données
à partir de données. Cette séance de TP vise à vous donner les connaissances de base
nécessaires mais est loin de couvrir toutes les fonctionnalités de ces deux librairies. Pour aller Prétraiter des données
plus loin, vous êtes invités à regarder les documentations en ligne indiquées plus haut. Générer des données

Construire des modèles


NumPy
Charger et sauvegarder des
L’utilisation de fonctionnalités de NumPy commence par l’importation de cette librairie modèles

Cours - Méthodes factorielles


>>> import numpy as np
Travaux pratiques - Analyse en
L’emploi de raccourcis (ici np plutôt que numpy ) permet de faciliter l’écriture des appels des composantes principales
fonctions de la librairie. Travaux pratiques - Analyse factorielle
Le type de base dans NumPy est le tableau unidimensionnel ou multidimensionnel composé discriminante
d’éléments de même type. La classe correspondante est ndarray , à ne pas confondre avec la
Cours - Classification automatique
classe Python array.array qui gère seulement des tableaux unidimensionnels (et présente des
Travaux pratiques - K-means
fonctionalités comparativement limitées).
Principaux attributs de ndarray : Travaux pratiques - Classification
spectrale
ndarray.ndim dimension du tableau (nombre d’axes)
Cours - Estimation de densité
ndarray.shape tuple d’entiers indiquant la taille dans chaque dimension ; ex : une
matrice à n lignes et m colonnes : (n,m) Travaux pratiques - Estimation de
densité par noyaux
ndarray.size nombre total d’éléments du tableau
ndarray.dtype type de (tous) les éléments du tableau ; il est possible d’utiliser les types Travaux pratiques - Modèles de
prédéfinis comme numpy.int64 ou numpy.float64 ou définir de nouveaux mélange

types Cours - Données manquantes


ndarray.data les données du tableau ; en général, pour accéder aux données d’un
Travaux pratiques - Données
tableau on passe plutôt par les indices
manquantes

Cours - Quantification vectorielle,


Création de tableaux
cartes de Kohonen
De nombreuses méthodes de création de tableaux sont disponibles. D’abord, un tableau peut
être créé à partir d’une liste (ou d’un tuple) Python, à condition que tous les éléments soient TP - Introduction à Matlab.
de même type (le type des éléments du tableau est déduit du type des éléments de la liste ou Quantification vectorielle, cartes de
tuple) : Kohonen

Cours - Réseaux de neurones


>>> ti = np.array([1, 2, 3, 4])
multicouches
>>> ti
array([1, 2, 3, 4]) TP - Réseaux de neurones
>>> ti.dtype multicouches
dtype('int64')
>>> tf = np.array([1.5, 2.5, 3.5, 4.5]) RECHERCHE
>>> tf.dtype
dtype('float64') Go

À partir des listes simples sont produits des tableaux unidimensionnels, à partir des listes de
listes (de même taille) des tableaux bidimensionnels, et ainsi de suite. Par exemple :

>>> tf2d = np.array([[1.5, 2, 3], [4, 5, 6]])


>>> tf2d
array([[ 1.5, 2. , 3. ],
[ 4. , 5. , 6. ]])

Le type du tableau peut être indiqué explicitement à la création, des conversions sont
effectuées pour les valeurs fournies :

>>> tff = np.array([[1, 2, 3], [4, 5, 6]], dtype=float)


>>> tff
array([[ 1., 2., 3.],
[ 4., 5., 6.]])
>>> tfi = np.array([[1.5, 2, 3], [4, 5, 6]], dtype=int)
>>> tfi
array([[1, 2, 3],
[4, 5, 6]])
>>> tfi.dtype
dtype('int64')
>>> tfi.shape
(2, 3)
>>> tfi.ndim
2
>>> tfi.size
6

Il est souvent nécessaire de créer des tableaux remplis de 0, de 1, ou dont le contenu n’est
pas initialisé. Par défaut, le type des tableaux ainsi créés est float64 .

>>> tz2d = np.zeros((3,4))


>>> tz2d
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
>>> tu2d = np.ones((3,4))
>>> tu2d
array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]])
>>> id2d = np.eye(5)
>>> id2d
...
>>> tni2d = np.empty((3,4))
...

Question :
Expliquez les deux derniers résultats obtenus.

Correction :
Le premier tableau id2d représente une matrice identité d’ordre 5, le second tableau tni2d
représente une matrice non initialisée à 3 lignes et 4 colonnes.

>>> id2d
array([[ 1., 0., 0., 0., 0.],
[ 0., 1., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.]])

Des tableaux peuvent être initialisés aussi par des séquences générées, par exemple :

>>> ts1d = np.arange(0, 40, 5)


>>> ts1d
array([ 0, 5, 10, 15, 20, 25, 30, 35])
>>> ts1d2 = np.linspace(0, 35, 8)
>>> ts1d2
array([ 0., 5., 10., 15., 20., 25., 30., 35.])
>>> ta2d = np.random.rand(3,5)
>>> ta2d
array([[ 0.80125647, 0.6638199 , 0.77308665, 0.97916913, 0.34123528],
[ 0.50651726, 0.75819493, 0.20378306, 0.31850636, 0.57625289],
[ 0.9262173 , 0.80369567, 0.10563466, 0.17166009, 0.87835762]])

Question :
Quel est le résultat de l’appel np.random.rand(3,5) ? Regardez la documentation NumPy (voir
lien au début du TP).

Correction :
Construction d’un tableau à trois lignes et 5 colonnes, dont les éléments sont initialisés par
tirage aléatoire suivant une loi normale uniforme avec des valeurs dans l’intervalle [0, 1] .

Question :
Générez le contenu d’un tableau de même taille (3, 5) à partir plutôt d’une loi normale (de
moyenne 0 et variance 1).

Correction :
C’est la fonction .randn() qui doit être employée à la place.

Les tableaux peuvent être redimensionnés en utilisant reshape :

>>> tr = np.arange(20)
>>> tr
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
>>> tr.reshape(4,5)
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
>>> tr.reshape(2,10)
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
>>> tr.reshape(20)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])

Affichage des tableaux


Les tableaux unidimensionnels sont affichés comme des listes, les tableaux bidimensionnels
comme des matrices et les tableaux tridimensionnels comme des listes de matrices :

>>> ta1d = np.random.rand(5)


>>> ta1d
array([ 0.68431206, 0.22183178, 0.50668827, 0.40924377, 0.35185467])
>>> ta3d = np.random.rand(2,3,5)
>>> ta3d
array([[[ 0.95296683, 0.29799573, 0.68039431, 0.02477835, 0.65279665],
[ 0.16992877, 0.97304981, 0.60438211, 0.80814027, 0.15760128],
[ 0.46524801, 0.08403727, 0.98666534, 0.55898704, 0.02411968]],

[[ 0.84381192, 0.10907378, 0.84935009, 0.53024827, 0.57566448],


[ 0.60970992, 0.86396462, 0.55000945, 0.47922195, 0.36945843],
[ 0.87864068, 0.77920333, 0.53799669, 0.63145466, 0.28022316]]])

Si un tableau est considéré trop grand pour être affiché en entier, NumPy affiche le début et la
fin, avec des ... au milieu :

>>> ta2d = np.random.rand(30,50)


>>> ta2d
array([[ 0.08350917, 0.38925592, 0.35106269, ..., 0.70428592,
0.42510307, 0.83276118],
[ 0.00582013, 0.76582907, 0.02229477, ..., 0.47484366,
0.51582442, 0.58890372],
[ 0.78034243, 0.26834462, 0.83586084, ..., 0.74997071,
0.99517732, 0.8835053 ],
...,
[ 0.34286223, 0.33289184, 0.54428012, ..., 0.6694786 ,
0.27162091, 0.12956407],
[ 0.57198826, 0.86614192, 0.45765978, ..., 0.08197879,
0.6850151 , 0.07589935],
[ 0.75858312, 0.02430082, 0.4284809 , ..., 0.69458469,
0.67047361, 0.2623298 ]])
Accès aux composantes d’un tableau, extraction de parties d’un tableau
Nous avons déjà lors du TP précédent vu l’utilisation de : pour définir des intervalles d’indices
dans l’accès à des listes. L’utilisation pour les tableaux unidimensionnels est similaire :

>>> tr
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
>>> tr[:6]
array([0, 1, 2, 3, 4, 5])
>>> tr[:6:2] # la dernière valeur indique le pas de l'échantillonnage
array([0, 2, 4])
>>> a = tr[:2]
>>> a
array([0, 1])
>>> a[0] = 3
>>> tr
array([ 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])

Les données ne sont pas copiées de tr vers un nouveau tableau a , la modification d’un
élément de a avec a[0] = 3 change aussi le contenu de tr[0] . Pour obtenir une copie il faut
utiliser copy() :

>>> a = tr[:2].copy()
>>> a
array([3, 1])
>>> a[0] = 0
>>> a
array([0, 1])
>>> tr
array([ 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])

On peut procéder de la même façon pour les tableaux multidimensionnels :

>>> ta2d = np.random.rand(3,5)


>>> ta2d
array([[ 0.27681055, 0.98760001, 0.44322499, 0.65422127, 0.21553808],
[ 0.0691005 , 0.09843615, 0.62915029, 0.58226529, 0.28827975],
[ 0.44979767, 0.30371289, 0.77210828, 0.30087438, 0.95948081]])
>>> ta2d[0,0]
0.27681054817098449
>>> ta2d[0,:]
array([ 0.27681055, 0.98760001, 0.44322499, 0.65422127, 0.21553808])
>>> ta2d[0]
array([ 0.27681055, 0.98760001, 0.44322499, 0.65422127, 0.21553808])
>>> ta2d[:,0]
array([ 0.27681055, 0.0691005 , 0.44979767])
>>> ta2d[:2,:2]
array([[ 0.27681055, 0.98760001],
[ 0.0691005 , 0.09843615]])

Question :
Faites l’extraction des colonnes impaires de ta2d .

Correction :
Toutes les lignes (donc :, ), la première colonne est 1 et on va jusqu’au bout avec un pas de
2 (donc 1::2 ) :

>>> ta2d[:,1::2]
array([[ 0.98760001, 0.65422127],
[ 0.09843615, 0.58226529],
[ 0.30371289, 0.30087438]])

Pour les tableaux multidimensionnels, lors des itérations c’est le dernier indice qui change le
plus vite, ensuite l’avant-dernier, et ainsi de suite. Par exemple, pour les tableaux
bidimensionels c’est l’indice de colonne qui change d’abord et ensuite celui de ligne (le tableau
est lu ligne après ligne) :

>>> for x in ta2d:


print(x)
[ 0.27681055 0.98760001 0.44322499 0.65422127 0.21553808]
[ 0.0691005 0.09843615 0.62915029 0.58226529 0.28827975]
[ 0.44979767 0.30371289 0.77210828 0.30087438 0.95948081]

Lecture et écriture des données d’un tableau


Les fonctions de lecture / d’écriture de tableaux depuis /dans des fichiers sont variées, nous
regarderons rapidement deux des plus simples et plus rapides car les fichiers de données ont
en général des formats assez simples.
D’abord, ouvrez une autre fenêtre terminal et entrez wget
http://cedric.cnam.fr/~crucianm/src/geyser.txt . Vérifiez que le fichier a bien été enregistré dans le
répertoire et affichez les 10 premières lignes du fichier avec head geyser.txt . Ces commandes
sont valables pour Linux et MacOS, sous Windows il faudra télécharger le fichier
manuellement.
La fonction numpy.loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None,
skiprows=0, usecols=None, unpack=False, ndmin=0) , qui retourne un ndarray , réalise une lecture à
partir d’un fichier texte et est bien adaptée aux tableaux bidimensionnels ; chaque ligne de
texte doit contenir un même nombre de valeurs. Les principaux paramètres sont :

◾ fname : fichier ou chaîne de caractères ; si le fichier a une extension .gz ou .bz2 , il est
d’abord décompressé.
◾ dtype : type, optionnel, float par défaut.
◾ comments : chaîne de caractères, optionnel, indique une liste de caractères employée
dans le fichier pour précéder des commentaires (à ignorer lors de la lecture).
◾ delimiter : chaîne de caractères, optionnel, indique la chaîne de caractères employée
pour séparer des valeurs, par défaut “ “ (l’espace).
◾ converters : dictionnaire, optionnel, pour permettre des conversions.
◾ skiprows : entier, optionnel, pour le nombre de lignes à sauter en début de fichier
(par défaut 0).
◾ usecols : séquence, optionnel, indique les colonnes à lire ; par ex. usecols = [1,4,5]
extrait la 2ème, 5ème et 6ème colonne ; par défaut toutes les colonnes sont
extraites.
◾ unpack : booléen, optionnel, false par défaut ; si true , le tableau est transposé.
◾ ndmin : entier, optionnel, le tableau a au moins ndmin dimensions ; par défaut 0 .

(voir http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html)
Utilisation :

>>> geyser = np.loadtxt('geyser.txt', delimiter=' ')


>>> geyser.shape
(272, 2)
>>> geyser[:10,:]
array([[ 3.6 , 79. ],
[ 1.8 , 54. ],
[ 3.333, 74. ],
[ 2.283, 62. ],
[ 4.533, 85. ],
[ 2.883, 55. ],
[ 4.7 , 88. ],
[ 3.6 , 85. ],
[ 1.95 , 51. ],
[ 4.35 , 85. ]])

Une fonction plus flexible est genfromtxt , vous pouvez regarder son utilisation dans la
documentation.
La fonction numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='',
comments='# ') permet d’écrire un tableau dans un fichier texte. Les paramètres sont :

◾ fname : fichier ; si le fichier a une extension .gz ou .bz2 , il est compressé.


◾ X : le tableau à écrire dans le fichier texte.
◾ fmt : chaîne de caractères, optionnel ; indique le formatage du texte écrit.
◾ delimiter : chaîne de caractères, optionnel, indique la chaîne de caractères employée
pour séparer des valeurs, par défaut `` `` (l’espace).
◾ newline : chaîne de caractères, optionnel, indique le caractère à employer pour
séparer des lignes.
◾ header : chaîne de caractères, optionnel, indique le commentaire à ajouter au début
du fichier.
◾ footer : chaîne de caractères, optionnel, indique le commentaire à ajouter à la fin du
fichier.
◾ comments : caractère à ajouter avant header et footer pour en faire des commentaires
; par défaut # .

(voir http://docs.scipy.org/doc/numpy/reference/generated/numpy.savetxt.html)
Utilisation :

>>> np.savetxt('geyserv_nouveau.txt', geyser, delimiter=', ')

Dans une autre fenêtre terminal, affichez les 10 premières lignes du fichier enregistré avec
head geyserv_nouveau.txt .

Autres opérations d’entrée et sortie :

◾ fromfile(file[, dtype, count, sep]) : Construction d’un tableau à partir d’un fichier
texte ou binaire.
◾ fromregex(file, regexp, dtype) : Construction d’un tableau à partir d’un fichier texte,
avec un parseur d’expressions régulières.
◾ genfromtxt() : Fonction plus flexible pour la construction d’un tableau à partir d’un
fichier texte, avec une gestion des valeurs manquantes.
◾ load(file[, mmap_mode, allow_pickle, ...]) : Lecture de tableaux (ou autres objets) à
partir de fichiers .npy , .npz ou autres fichiers de données sérialisées.
◾ loadtxt(fname[, dtype, comments, delimiter, ...]) : Lecture de données à partir d’un
fichier texte.
◾ ndarray.tofile(fid[, sep, format]) : Ecriture d’un tableau dans un fichier texte ou
binaire (par défaut).
◾ save(file, arr[, allow_pickle, fix_imports]) : Ecriture d’un tableau dans un fichier
binaire de type .npy .
◾ savetxt(fname, X[, fmt, delimiter, newline, ...]) : Ecriture d’un tableau dans un fichier
texte.
◾ savez(file, *args, **kwds) : Ecriture de plusieurs tableaux dans un fichier de type .npz
sans compression.
◾ savez_compressed(file, *args, **kwds) : Ecriture de plusieurs tableaux dans un fichier de
type .npz avec compression.

Voir http://docs.scipy.org/doc/numpy/neps/npy-format.html pour le format des fichiers de


type .npy et .npz .

Opérations simples sur les tableaux


Concaténation de tableaux bidimensionnels :

>>> tu2d = np.ones((2,2))


>>> tu2d
array([[ 1., 1.],
[ 1., 1.]])
>>> tb2d = np.ones((2,2))*2
>>> tb2d
array([[ 2., 2.],
[ 2., 2.]])
>>> tcl = np.concatenate((tu2d,tb2d))
>>> tcl
array([[ 1., 1.],
[ 1., 1.],
[ 2., 2.],
[ 2., 2.]])
>>> tcl = np.concatenate((tu2d,tb2d),axis=0) # ou np.vstack
>>> tcl
array([[ 1., 1.],
[ 1., 1.],
[ 2., 2.],
[ 2., 2.]])
>>> tcl = np.concatenate((tu2d,tb2d),axis=1) # ou np.hstack
>>> tcl
array([[ 1., 1., 2., 2.],
[ 1., 1., 2., 2.]])

Ajouter un tableau unidimensionnel comme colonne à un tableau bidimensionnel :

>>> from numpy import newaxis


>>> tu1d = np.ones(2)
>>> tu1d
array([ 1., 1.])
>>> tu1d[:,newaxis]
array([[ 1.],
[ 1.]])
>>> np.column_stack((tu1d[:,newaxis],tb2d))
array([[ 1., 2., 2.],
[ 1., 2., 2.]])
>>> np.hstack((tu1d[:,newaxis],tb2d))
array([[ 1., 2., 2.],
[ 1., 2., 2.]])

Opérations arithmétiques élément par élément :

>>> tsomme = tb2d - tu1d


>>> tsomme
array([[ 1., 1.],
[ 1., 1.]])
>>> tb2d*5
array([[ 10., 10.],
[ 10., 10.]])
>>> tb2d**2
array([[ 4., 4.],
[ 4., 4.]])
>>> tc = np.hstack((tb2d,tu1d[:,newaxis]))
>>> tc
array([[ 2., 2., 1.],
[ 2., 2., 1.]])
>>> tc > 1
array([[ True, True, False],
[ True, True, False]], dtype=bool)
>>> tb2d * tb2d
array([[ 4., 4.],
[ 4., 4.]])
>>> tb2d *= 3
>>> tb2d
array([[ 6., 6.],
[ 6., 6.]])
>>> tb2d += tu2d
>>> tb2d
array([[ 7., 7.],
[ 7., 7.]])
>>> tb2d.sum()
28.0
>>> geyser = np.loadtxt('geyser.txt', delimiter=' ')
>>> geyser.min()
1.6000000000000001
>>> geyser.max()
96.0
>>> geyser.sum()
20232.676999999996
>>> geyser.sum(axis=0)
array([ 948.677, 19284. ])
>>> geyser.sum(axis=1)
...

Algèbre linéaire

>>> g0 = geyser[:2,:]
>>> g0
array([[ 3.6, 79. ],
[ 1.8, 54. ]])
>>> g0.transpose()
array([[ 3.6, 1.8],
[ 79. , 54. ]])
>>> np.linalg.inv(g0)
array([[ 1.03448276, -1.51340996],
[-0.03448276, 0.06896552]])
>>> g0.dot(tu2d) # ou np.dot(g0,tu2d)
array([[ 82.6, 82.6],
[ 55.8, 55.8]])
>>> tu2d
array([[ 1., 1.],
[ 1., 1.]])
>>> g0.dot(np.eye(2))
array([[ 3.6, 79. ],
[ 1.8, 54. ]])
>>> >>> g0.trace()
57.600000000000001

Résolution de systèmes linéaires :

>>> y = np.array([[5.], [7.]])


>>> np.linalg.solve(g0, y)
array([[-5.42145594],
[ 0.31034483]])

Valeurs et vecteurs propres :

>>> vpvp = np.linalg.eig(g0)


>>> vpvp
(array([ 0.92097563, 56.67902437]), array([[-0.99942549, -0.83004523],
[ 0.03389222, -0.55769609]]))

Cela permet d’obtenir les valeurs propres (chacune répétée suivant sa multiplicité) et les
vecteurs propres tels que la colonne vpvp[1][:,i] est le vecteur propre unitaire (de norme égale
à 1) correspondant à la valeur propre vpvp[0][i] .

Question :
Comment vérifier facilement ce calcul ?

Correction :
Simplement en vérifiant la relation de diagonalisation de la matrice symétrique initiale :

>>> md = np.diag(vpvp[0])
>>> vpvp[1].dot(md.dot(vpvp[1].transpose()))

Vectorisation de fonctions
Des fonctions Python qui travaillent sur des scalaires peuvent être vectorisées, c’est à dire
travailler sur des tableaux, élément par élément. Par exemple :

>>> def addsubtract(a,b):


... if a > b:
... return a - b
... else:
... return a + b

>>> addsubtract(2,3)
5
>>> vec_addsubtract = np.vectorize(addsubtract)
>>> tu2d
array([[ 1., 1.],
[ 1., 1.]])
>>> g0
array([[ 3.6, 79. ],
[ 1.8, 54. ]])
>>> vec_addsubtract(g0,tu2d)
array([[ 2.6, 78. ],
[ 0.8, 53. ]])

SciPy

SciPy ajoute de très nombreuses fonctions permettant de faire des calculs scientifiques. Il est
possible d’importer SciPy en entier avec import scipy mais il est préférable de se limiter aux
fonctionnalités utilisées, par exemple from scipy import linalg .

scipy.linalg contient toutes les fonctions de numpy.linalg plus quelques autres. Par ailleurs,
scipy.linalg est systématiquement compilée avec un support BLAS/LAPACK, alors que pour
numpy.linalg cela n’est pas obligatoire. Les calculs peuvent ainsi être plus rapide si c’est
scipy.linalg qui est utilisée.

Exemples :
>>> linalg.det(g0)
52.19999999999998
>>> linalg.norm(g0) # par défaut, norme de Frobenius
95.776823918941901
>>> linalg.norm(g0,'fro')
95.776823918941901
>>> linalg.norm(g0,1) # norme L1
133.0
>>> linalg.eig(g0)
(array([ 0.92097563+0.j, 56.67902437+0.j]), array([[-0.99942549, -0.83004523],
[ 0.03389222, -0.55769609]]))

Statistiques
De nombreuses fonctionnalités statistiques sont disponibles dans le module scipy.stats , comme
la génération de valeurs aléatoires suivant différentes distributions, des statistiques
descriptives et des tests statistiques.
Regardez les fonctionnalités de scipy.stats sur
http://docs.scipy.org/doc/scipy/reference/tutorial/stats.html.

Question :
Générez en utilisant scipy.stats une matrice 6 x 6 dont les valeurs sont issues d’une loi
normale de moyenne 1 et écart-type 3. Calculez les statistiques descriptives par ligne et par
colonne. Que constatez-vous ?

Correction :
Il faut utiliser norm.rvs() avec les valeurs appropriées pour la localisation et l’échelle :

>>> eln = norm.rvs(loc=1, scale=3, size=36)


>>> meln = eln.reshape(6,6)
>>> for i in np.arange(6):
stats.describe(meln[i,:]) // pour la ligne i
stats.describe(meln[:,i]) // pour la colonne i

Evidemment, les statistiques descriptives diffèrent de façon significative entre lignes et entre
colonnes.

Question :
Calculez les statistiques descriptives par ligne et par colonne pour le tableau geyser .

Correction :

>>> stats.describe(geyser[:,0]) // première colonne


>>> stats.describe(geyser[:,1]) // seconde colonne
>>> ...

Visualisation avec Matplotlib

◾ Documentation Matplotlib

Matplotlib permet de construire de très nombreux types de graphiques directement à partir de


l’interpréteur Python et nous sera très utile pour visualiser des données, des fonctions de
décision, etc. Nous nous servirons principalement de matplotlib.pyplot , à importer en début de
session :

>>> import matplotlib.pyplot as plt

Construisons d’abord un graphique très simple :

>>> plt.plot(np.random.rand(100)) # données générées aléatoirement


>>> plt.show() # affichage du graphique

L’appel à np.random.rand(100) a généré un tableau unidimensionnel de 100 valeurs aléatoires


suivant une distribution uniforme, chaque valeur a été affichée (l’abscisse est l’indice de la
valeur dans le tableau, l’ordonnée est la valeur même) et les valeurs d’indices succesifs ont
été reliées entre elles. Cette représentation n’a de sens que si un lien existe entre indices
successifs ; par exemple, les données correspondent à une série chronologique et les indices
correspondent aux mesures successives.
Utiliser plt.show(block=False) à la place de plt.show() permet de continuer à travailler en
conservant le graphique. Néanmoins, les appels suivants à plt.plot() modifieront le même
graphique (tant que sa fenêtre graphique n’est pas fermée).
Une alternative est d’utiliser le mode interactif avec plt.ion() (pour y entrer) et plt.ioff() pour
en sortir. En mode interactif plt.show() n’est plus nécessaire, le graphique est affiché et modifié
directement.
Les données geyser représentent deux telles séries chronologiques : les durées des éruptions
du geyser Old Faithful et les durées des pauses entre éruptions successives. Pour mieux
comprendre ce qui est affiché il est nécessaire d’indiquer des étiquettes pour les axes,
d’ajouter une légende et éventuellement de donner un titre au graphique. C’est ce que font les
instructions suivantes :

>>> plt.plot(geyser)
>>> plt.title('Old Faithful Geyser Data') # intitulé du graphique
>>> plt.xlabel('numéro éruption') # signification axe des x
>>> plt.ylabel('durée éruption/pause (min)') # signification axe des y
>>> plt.legend(('Durée éruption', 'Durée pause'), loc='best')
>>> plt.show()

On observe que chaque colonne du tableau geyser a été représentée comme une série à part.

Question :
Les deux séries ont des moyennes et des écart-types très différents. Transformez le tableau
geyser pour obtenir une moyenne de 0 et un écart-type de 1 pour chacune de ces séries et
affichez-les de nouveau.

Lorsque les observations sont issues de tirages indépendants, il est d’usage de représenter le
vecteur correspondant à chaque observation comme un point, éventuellement identifié par son
indice. Il est possible de transmettre à la fonction plot deux tableaux unidimensionnels (de
même taille) représentant les coordonnées x et respectivement y des données :

>>> plt.plot(geyser[:,0], geyser[:,1])


>>> plt.show()

Le résultat est illisible car par défaut les points d’indices successifs sont reliés entre eux. Il
faut modifier l’affichage, en précisant par ex. que l’on souhaite afficher chaque point comme
un + de couleur rouge :

>>> plt.plot(geyser[:,0], geyser[:,1],'r+')


>>> plt.show()

Regardez la description complète de la commande plot sur


http://matplotlib.org/api/pyplot_summary.html.

Question :
Multipliez une des colonnes par 2.5 et affichez le résultat.

Il est également possible d’afficher des nuages de points en 3D en utilisant la commande


scatter :

>>> from mpl_toolkits.mplot3d import Axes3D


>>> fig = plt.figure()
>>> ax = fig.add_subplot(111, projection='3d')
>>> ax.scatter(np.random.randn(100), np.random.randn(100), np.random.randn(100))
>>> plt.show()

Le graphique peut être tourné en 3D à l’aide de la souris (bouton gauche maintenu appuyé).
Il est posible d’avoir plusieurs figures ouvertes en même temps si chacune a son propre
identifiant ( fig1 , fig2 , …) et si les appels à la fonction show() ne sont pas bloquants (utilisation
de plt.show(block=False) ).

Regardez les commandes utilisables pour obtenir des graphiques en 3D sur


http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html.

Question :
En vous servant de la documentation, modifiez la couleur des points et ajoutez des
étiquettes sur les axes.

Question :
Complétez le tableau geyser d’une troisième colonne issue de tirages aléatoires et affichez le
résultat sous forme graphique.

Il est possible d’afficher les étiquettes textuelles associées aux observations. Pour cela, il faut
d’abord chercher des données adaptées en entrant dans une fenêtre terminal :

[nom@machine ~]$ wget http://cedric.cnam.fr/~crucianm/src/mammals.csv

Vous pouvez regarder le contenu de ce fichier. Nous sélectionnons pour une visualisation les
colonnes suivantes :

◾ durée sommeil sans rêve (h/jour)


◾ durée totale sommeil (h/jour)
◾ index d’exposition durant le sommeil (1-5)

La lecture des données sera faite dans deux tableaux différents, un pour les trois variables
numériques et l’autre pour les noms des espèces :

>>> import numpy as np # si pas encore fait


>>> import matplotlib.pyplot as plt # si pas encore fait

>>> mammals248 = np.loadtxt('mammals.csv', delimiter=';', usecols=[2,4,8], skiprows=1)


>>> mammals248[:5,:]
array([[ 5.71200000e+03, 1.80000000e+00, 3.00000000e+00],
[ 6.60000000e+00, 2.00000000e+00, 3.00000000e+00],
[ 4.45000000e+01, 1.80000000e+00, 1.00000000e+00],
[ 5.70000000e+00, 1.80000000e+00, 5.00000000e+00],
[ 4.60300000e+03, 1.80000000e+00, 3.00000000e+00]])

>>> noms = np.genfromtxt('mammals.csv', dtype='str', delimiter=';', usecols=[0], skip_header=1)


>>> noms
array(['African elephant ', 'African giant pouched rat', 'Arctic Fox ',
'Arctic ground squirrel ', 'Asian elephant ', 'Baboon ',
...

Pour l’affichage :

>>> from mpl_toolkits.mplot3d import Axes3D # si pas encore fait


>>> fig = plt.figure()
>>> ax = fig.add_subplot(111, projection='3d')
>>> for i in range(len(noms)):
x,y,z = mammals248[i,0],mammals248[i,1],mammals248[i,2]
ax.scatter(x,y,z)
ax.text(x,y,z,noms[i])

>>> plt.show()

Il est possible d’utiliser le clic droit de la souris pour faire un zoom.

Question :
Pour améliorer la lisibilité, affichez seulement une observation sur deux.

Correction :
Dans la boucle for ci dessus, remplacez range(len(noms)) par np.arange(0, len(noms), 2) .

Introduction à Scikit-learn

◾ Site scikit-learn

Charger et sauvegarder des données


À partir de fichiers qui présentent des formats simples, les données peuvent être lues en
utilisant la fonction loadtxt de NumPy. La fonction genfromtxt de NumPy donne une flexibilité
supplémentaire mais peut ralentir la lecture pour des fichiers de taille plus importante.
Le package sklearn.dataset inclut des fonctions supplémentaires de lecture, de génération de
données, ainsi que plusieurs ensemble de données qu’il n’est plus nécessaire de télécharger.
Vous pouvez examiner les fonctions proposées sur http://scikit-learn.org/stable/datasets/. Les
données sont représentées en général par un tuple (X, y) , où X est un tableau bidimensionnel
NumPy de n_samples x n_features contenant les valeurs des variables d’entrée et y un tableau
unidimensionnel NumPy de longueur n_samples contenant les résultats désirés.
Il est ainsi possible de lire directement des données en format SVMlight / LibSVM, dans lequel
chaque observation correspond à une ligne de fichier sous la forme suivante : <label> <feature-
id>:<feature-value> <feature-id>:<feature-value> ... , où <label> est le résultat désiré pour cette
observation (par ex. l’étiquette de classe), et chaque paire <feature-id>:<feature-value> donne un
index où la valeur est non nulle et la valeur associée. Ce format est particulièrement utile pour
des données creuses (de nombreuses valeurs nulles, qui ainsi ne sont pas stockées) mais est
parfois employé comme format par défaut même lorsque les valeurs ne sont pas nulles.
L’utilisation est décrite sur : http://scikit-learn.org/stable/datasets/#datasets-in-svmlight-
libsvm-format.

Prétraiter des données


Plusieurs fonctionnalités de pré-traitement des données sont disponibles dans le package
sklearn.preprocessing : outils pour centrer le nuage des observations (rendre la moyenne de
chaque variable égale à 0), pour centrer et réduire les variables (rendre la moyenne de chaque
variable égale à 0, puis rendre la variance de chaque variable égale à 1), pour normer les
observations (rendre la norme de chaque observation égale à 1), pour (re)coder des variables
(par exemple, codage d’une variable nominale à m modalités par m variables binaires, comme
nous l’avons vu en cours), transformations ad-hoc (par exemple, application de
transformations logarithmiques à certaines variables). Voir http://scikit-
learn.org/stable/modules/preprocessing.html.
Par exemple, pour centrer et réduire les variables correspondant aux deux colonnes de geyser :

>>> from sklearn import preprocessing


>>> geyser = np.loadtxt('geyser.txt')
>>> geyser[:5,:]
array([[ 3.6 , 79. ],
[ 1.8 , 54. ],
[ 3.333, 74. ],
[ 2.283, 62. ],
[ 4.533, 85. ]])
>>> geyserCR = preprocessing.scale(geyser)
>>> geyserCR[:5,:]
array([[ 0.09849886, 0.59712344],
[-1.48145856, -1.24518118],
[-0.13586149, 0.22866251],
[-1.05750332, -0.6556437 ],
[ 0.91744345, 1.03927655]])
>>> geyser.mean(axis=0)
array([ 3.48778309, 70.89705882])
>>> geyserCR.mean(axis=0)
array([ 4.48579082e-16, 4.27048103e-16])
>>> geyser.std(axis=0)
array([ 1.13927121, 13.56996002])
>>> geyserCR.std(axis=0)
array([ 1., 1.])

Générer des données


Le package sklearn.dataset comprend aussi quelques outils de génération de données, adaptés
à différents types de problèmes : classification automatique, classement (discrimination) à
deux ou plusieurs classes, régression, apprentissage de manifolds. Une description se trouve
sur : http://scikit-learn.org/stable/datasets/#sample-generators.

Construire des modèles


Dans Scikit-learn, un estimator est un objet qui implémente la méthode fit(X, y) pour estimer
un modèle et predict(T) afin d’utiliser ce modèle pour prendre des décisions (faire des
prédictions). Des exemples de telles classes : sklearn.svm.SVC ,
sklearn.discriminant_analysis.LinearDiscriminantAnalysis .

Charger et sauvegarder des modèles


Comme nous l’avons vu dans la séance introductive, pickle ( import pickle ) permet de sérialiser
(pour enregistrer dans un fichier ou écrire dans un string) et de désérialiser (pour lire depuis
un fichier ou depuis un string) un objet quelconque, donc également un modèle.
Pour enregistrer (ou lire) des modèles très volumineux, joblib ( from sklearn.externals import
joblib ) est conseillé.

PRÉCÉDENT | SUIVANT | INDEX


MONTRER LE CODE SOURCE
© Copyright 2016, Michel Crucianu, Meziane Yacoub - Cnam. Mis à jour le oct. 28, 2019. Créé avec Sphinx 1.6.7.

Vous aimerez peut-être aussi