#!/usr/bin/env python # coding: utf-8 #

Pau Machine Learning : PCA algorithm # Voici le premier épisode de Pau ML, dont le but est d'échanger autour du data science. Pour commencer, nous attaquons une méthode très classique de data mining : l'analyse en composantes principales, ou PCA in english. # In[1]: get_ipython().run_line_magic('pylab', '--no-import-all inline') from sklearn.decomposition import PCA matplotlib.rcParams['figure.figsize'] = 10, 10 #

1. Un exemple jouet # In[2]: alpha = 4 size = 100 a = np.random.uniform(-1, alpha - 1, (size, 2)) b = np.random.uniform(-2, alpha - 2, (size, 2)) c = np.random.uniform(-3, alpha - 3, (size, 2)) d = np.random.uniform(0, alpha, (size, 2)) e = np.random.uniform(1, 1 + alpha, (size, 2)) f = np.random.uniform(2, 2 + alpha, (size, 2)) X = np.concatenate((a,b,c,d,e,f),axis=0) pca = PCA(n_components=2) plt.scatter(X[:,0],X[:,1]) pca.fit(X) print(pca.explained_variance_ratio_) # La sortie ci-dessus renseigne le pourcentage de variance expliqué par chacun des axes de l'ACP. Ces valeurs sont calculées grâce à la diagonalisation de la matrice ${}^T\!XX$, qui représentent les corrélations entre les colonnes de $X$ (les variables de notre problème d'analyse de données). Chaque coefficient de cette matrice est défini par : # $$ # ({}^T\!XX)_{ij} = \sum_{k=1}^n X_{ki}X_{kj}, \forall i,j=1, \ldots, p. # $$ # Mathématiquement, l'analyse en composantes principales est un simple changement de représentation (un changement de base): passer d'une représentation canonique (avec la base canonique) à une représentation idéale grâce à la matrice des corrélations (la base des composantes principales). Ci-dessous par exemple voici les nouvelles coordonnées de $X$ dans la nouvelle base : # In[3]: newX = pca.transform(X) print(newX) plt.scatter(newX[:,1], newX[:,1]) #

2. Exemple digits # L'intérêt de l'analyse en composantes principales est de considérer des données de dimension *plus grande que 2*. Comment représenter des observations ayant un grand nombre de feature ($p=10$, $p=100$ ou $p=10^6$) ? Comment réduire la dimension en tenant compte des corrélations entre les caractères ? #

2.1 Description de l'échantillon # Grâce au module sklearn, on va étudier un exemple concret : la reconnaissance d'écriture, et plus particulièrement la reconnaissance de chiffres. Dans cet exemple, chaque image représente un chiffre écrit à la main, à faible résolution (8*8 pixels). Nous sommes donc dans le cas où $p=64$. # In[4]: from sklearn import datasets #iris = datasets.load_iris() digits = datasets.load_digits() # Voici par exemple une écriture du chiffre $0$ dans une matrice 8*8 pixels représentant les niveaux de gris de chaque pixel : # In[5]: digits.images[0] # Voici une série d'images correspondant aux 10 premières observations du dataset digits : # In[6]: #Load the digits dataset digits = datasets.load_digits() #Display the first digit for elt in range(10): plt.figure(1, figsize=(3, 3)) plt.imshow(digits.images[elt], cmap=plt.cm.gray_r, interpolation='nearest') plt.show() #

2.2. PCA des digits 0 et 7 # Attaquons maintenant notre analyse en composantes principales en essayant de représenter notre échantillon avec seulement deux composantes principales (au lieu de 64 dimensions initiales). # In[7]: X = digits.data pca = PCA(n_components=2) pca.fit(X) print(pca.explained_variance_ratio_) # Le résultat ci-dessus nous dit que 27% de l'information est représenté par les deux premiers axes de l'ACP. Commençons par étudier le cas des digits 0 et 7. Comment sont représentés les observations de 0 et de 7 dans les deux premiers axes de l'ACP ? # In[8]: liste_0 = [] liste_7 = [] for k,elt in enumerate(digits.target): if (elt==0): liste_0.append(k) if (elt==7): liste_7.append(k) # In[9]: print('On étudie '+str(len(liste_0))+' écritures du chiffre 0 et '+str(len(liste_7))+' du chiffre 7.') # In[10]: X0 = digits.data[liste_0,:] X7 = digits.data[liste_7,:] X07 = np.concatenate((X0,X7)) pca = PCA(n_components=5) pca.fit(X07) # On va représenter ces écritures selon les deux premiers axes de l'analyse en composantes principales. # In[11]: Z07 = pca.transform(X07) x = Z07[:,0] y = Z07[:,1] colors = list(digits.target[liste_0]) + list(digits.target[liste_7]) #area = np.pi * (15 * np.random.rand(N))**2 plt.scatter(x, y, c=colors, alpha=0.5) # Not that bad ! Grâce à un simple changement de représentation, il est maintenant très facile de détecter automatiquement un 0 ou un 7 avec un algorithme de classification en deux dimensions comme une Analyse Discrimnante Linéaire (LDA in english). Si l'on regarde de plus près cette nouvelle représentation, voici à quoi ressemble le premier axe de cette représentation : # In[12]: components = pca.components_ components[0].reshape((8,8)) # Avec une image c'est mieux : # In[13]: plt.figure(1, figsize=(3, 3)) plt.imshow(components[1].reshape((8,8)), cmap=plt.cm.gray_r, interpolation='nearest') plt.show() # Bien sûr, les choses se compliquent avec les 10 chiffres... # In[14]: X = digits.data pca = PCA(n_components=5) pca.fit(X) Z = pca.transform(X) x = Z[:,0] y = Z[:,1] colors = digits.target #area = np.pi * (15 * np.random.rand(N))**2 plt.scatter(x, y, c=colors, alpha=0.5) plt.show() # # A vous de jouer ! # On étudie 84 peintures de Rembrant et Van Gogh grâce à l'ACP. Pour cela on représente chaque image par son histogramme de couleurs. Dans le cas présent, cela consiste à partitioner l’espace des couleurs (ici, $[0,255]^3$) # en k parties égales et, pour chaque image I, calculer la proportion $p_{Ij}$ des pixels se trouvant dans la partie j, pour $j = 1, . . . , k$. Après avoir effectué cette étape, on associe à chaque image I le vecteur numérique de taille k contenant les proportions ($p_{I1},\ldots, p_{Ik}$). # # ##Echauffement # Les fichiers painting8.txt et painting64.txt contiennent l'histogramme des couleurs de chaque pour $k=8$ et $k=64$. Les 40 premières lignes correspondent aux tableaux de Rembrant et les 44 dernières à ceux de Van Gogh et les peintures se trouvent ici . # # Faites une analyse en composantes principales pour séparer les peintures de Rembrant et Van Gogh. # In[15]: #PCA for painting dataset paint_data = np.genfromtxt("painting64.txt", delimiter=',') print(paint_data.shape) # In[16]: # PCA analyses pca = PCA(n_components=3) pca.fit(paint_data) new_paint_data = pca.transform(paint_data) x, y, z = new_paint_data[:,[0, 1, 2]].transpose() print(pca.explained_variance_ratio_) # plot colors = 40*["blue"] + 44*["red"] plt.subplot(211) plt.scatter(x, y, color=colors) plt.xlabel("First component") plt.ylabel("Second component") plt.subplot(212) plt.scatter(x, z, color=colors) plt.xlabel("First component") plt.ylabel("Third component") # Visualisation avec panda. # In[20]: import pandas as pd from pandas.tools.plotting import scatter_matrix df = pd.DataFrame({"Comp1": x, "Comp2": y, "Comp3": z}) pltmat = scatter_matrix(df, alpha=.6, figsize=(10, 10), diagonal='kde', marker="o")