Skip to content

Instantly share code, notes, and snippets.

@phileas-condemine
Last active June 23, 2020 15:06
Show Gist options
  • Save phileas-condemine/2db55ae38e78c61728716dc3a7b91979 to your computer and use it in GitHub Desktop.
Save phileas-condemine/2db55ae38e78c61728716dc3a7b91979 to your computer and use it in GitHub Desktop.
Exemple d'utilisation des techniques word2vec & GloVe en R
## Word2vec & GloVe
Certains chercheurs mettent à disposition des modèles word2vec, GloVe, LSA qui peuvent être considérés comme des tables de correspondance entre des mots et un vecteur numérique dans un espace d'une certaine taille (en générale très inférieure à la taille du vocabulaire qui est, on le rappelle, grande). Cet espace est un espace "sémantique" en quelques sortes.
Glove, Word2vec et LSA produisent tous les 3 des vectorisations du langage ie des représentations dans un espace vectoriel réel de taille N (choisie)
- word2vec : s'appuie sur un simple perceptron multi-couches (réseau de neurone) à une couche cachée (de taille N) où la tâche est de prédire le mot en fonction du contexte ou réciproquement. La vectorisation en dimension N est fournie par l'ensemble des poids des neurones de la couche cachée.
- global vector : s'appuie sur la factorisation de la matrice de co-occurrence des termes.
- LSA : s'appuie sur la décomposition en valeurs singulières de la matrice termes-documents.
Cette tâche d'apprentissage considérable est souvent faite sur de très gros corpus (comme Wikipédia par exemple), et leur réutilisation à d'autres fins s'appelle le transfer learning.
L'exemple développé ci-dessous s'appuie sur le tutoriel GloVe [text2vec](http://text2vec.org/glove.html)
Un autre exemple avec word2vec, est situé en dessous du premier, pour illustrer un exemple de transfer learning.
```{r eval=F}
library(text2vec)
text8_file = "data_text_mining/text8"
# if (!file.exists(text8_file)) {
# download.file("http://mattmahoney.net/dc/text8.zip", "~/text8.zip")
# unzip ("~/text8.zip", files = "text8", exdir = "~/")
# }
wiki = readLines(text8_file, n = 1, warn = FALSE)
```
```{r eval=F}
# tokenisation
tokens = space_tokenizer(wiki)
# creation d'un vocabulaire de 1-grammes
it = itoken(tokens, progressbar = FALSE)
vocab = create_vocabulary(it)
# on supprime les n-grammes rares
vocab = prune_vocabulary(vocab, term_count_min = 5L)
vectorizer = vocab_vectorizer(vocab)
# co-occurrence avec un contexte de taille 5
tcm = create_tcm(it, vectorizer, skip_grams_window = 5L)
```
```{r, eval=F}
glove = GlobalVectors$new(word_vectors_size = 50, vocabulary = vocab, x_max = 10)
wv_main = glove$fit_transform(tcm, n_iter = 50, convergence_tol = 0.01)
save(wv_main,glove,file="GloVe.RData")
```
```{r eval=F}
load("GloVe.RData")
dim(wv_main)
wv_context = glove$components
dim(wv_context)
word_vectors = wv_main + t(wv_context)
```
Dans cet espace numérique, il a été montré que deux mots proches (au sens d'une distance mathématique donc) avaient des sens proches. C'est un énorme gain par rapport à l'approche bag of words où deux synonymes peuvent avoir une similarité apparente très faible du fait qu'ils sont rarement utilisés ensemble dans les mêmes documents (lorsque la similarité est calculée via les colonnes de la matrice documents termes typiquement).
```{r eval=F}
#calcul de la distance cosinus
cos_sim = sim2(x = word_vectors, y = word_vectors["berlin", , drop = FALSE], method = "cosine", norm = "l2")
```
Termes les plus proches
```{r eval=F}
head(sort(cos_sim[,1], decreasing = TRUE), 10)
```
Termes diamétralement opposés
```{r eval=F}
tail(sort(cos_sim[,1], decreasing = TRUE), 10)
```
Termes décorrélés
```{r eval=F}
head(sort(abs(cos_sim[,1])), 10)
```
Les propriétés mathématiques et sémantiques de ces modèles en ont fait leur renommée :
```{r eval=F}
berlin = word_vectors["paris", , drop = FALSE] -
word_vectors["france", , drop = FALSE] +
word_vectors["germany", , drop = FALSE]
cos_sim = sim2(x = word_vectors, y = berlin, method = "cosine", norm = "l2")
```
Termes les plus proches
```{r eval=F}
head(sort(cos_sim[,1], decreasing = TRUE), 10)
```
Termes diamétralement opposés
```{r eval=F}
tail(sort(cos_sim[,1], decreasing = TRUE), 10)
```
Termes décorrélés
```{r eval=F}
head(sort(abs(cos_sim[,1])), 10)
```
On peut représenter les mots graphiquement
```{r, eval=F}
words=c("money","finance","economy","cash","dollar","euro",
"data","mining","science","study","predictive","learning",
"country","city","town","house","place","home",
"english","french","language","german","travel","speak")
topic=c(rep("economie",6),
rep("modélisation",6),
rep("lieu",6),
rep("langage",6))
terms = word_vectors[words, , drop = FALSE] #on peut récupérer les mots les plus similaires à plusieurs références
terms_df=data.frame(predict(prcomp(terms,rank. = 2)))
terms_df$word=words
terms_df$topic=topic
g <- ggplot(terms_df,aes(x=PC1,y=PC2,label=word,color=topic))+geom_text()
g
library(plotly)
p <- ggplotly(g)
p
htmlwidgets::saveWidget(as_widget(p),"PC1_PC2_glove.html")
htmltools::includeHTML("PC1_PC2_glove.html")
```
L'exemple ci-dessous s'appuie sur un package github non pré-compilé, il vous faudra donc installer RTools pour le faire fonctionner.
Attention pour l'installation, le package n'est pas sur CRAN
```{r, eval=F}
devtools::install_github("bmschmidt/wordVectors")
```
Les données peuvent être téléchargées [ici](http://embeddings.net/frWac_non_lem_no_postag_no_phrase_200_cbow_cut100.bin)
On charge le modèle, c'est un peu long...
```{r, results='hide', message=FALSE, warning=FALSE, eval=F}
library(wordVectors)
library(magrittr)
model = read.vectors("data_text_mining/frWac_non_lem_no_postag_no_phrase_200_cbow_cut100.bin")
```
On peut explorer cet embedding grâce aux fonctions du package illustrée dans ce [tutoriel](https://github.com/bmschmidt/wordVectors/blob/master/vignettes/introduction.Rmd)
```{r, eval=F}
model %>% closest_to("economie") # montre les mots les plus proche de economie dans cet espace
```
Les propriétés mathématiques et sémantiques de ces modèles ont en fait leur renommée :
```{r, eval=F}
model %>% closest_to(~ "homme" - "il" + "elle")
model %>% closest_to(~ "roi" - "il" + "elle")
```
(ok, on a un petit souci d'accent..)
On peut représenter les mots graphiquement :
```{r, eval=F}
terms = closest_to(model,model[[c("croissance","récession","chomage","impot")]],50) #on peut récupérer les mots les plus similaires à plusieurs références
eco = model[[terms$word,average=F]] #average = FALSE, on prend la version numérique de chaque mot
plot(eco,method="pca")
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment