Skip to content

Commit cb65553

Browse files
committed
PCA
close #580
1 parent cc9a2d0 commit cb65553

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

content/NLP/02_exoclean.qmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ tf_idf_term("renard")
219219
L'exemple précédent ne passait pas très bien à l'échelle. Heureusement, `Scikit` propose une implémentation de la recherche par vecteur TF-IDF que nous pouvons explorer avec un nouvel exercice.
220220

221221
::: {.exercise}
222-
## Exercice 6 : TF-IDF : calcul de fréquence
222+
## Exercice 1 : TF-IDF : calcul de fréquence
223223

224224
1. Utiliser le vectoriseur TF-IdF de `scikit-learn` pour transformer notre corpus en une matrice `document x terms`. Au passage, utiliser l'option `stop_words` pour ne pas provoquer une inflation de la taille de la matrice. Nommer le modèle `tfidf` et le jeu entraîné `tfs`.
225225
2. Après avoir construit la matrice de documents x terms avec le code suivant, rechercher les lignes où les termes ayant la structure `abandon` sont non-nuls.
@@ -367,7 +367,7 @@ from nltk.metrics import BigramAssocMeasures
367367
```
368368

369369
::: {.exercise}
370-
## Exercice 7 : n-grams et contexte du mot fear
370+
## Exercice 2 : n-grams et contexte du mot fear
371371

372372
1. Utiliser la méthode `concordance` pour afficher le contexte dans lequel apparaît le terme `fear`.
373373
2. Sélectionner et afficher les meilleures collocations, par exemple selon le critère du ratio de vraisemblance.

content/modelisation/5_clustering.qmd

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,5 +541,128 @@ Pour mettre en pratique les méthodes de création de clusters, de la base brute
541541
L'ACP est également très utile dans le champ de la réduction du nombre de variables pour de nombreux types de modélisations, comme par exemple les régressions linéaires.
542542
Il est ainsi possible de projeter l'espace des variables explicatives dans un espace de dimension donnée plus faible, pour notamment limiter les risques d'_overfitting_.
543543

544+
L'inconvénient de cette approche est quelle rend les données utilisées en entrée du modèle moins interprétables qu'avec un LASSO puisque cette dernière technique sélectionne des variables là où la PCA sélectionne des combinaisons linéaires de nos variables.
545+
546+
## Exemple
547+
548+
Reprenons nos données précédentes. Avant de faire une analyse en composante principale, dont l'objectif est de synthétiser des sources de variabilité dans nos données, il est conseillé de standardiser les variables lorsque celles-ci ont des échelles différentes (ce qui est le cas dans notre cas).
549+
550+
```{python}
551+
from sklearn.preprocessing import StandardScaler
552+
553+
X = df2.drop(['per_gop'], axis=1)
554+
y = votes['winner']
555+
556+
print('Dimensions des données avant PCA : {}'.format(X.shape))
557+
```
558+
559+
Faisons déjà un premier test en réduisant nos données à deux composantes, c'est-à-dire à deux combinaisons linéaires de celles-ci. Il s'agit d'une méthode implémentée en `Scikit`, très pratique. Le faire à la main serait pénible
560+
561+
562+
```{python}
563+
#| echo: true
564+
from sklearn.decomposition import PCA
565+
566+
scaler = StandardScaler()
567+
X_standardized = scaler.fit_transform(X)
568+
569+
n_components = 2
570+
pca = PCA(n_components=n_components)
571+
```
572+
573+
<details>
574+
575+
<summary>
576+
Faire une PCA à la main (exercice éducatif mais peu utile dans la vraie vie)
577+
</summary>
578+
579+
```{python}
580+
#| echo: true
581+
582+
# Step 1: Compute the covariance matrix
583+
cov_matrix = np.cov(X_standardized.T)
584+
585+
# Step 2: Perform eigen decomposition
586+
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
587+
588+
# Step 3: Sort eigenvectors by eigenvalues
589+
sorted_indices = np.argsort(-eigenvalues)
590+
eigenvectors_sorted = eigenvectors[:, sorted_indices]
591+
592+
first_component_manual = eigenvectors_sorted[:, 0]
593+
first_component_manual
594+
```
595+
596+
</details>
597+
598+
599+
On peut utiliser notre méthode `fit_transform` pour calculer les paramètres utiles de notre PCA, à savoir les poids à utiliser pour reprojeter nos variables dans l'espace des composantes:
600+
601+
```{python}
602+
#| echo: true
603+
604+
x_2d = pca.fit_transform(X_standardized)
605+
columns=[f'component_{i}' for i in range(1, n_components + 1)]
606+
df_pca = pd.DataFrame(x_2d, columns=columns)
607+
df_pca['classe'] = y
608+
print('Dimensions des données après PCA : {}'.format(x_2d.shape))
609+
df_pca
610+
```
611+
612+
Ces composantes ne sont plus interprétables directement. Il s'agit d'une combinaison linéaire de nos variables. Prenons le premier axe pour s'en assurer:
613+
614+
```{python}
615+
#| echo: true
616+
np.dot(X_standardized, pca.components_[0])
617+
```
618+
619+
Pourquoi rendre nos données moins interprétables? Parce qu'avec seulement deux colonnes, on va synthétiser beaucoup plus d'information, c'est-à-dire capturer beaucoup plus de variance de nos données, qu'avec nos données brutes.
620+
621+
La variance expliquée par chaque composante est la suivante:
622+
623+
```{python}
624+
#| echo: true
625+
tableau_variance = pd.DataFrame(
626+
{"Axe": [f"Composante {i+1}" for i in range(2)],
627+
"Variance expliquée (%)": pca.explained_variance_ratio_*100}
628+
)
629+
tableau_variance
630+
```
631+
632+
Avec deux axes, on capture donc une bonne partie de notre variance:
633+
634+
```{python}
635+
#| echo: true
636+
tableau_variance["Variance expliquée (%)"].sum()
637+
```
638+
639+
Le premier axe capture une part importante de la variance, le deuxième axe étant déjà beaucoup moins explicatif. Ceci est attendu puisque les axes des PCA capturent une part décroissante de la variance.
640+
641+
Ici nous avions fixé le nombre d'axes principaux à 2. Comment choisir ce nombre en pratique ? Comme précédemment pour les _k means_, le critère du coude est fréquemment utilisé. Représentons la part de variance expliquée en fonction du nombre d'axes:
642+
643+
```{python}
644+
#| echo: true
645+
import plotly.express as px
646+
pca = PCA()
647+
pca.fit(X_standardized)
648+
exp_var_cumul = np.cumsum(pca.explained_variance_ratio_)
649+
650+
px.area(
651+
x=range(1, exp_var_cumul.shape[0] + 1),
652+
y=exp_var_cumul,
653+
labels={"x": "# Components", "y": "Explained Variance"}
654+
)
655+
```
656+
657+
Les coudes sont peu francs, on peut donc choisir deux ou trois axes. Si on préfère utiliser un seuil de variance expliquée dans notre analyse, on utilisera plutôt l'option `n_components` de `Scikit`. Par exemple, si on désire conserver les axes permettant d'expliquer 90% de la variabilité de nos données:
658+
659+
```{python}
660+
#| echo: true
661+
pca = PCA(n_components=0.9)
662+
pca.fit(X_standardized)
663+
664+
print(pca.explained_variance_ratio_)
665+
```
666+
544667

545668
# Références {-}

0 commit comments

Comments
 (0)