J-4 Text mining avec SPARK (2/2)

Dans ce billet on continue note exercice de « Text Mining » initié dans le billet J-9 Text mining avec SPARK (1/2). Nous allons utiliser et améliorer notre algorithme pour réussir a réaliser une recherche sémantique des termes . Ce billet fait partie d’une série des exercices courtes (1h) destinés à l’apprentissage de SPARK nommés A la conquête de SPARK sur AZURE.

Parcours du Combattant:

  1. Utilisation de liste de synonymes pour capturer les mots sémantiquement proches .
  2. Utilisation de notre version de l’algorithme  TF-IDF pour répondre aux questions génériques.

Boite à outil du combattant:

  1. Abonnement Azure ou la Version d’essai Gratuite (avec 170€)
  2. 1H de libre devant vous
  3. Avoir déployé un Cluster SPARK avoir téléchargé ce-fichier dans un Blob Storage Azure dans la compte de stockage du Cluster (voir ce billet)
  4. Avoir téléchargé ce fichier dans la même compte de stockage.

1.Utilisation de liste de synonymes pour capturer les mots sémantiquement proches.

Dans cette section nous allons utiliser une liste de 450k mots françaises avec un synonyme principal pour chaque une des mots. L’objectif est de limiter les imprécisions dues aux multitudes des mots avec des significations proches e.g bon, superbe, super, etc. Pour générer ce fichier je me suis basé sur le lexique et thesaurus français disponibles gratuitement dans dans dicollecte.org et choisi pour chaque mot quel était le synonyme le plus populaire. Le résultat est ce fichier JSON qu’il faut télécharger dans le compte de stockage du cluster.

Pour exploiter la liste de mots j’ai choisi de les inclure dans le code comme un Map Scala. Le lignes de code suivantes s’occupent de la transformation.

[pastacode lang= »ruby » message= » » highlight= »Transformation de RDD en MAP » provider= »manual »]

val urlwords = "wasb://yourContainer@yourStorageAccount.blob.core.windows.net/mots-fr.js" val words = sqlContext.jsonFile(urlwords) val wordMeaning = words.map(r => (r.getString(1), r.getString(0))) val trad = wordMeaning.collectAsMap()

[/pastacode]

 L’astuce est de transformer le DataFrame « Words » en RDD[Pair] ce qui offre la possibilité d’utiliser la fonction « collectAsMap » pour avoir un object utilisable dans nos fonctions map et reduce.
La deuxième étape est de transformer le fonction « ArticleWordCount » pour remplacer chaque mot pour son synonyme « parent ».

[pastacode lang= »ruby » message= »Utilisation du Map pour « traduireé les mots » highlight= »1,6″ provider= »manual »]

def ArticleWordCount(row: Row, wMean:scala.collection.Map[String, String]) : (String, Array[LinkedList[WordCount]]) = { val hashSize = 50000 val ret = new Array[LinkedList[WordCount]](hashSize) for(w <- row.getString(0).split("\\W")) { var word = if(wMean.contains(w) && wMean(w)!="") {wMean(w)} else {w} var i = word.hashCode()%hashSize if(i s.word == word.toLowerCase) if(found != None) { found.get.wordCount = found.get.wordCount+1 } else ret(i).insert(LinkedList[WordCount](WordCount(word.toLowerCase, 1, 1, 0))) } } (row.getString(2), ret); }[/pastacode]

Les modifications faites sont le rajout du paramètre map dans la définition de la fonction (ligne 1) et l’utilisation du map pour remplecer chaque mot s’il se trouve dans la liste de synonymes (ligne 6).
Après cette modification les mots le plus importants par article varient légèrement.
blog ai3 Vectoriel J-4 Text mining avec SPARK (2/2)
Si on compare avec les résultats précédents les mots ‘vectoriels’ et ‘vectoriel’ produisent un seul terme avec plus de poids laissent rentrer autres termes dans le top 10.

2. Utilisation de notre version de l’algorithme  TF-IDF pour répondre aux questions génériques

Pour la réalisation de notre super moteur de recherche sémantique nous allons juste devoir rajouter une fonction additionnelle « InText » qui permet de filtrer des articles par rapport a un mot particulier. Voici le code

[pastacode lang= »ruby » message= »In Text » highlight= » » provider= »manual »]

def inText(art: (String, Array[LinkedList[WordCount]]), word:String, trad:scala.collection.Map[String, String]):Boolean = { var w = if(trad.contains(word) && trad(word)!="") {trad(word)} else {word} val hashSize = 50000 var i = w.hashCode()%hashSize if(i<0) { i = -i } if(art._2(i) == null) return false for(p s.word == w) if(found != None) { return true } } return false }

[/pastacode]

Cette fonction suit juste la logique des fonctions précédentes pour retourner VRAI ou FALSE si le mot se trouve dans un article. Maintenant l’idée est
  1. Utiliser cette fonction InText avec filter et SumWords pour obtenir la fréquence des mots dans tous es articles concernant ce mot.
  2. Utiliser tf-idf pour détecter les mots les plus importants comme s’il s’agissait d’un seul article.
  3. Utiliser topCount pour afficher les mots les plus importants.

Tout ça en une ligne de code 🙂

[pastacode lang= »ruby » message= »Savoie » highlight= » » provider= »manual »]

TopCount(PonderateWords(tfidf.filter(art => inText(art, "savoie" , trad)).reduce(SumWords), docFrequency, d), 10)

[/pastacode]

Et voici les résultat… (à noter que du la taille du programme j’ai du m’en passer du Zeppellin et exécuter directement le code scala depuis le cluster via remote desktop avec spark-shell -i « c:\mylocalfoder\myscript.scala ».

blog ai3 savoie J-4 Text mining avec SPARK (2/2)

Même s’il n’y a pas d’article parlent directement de savoie 🙂

Et voici le code complet

2 thoughts on “J-4 Text mining avec SPARK (2/2)

  1. Bonjour, je crois que c’est un excellent blog .
    Je tiens à le dire 😉 Je vais revenir encore une fois puisque je
    book Marqué cela. L’argent et la liberté est le
    meilleur moyen de changer, pouvez-vous être riche et continuer à aider les autres.

  2. Pingback: A la conquête de SPARK sur AZURE | Le blog Ai3Le blog Ai3

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.