Skip to content

Commit

Permalink
Continue la restructuration des sous-parties (#492)
Browse files Browse the repository at this point in the history
* Levels

* Numérotation modélisation

* Partie NLP
  • Loading branch information
linogaliana committed Apr 23, 2024
1 parent d75641d commit 06d003a
Show file tree
Hide file tree
Showing 17 changed files with 188 additions and 188 deletions.
22 changes: 11 additions & 11 deletions content/NLP/01_intro.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ L'objectif est de découvrir les principaux enjeux du nettoyage de données en N
et les enjeux de l'analyse de fréquence.


## Base d'exemple
# Base d'exemple

La base d'exemple est le *Comte de Monte Cristo* d'Alexandre Dumas.
Il est disponible
Expand Down Expand Up @@ -71,9 +71,9 @@ dumas[10000:10500]
```


## La particularité des données textuelles
# La particularité des données textuelles

### Objectif
## Objectif

Le *natural language processing* (NLP) ou
*traitement automatisé du langage* (TAL) en Français,
Expand All @@ -94,7 +94,7 @@ Si cette tâche n'était pas assez difficile comme ça, on peut ajouter d'autres
* **propres à chaque langue** : il n'existe pas de règle de passage unique entre deux langues
* de **grande dimension** : des combinaisons infinies de séquences de mots

### Méthode
## Méthode

L’analyse textuelle vise à transformer le texte en données
numériques manipulables. Pour cela il est nécessaire de se fixer
Expand All @@ -110,7 +110,7 @@ Sinon un algorithme sera incapable de détecter une information pertinente dans



## Nettoyer un texte
# Nettoyer un texte

Les *wordclouds* sont des représentations graphiques assez pratiques pour visualiser
les mots les plus fréquents, lorsqu'elles ne sont pas utilisées à tort et à travers.
Expand Down Expand Up @@ -186,7 +186,7 @@ mesure de les comparer.
:::


### Tokenisation
## Tokenisation

::: {.cell .markdown}
```{=html}
Expand Down Expand Up @@ -238,7 +238,7 @@ words[1030:1050]



### Retirer les stop words
## Retirer les stop words

Le jeu de données est maintenant propre. On peut désormais retirer les
mots qui n'apportent pas de sens et servent seulement à faire le
Expand Down Expand Up @@ -306,7 +306,7 @@ plt.axis("off")
```


### *Stemming*
## *Stemming*

Pour réduire la complexité d'un texte, on peut tirer partie de
_"classes d'équivalence"_ : on peut
Expand Down Expand Up @@ -364,7 +364,7 @@ stemmer = FrenchStemmer()
:::


## Reconnaissance des entités nommées
# Reconnaissance des entités nommées

Cette étape n'est pas une étape de préparation mais illustre la capacité
des librairies `Python` a extraire du sens d'un texte. La librairie
Expand Down Expand Up @@ -417,7 +417,7 @@ souvent nécessaire d'enrichir les règles par défaut
par des règles _ad hoc_, propres à chaque corpus.


## Représentation d'un texte sous forme vectorielle
# Représentation d'un texte sous forme vectorielle

Une fois nettoyé, le texte est plus propice à une représentation vectorielle.
En fait, implicitement, on a depuis le début adopté une démarche *bag of words*.
Expand All @@ -435,4 +435,4 @@ La pondération la plus simple est basée sur la fréquence des mots dans le doc
C'est l'objet de la métrique **tf-idf** (term frequency - inverse document frequency)
abordée dans un prochain chapitre.

## Références
# Références
20 changes: 10 additions & 10 deletions content/NLP/02_exoclean.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ plongements de mots permet d'obtenir des tableaux comme celui-ci :
Illustration de l'intérêt des _embeddings_ [@galianafuzzy]
:::

## Librairies nécessaires
# Librairies nécessaires

Cette page évoquera les principales librairies pour faire du NLP, notamment :

Expand Down Expand Up @@ -151,7 +151,7 @@ nltk.download('wordnet')
nltk.download('omw-1.4')
```

## Données utilisées
# Données utilisées

::: {.cell .markdown}
```{=html}
Expand Down Expand Up @@ -275,7 +275,7 @@ constructions d'indices de similarité cosinus reposent sur ce type d'approche.
:::


### Fréquence d'un mot
## Fréquence d'un mot

Avant de s'adonner à une analyse systématique du champ lexical de chaque
auteur, on va se focaliser dans un premier temps sur un unique mot, le mot *fear*.
Expand Down Expand Up @@ -392,7 +392,7 @@ fig.get_figure()
```


### Premier *wordcloud*
## Premier *wordcloud*

Pour aller plus loin dans l'analyse du champ lexical de chaque auteur,
on peut représenter un `wordcloud` qui permet d'afficher chaque mot avec une
Expand Down Expand Up @@ -494,7 +494,7 @@ pour faire celui-ci afin d'avoir les mots qui s'affichent en
passant sa souris sur chaque barre.


### Aparté : la loi de Zipf
## Aparté : la loi de Zipf

::: {.cell .markdown}
```{=html}
Expand Down Expand Up @@ -591,7 +591,7 @@ Le coefficient de la régression est presque 1 ce qui suggère bien une relation
quasiment log-linéaire entre le rang et la fréquence d'occurrence d'un mot.
Dit autrement, le mot le plus utilisé l'est deux fois plus que le deuxième mot le plus fréquent qui l'est trois plus que le troisième, etc.

## Nettoyage d'un texte
# Nettoyage d'un texte

Les premières étapes dans le nettoyage d'un texte, qu'on a
développé au cours du [chapitre précédent](/content/NLP/01_intro.html), sont :
Expand Down Expand Up @@ -792,7 +792,7 @@ print("---------------------------")
print(lemmatized_output[:209])
```

## TF-IDF: calcul de fréquence
# TF-IDF: calcul de fréquence

Le calcul [tf-idf](https://fr.wikipedia.org/wiki/TF-IDF) (term _frequency–inverse document frequency_)
permet de calculer un score de proximité entre un terme de recherche et un
Expand Down Expand Up @@ -888,7 +888,7 @@ La matrice `document x terms` est un exemple typique de matrice _sparse_ puisque
:::


## Approche contextuelle : les *n-grams*
# Approche contextuelle : les *n-grams*


Jusqu'à présent, dans l'approche _bag of words_, l'ordre des mots n'avait pas d'importance.
Expand Down Expand Up @@ -1015,7 +1015,7 @@ bigram_measures = nltk.collocations.BigramAssocMeasures()
def collocations_word(word = "fear"):
# Ngrams with a specific name
name_filter = lambda *w: word not in w
## Bigrams
# Bigrams
finder = BigramCollocationFinder.from_words(
nltk.corpus.genesis.words('english-web.txt'))
# only bigrams that contain 'fear'
Expand All @@ -1033,4 +1033,4 @@ collocations_word("love")
```


## Références
# Références
12 changes: 6 additions & 6 deletions content/NLP/03_lda.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ sur le sujet constitue une très bonne ressource pour comprendre
les fondements de cette technique.


## Librairies nécessaires
# Librairies nécessaires

Cette page évoquera les principales librairies pour faire du NLP, notamment :

Expand Down Expand Up @@ -119,7 +119,7 @@ from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.decomposition import NMF, LatentDirichletAllocation
```

## Données utilisées
# Données utilisées

*Si vous avez déjà lu la section précédente et importé les données, vous
pouvez passer à la section suivante*
Expand Down Expand Up @@ -173,7 +173,7 @@ train_clean.head(2)



## Principe de la LDA (Latent Dirichlet Allocation)
# Principe de la LDA (Latent Dirichlet Allocation)

Le modèle __Latent Dirichlet Allocation (LDA)__ est un modèle probabiliste génératif qui permet
de décrire des collections de documents de texte ou d’autres types de données discrètes. LDA fait
Expand Down Expand Up @@ -249,7 +249,7 @@ On va se concentrer sur Edgar Allan Poe.
corpus = train_clean[train_clean["Author"] == "EAP"]
```

## Entraîner une LDA
# Entraîner une LDA

Il existe plusieurs manières d'entraîner une LDA.

Expand Down Expand Up @@ -279,7 +279,7 @@ lda = LatentDirichletAllocation(n_components=11, max_iter=5,
lda.fit(count_data)
```

## Visualiser les résultats
# Visualiser les résultats

On peut déjà commencer par utiliser une fonction pour afficher les
résultats :
Expand Down Expand Up @@ -392,6 +392,6 @@ Plus les barres sont loin les unes des autres, plus elles sont différentes. Un
* Les **barres rouges** représentent une estimation du nombre de termes générés dans un sujet précis. La barre rouge la plus longue correspond au mot le plus utilisé dans ce sujet.


## Références
# Références

* Le [poly d'Alberto Brietti](http://alberto.bietti.me/files/rapport-lda.pdf)
34 changes: 17 additions & 17 deletions content/NLP/04_word2vec.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ et un [deuxième](https://www.kaggle.com/meiyizi/spooky-nlp-and-topic-modelling-
) ;
* Un [dépôt `Github`](https://github.com/GU4243-ADS/spring2018-project1-ginnyqg) ;

## Packages à installer
# Packages à installer

Comme dans la [partie précédente](/content/NLP/02_exoclean.qmd), il faut télécharger des librairies
spécialiséees pour le NLP, ainsi que certaines de leurs dépendances.
Expand Down Expand Up @@ -107,7 +107,7 @@ import gensim.downloader
from sentence_transformers import SentenceTransformer
```

## Nettoyage des données
# Nettoyage des données

Nous allons ainsi à nouveau utiliser le jeu de données `spooky` :

Expand All @@ -123,7 +123,7 @@ spooky_df.head()
```


### Preprocessing
## Preprocessing

En NLP, la première étape est souvent celle du *preprocessing*, qui inclut notamment les étapes de tokenization et de nettoyage du texte. Comme celles-ci ont été vues en détail dans le précédent chapitre, on se contentera ici d'un *preprocessing* minimaliste : suppression de la ponctuation et des *stop words* (pour la visualisation et les méthodes de vectorisation basées sur des comptages).

Expand Down Expand Up @@ -181,7 +181,7 @@ spooky_df.head()
```


### Encodage de la variable à prédire
## Encodage de la variable à prédire

On réalise un simple encodage de la variable à prédire :
il y a trois catégories (auteurs), représentées par des entiers 0, 1 et 2.
Expand All @@ -203,7 +203,7 @@ On peut vérifier les classes de notre `LabelEncoder` :
le.classes_
```

### Construction des bases d'entraînement et de test
## Construction des bases d'entraînement et de test

On met de côté un échantillon de test (20 %) avant toute analyse (même descriptive).
Cela permettra d'évaluer nos différents modèles toute à la fin de manière très rigoureuse,
Expand All @@ -227,9 +227,9 @@ la méthode `inverse_transform` :
print(y_train[0], le.inverse_transform([y_train[0]])[0])
```

## Statistiques exploratoires
# Statistiques exploratoires

### Répartition des labels
## Répartition des labels

Refaisons un graphique que nous avons déjà produit précédemment pour voir
la répartition de notre corpus entre auteurs :
Expand All @@ -249,7 +249,7 @@ fig.get_figure()
On observe une petite asymétrie : les passages des livres d'Edgar Allen Poe sont plus nombreux que ceux des autres auteurs dans notre corpus d'entraînement, ce qui peut être problématique dans le cadre d'une tâche de classification.
L'écart n'est pas dramatique, mais on essaiera d'en tenir compte dans l'analyse en choisissant une métrique d'évaluation pertinente.

### Mots les plus fréquemment utilisés par chaque auteur
## Mots les plus fréquemment utilisés par chaque auteur

On va supprimer les *stop words* pour réduire le bruit dans notre jeu
de données.
Expand Down Expand Up @@ -327,14 +327,14 @@ en termes de vocabulaire,
ce qui laisse penser qu'il est envisageable de prédire les auteurs à partir
de leurs textes dans une certaine mesure.

## Prédiction sur le set d'entraînement
# Prédiction sur le set d'entraînement

Nous allons à présent vérifier cette conjecture en comparant
plusieurs modèles de vectorisation,
_i.e._ de transformation du texte en objets numériques
pour que l'information contenue soit exploitable dans un modèle de classification.

### Démarche
## Démarche

Comme nous nous intéressons plus à l'effet de la vectorisation qu'à la tâche de classification en elle-même,
nous allons utiliser un algorithme de classification simple (un SVM linéaire), avec des paramètres non fine-tunés (c'est-à-dire des paramètres pas nécessairement choisis pour être les meilleurs de tous).
Expand Down Expand Up @@ -368,7 +368,7 @@ puis on calcule le `score F1` sur ces données agrégées.
L'avantage de ce choix est qu'il permet de tenir compte des différences
de fréquences des différentes classes.

### Pipeline de prédiction
## Pipeline de prédiction

On va utiliser un *pipeline* `scikit` ce qui va nous permettre d'avoir
un code très concis pour effectuer cet ensemble de tâches cohérentes.
Expand Down Expand Up @@ -409,7 +409,7 @@ def fit_vectorizers(vectorizer):
return grid_search
```

## Approche _bag-of-words_
# Approche _bag-of-words_

On commence par une approche __"bag-of-words"__,
i.e. qui revient simplement à représenter chaque document par un vecteur
Expand Down Expand Up @@ -446,7 +446,7 @@ Quel score `F1` obtient-on finalement avec cette méthode de vectorisation sur n
cv_bow = fit_vectorizers(CountVectorizer)
```

## TF-IDF
# TF-IDF

On s'intéresse ensuite à l'approche __TF-IDF__,
qui permet de tenir compte des fréquences *relatives* des mots.
Expand Down Expand Up @@ -495,7 +495,7 @@ cv_tfidf = fit_vectorizers(TfidfVectorizer)
On observe clairement que la performance de classification est bien supérieure,
ce qui montre la pertinence de cette technique.

## Word2vec avec averaging
# Word2vec avec averaging

On va maintenant explorer les techniques de vectorisation basées sur les
*embeddings* de mots, et notamment la plus populaire : `Word2Vec`.
Expand Down Expand Up @@ -604,7 +604,7 @@ cv_w2vec = fit_w2v_avg(w2v_model.wv)
La performance chute fortement ;
la faute à la taille très restreinte du corpus, comme annoncé précédemment.

## Word2vec pré-entraîné + averaging
# Word2vec pré-entraîné + averaging

Quand on travaille avec des corpus de taille restreinte,
c'est généralement une mauvaise idée d'entraîner son propre modèle `word2vec`.
Expand Down Expand Up @@ -688,7 +688,7 @@ Cela a plusieurs limites :
- lorsque les documents sont longs, la moyennisation peut créer
des représentation bruitées.

## Contextual embeddings
# Contextual embeddings

Les *embeddings* contextuels visent à pallier les limites des *embeddings*
traditionnels évoquées précédemment.
Expand Down Expand Up @@ -751,7 +751,7 @@ Dans le cas de notre tâche de classification, il est probable que
certains mots (noms de personnage, noms de lieux) soient suffisants pour classifier de manière pertinente,
ce que ne permettent pas de capter les *embeddings* qui accordent à tous les mots la même importance.

## Aller plus loin
# Aller plus loin

- Nous avons entraîné différents modèles sur l'échantillon d'entraînement par validation croisée, mais nous n'avons toujours pas utilisé l'échantillon test que nous avons mis de côté au début. Réaliser la prédiction sur les données de test, et vérifier si l'on obtient le même classement des méthodes de vectorisation.
- Faire un *vrai* split train/test : faire l'entraînement avec des textes de certains auteurs, et faire la prédiction avec des textes d'auteurs différents. Cela permettrait de neutraliser la présence de noms de lieux, de personnages, etc.
Expand Down

0 comments on commit 06d003a

Please sign in to comment.