Chapitre 7 : Vectorisation

212_Paracentrotus-lividus-MS

Une innovation importante dans le traitement des données textuelles est sans doute celle de word2Vec . L’idée est finalement simple et tient sur deux éléments essentiels

  • le premier est que la similarité entre deux mots dans un corpus peut non seulement être mesurée par une corrélation, mais surtout être calculée non sur l’ensemble du corpus des des co-occurence, mais sur des fenêtre glissante de texte de l’ordre de 5 à 10 mots consécutifs. Les termes seront similaires parce qu’ils apparaissent dans les même séquence.
  • Le second est que l’on peut représenter les termes par des vecteurs dont les angles (leur cosinus) correspond aux corrélations. L’idée clé est de représenter cette matrices de corrélations dans un espace vectorielle de grande dimensions ( de 50 à 1000). A l’inverse de l’ACP qui cherche une représentation vectorielle réduite, on cherche une représentation vectorielle étendu pour conserver toute l’information.

De manière métaphorique un modèle word2vec peut être imaginé comme un oursin, chaque épine est un vecteur (et donc un mot), les épines proches sont celles qui marchent ensemble.

La méthode Word2Vec est on le comprendra gourmande en calcul, mais sur les machines actuelles ce n’est pas un grand problème sur des corpus de dizaines de milliers de termes. L’algorithme originel est l’invention de Mikolov. s’appuit sur un double réseau de neurones. D’autres méthodes ont été proposées telles que  Glove.

On peut imaginer de multiple variantes pour les différentes séquences ( lettre, ngrams, phrase, paragraphe…)

1 mise en oeuvre avec  wordVectors

Prend en compte l’environnement des termes. Il faut charger le corpus en un seul document, on perd donc certaines informations, mais nous pourrons voir comment sont utilisés les termes au long du corpus, leur proximité, etc. A noter que Wordtovec génère aussi des n-grams.

setwd("~/Thèse/Airbnb/airbnb")
if (!require(wordVectors)) {
  if (!(require(devtools))) {
    install.packages("devtools")
  }
  devtools::install_github("bmschmidt/wordVectors")
}

if (!file.exists("airbnbcitizen.txt")) prep_word2vec(origin="airbnbcitizen",destination="airbnbcitizen.txt",lowercase=T,bundle_ngrams=2)

if (!file.exists("airbnbcitizen_vectors.bin")) {model = train_word2vec("airbnbcitizen.txt","airbnbcitizen_vectors.bin",vectors=200,threads=4,window=12,iter=500,negative_samples=0)} else model = read.vectors("airbnbcitizen_vectors.bin")

On peut explorer le modèle par une simple requête avec la fonction closest_to

model %>% closest_to("community")
##               word similarity to "community"
## 1        community                 1.0000000
## 2       commitment                 0.6407087
## 3          compact                 0.5807126
## 4         launched                 0.5804849
## 5        continues                 0.5475895
## 6             grow                 0.5464257
## 7            began                 0.5286301
## 8            staff                 0.5173636
## 9           ensure                 0.5163425
## 10 core_principles                 0.5140277
model %>% closest_to("benefits")
##                word similarity to "benefits"
## 1          benefits                1.0000000
## 2         spreading                0.8043075
## 3  local_businesses                0.7945464
## 4  tourist_hotspots                0.7585208
## 5            beyond                0.7317488
## 6            spread                0.7224757
## 7           spreads                0.7110171
## 8  small_businesses                0.6989613
## 9           haven_t                0.6863389
## 10           social                0.6723834

 

2 – exploitation par typologies

Pour une approche plus globale une typologie par les kmeans fait apparaître des groupes de mots caractéristiques. Le groupe 2 manifestement concerne les jeux olympique de rio, le 3 semble concerné l’introduction de nouvelles initiatives

set.seed(10)
centers = 150
clustering = kmeans(model,centers=centers,iter.max = 40)
sapply(sample(1:centers,6),function(n) {
  names(clustering$cluster[clustering$cluster==n][1:10])
})
##       [,1]             [,2]            [,3]         [,4]        
##  [1,] "over"           "leading"       "new"        "outside"   
##  [2,] "past"           "rio"           "good_news"  "located"   
##  [3,] "welcomed"       "largest"       "poll"       "districts" 
##  [4,] "spent"          "head"          "introduced" "properties"
##  [5,] "alone"          "2018"          "think"      "main"      
##  [6,] "guest_arrivals" "winter"        "agree"      NA          
##  [7,] "countries"      "official"      "proposals"  NA          
##  [8,] "2012"           "pyeongchang"   "introduce"  NA          
##  [9,] "has_grown"      "olympic_games" "situation"  NA          
## [10,] "restaurant"     "gangwon"       "polling"    NA          
##       [,5]                     [,6]            
##  [1,] "families"               "county"        
##  [2,] "boost"                  "oregon"        
##  [3,] "supports"               "north_carolina"
##  [4,] "economic_opportunities" "malibu"        
##  [5,] "democratises"           "phoenix"       
##  [6,] NA                       "rhode_island"  
##  [7,] NA                       "san"           
##  [8,] NA                       "florida"       
##  [9,] NA                       "diego"         
## [10,] NA                       "alto"

Une autre approche passe par une méthode hiérarchique, on l’applique sur un sous-corpus constitué à partir de mots pivot qui associe l’accueil, ‘économie et l’idée de communauté qui caractérise le concept AIRbnb.

La première partie de la procédure constitue le sous corpus à partir de 4 ingredients. La seconde réalise le clustering. On s’apercoit ainsi , dans le bas du dendogram que les termes tourism, communities, economic et impact sont associés. C’est clairement un sujet relatif à l’impact sur le développement local, qui effectivement est un des axes de la stratégie de légitimation de AirBnb. Ne reste qu’à examiner les autres groupes et leurs arrangements.

#A partir de mots :
ingredients = c("welcome","host","economic","community")
term_set = lapply(ingredients, 
                  function(ingredient) {
                    nearest_words = model %>% closest_to(model[[ingredient]],20)
                    nearest_words$word
                  }) %>% unlist

subset = model[[term_set,average=F]]

subset %>%
  cosineDist(subset) %>% 
  as.dist %>%
  hclust %>%
  plot

w2v01b

3. Analyse avec Tsne

l’analyse est directe, il suffit de spécifier le nom du model et le degré de perplexité

plot(model,perplexity=10)
## Attempting to use T-SNE to plot the vector representation
## Cancel if this is taking too long
## Or run 'install.packages' tsne if you don't have it.
## sigma summary: Min. : 0.3501 |1st Qu. : 0.474 |Median : 0.5254 |Mean : 0.5312 |3rd Qu. : 0.5806 |Max. : 0.7824 |## Epoch: Iteration #100 error is: 25.1868789724176
## Epoch: Iteration #200 error is: 2.51273098790797
## Epoch: Iteration #300 error is: 1.65192074192181
## Epoch: Iteration #400 error is: 1.62689440968167
## Epoch: Iteration #500 error is: 1.61281769769218
## Epoch: Iteration #600 error is: 1.60004119282296
## Epoch: Iteration #700 error is: 1.59808728221376
## Epoch: Iteration #800 error is: 1.58923848256058
## Epoch: Iteration #900 error is: 1.60934087102874
## Epoch: Iteration #1000 error is: 1.57588503554317

w2v02

On peut regarder plus attentivement les détail en sélection des paires de mots : ici Community et benefits.

#Avec 2 mots
tastes = model[[c("community","benefits"),average=F]]

# model[1:3000,] here restricts to the 3000 most common words in the set.
host_and_benefits = model[1:1471,] %>% cosineSimilarity(tastes)

# Filter to the top 20 host or benefits.
host_and_benefits = host_and_benefits[
  rank(-host_and_benefits[,1])<20 |
    rank(-host_and_benefits[,2])<20,
  ]

plot(host_and_benefits,type='n')
text(host_and_benefits,labels=rownames(host_and_benefits),cex = 0.6)

w2v03

Un des avantages de word to vec est de pouvoir explorer la structure sémantique que révèle le modèle.  Dans l’exemple suivant

top_evaluative_words = model %>% 
  closest_to(~ "host"-"sharing",n=75)

hostness = model %>% 
  closest_to(~ "host"+"sharing",n=Inf) 

revenue = model %>% 
  closest_to(~ "benefits" + "sharing", n=Inf)

top_evaluative_words %>%
  inner_join(hostness) %>%
  inner_join(revenue) %>%
  ggplot() + 
  geom_text(aes(x=`similarity to "benefits" + "sharing"`,
                y=`similarity to "host" + "sharing"`,
                label=word),size=2.5,check_overlap = TRUE)
## Joining, by = "word"
## Joining, by = "word"

w2v05

bnb

Publicités