Texts analytics tutorial - Département de Mathématiques
Transcription
Texts analytics tutorial - Département de Mathématiques
Université de Caen Basse-Normandie 1 1er décembre 2015 Département de Mathématiques et Mécanique Text mining sur le web Sommaire 1.1 1.2 1.3 1.4 1.5 1.6 1.1 Description . . . . . . . . . . . . . . . . . . . . 1.1.1 Objectifs . . . . . . . . . . . . . . . . . . . . 1.1.2 Source . . . . . . . . . . . . . . . . . . . . . . 1.1.3 Les données . . . . . . . . . . . . . . . . . . . A-Création de la liste des restaurants . . . . Création de la liste des pages contenant tous B-Extraction des avis de la clientèle . . . . . C-Création de la matrice avis -mots cles. . . D-Analyse des avis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . les avis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 1 1 3 4 4 7 Description 1.1.1 Objectifs Web extraire des données depuis les pages web d’un site Text mining analyser par des méthodes simples les textes. Figure 1 – Classé 1er en décembre 2015 par tripadvisor 1.1.2 Source Je me suis inspiré d’un meetup fait à San Francisco sur Knime en septembre 2014 par Rosario Silipo, l’exposé est disponible. Les données initiales qui concernent des restaurants de San-Francisco sont aussi disponibles en suivant ce lien. Dans cette exercice on localise le problème aux restaurants de Caen, et on automatise la recherche de tous les avis déposés sur le site http://www.tripadvisor.fr, alors que le projet initial étudie uniquement les 10 premiers avis de chaque restaurant. 1.1.3 Les données Les données proviennent exclusivement du site http://www.tripadvisor.fr, elles seront extraites des pages web proposées par ce site. Toutes les tables intermédiaires sont disponibles à http://www.math.unicaen.fr/~kauffmann/data/mining-tripadvisor.tar.gz 1.2 A-Création de la liste des restaurants Dans cette question on génère la liste des pages de tripadvisor contenant les 10 premiers avis des consommateurs de chaque restaurants de Caen. http://www.math.unicaen.fr/~kauffman/cours 1 [email protected] 1er décembre 2015 Université de Caen Basse-Normandie Département de Mathématiques et Mécanique Figure 2 – Flux de processus Les restaurants répertoriés au 30 novembre 2015 sont au nombre de 347. 1 2 3 url http://www.tripadvisor.fr/Restaurants-g187182- Caen_Calvados_Basse_Normandie_Normandy.html http://www.tripadvisor.fr/Restaurants-g187182- oa30-Caen_Calvados_Basse_Normandie_Normandy.html#EATERY_LIST_CONTENTS http://www.tripadvisor.fr/Restaurants-g187182- oa60-Caen_Calvados_Basse_Normandie_Normandy.html#EATERY_LIST_CONTENTS Table 1 – Premières pages des restaurants Caennais au 2015/11/30 (fichier d’entrée) 1. Lire le fichier contenant la liste des pages étudiées : les restaurants de Caen. knime://LOCAL/data/pages_initiales.csv grâce au noeud CSV Reader. On définira les options suivantes Column delimiter Le séparateur de champs sera le point virgule. Row delimiter a fin de ligne sera ”\n”. Quote Char les chaines de caractères seront encadrées par une double apostrophe. Comment Char Le caractère débutant des commentaires sera le caractère #. Has Column Header Le fichier contient le nom des colonnes. 2. Démarrer une boucle sur les lignes de la table d’entrée avec le noeud Chunk Loop Start. Dans la question suivante, on fait les calculs à l’intérieur de la boucle : pour chacune des lignes du fichier pages_initiales.csv. (a) Lire le contenu de ces pages grâce au noeud HttpRetriever, en spécifiant que l’url est la colonne url. (b) Transformer votre code HTML en XML à l’aide du noeud HtmlParser. (c) Dans une page il y a plusieurs restaurants, on va rechercher dans cette page tous les restaurants cités dans cette page. Extraire les noms des restaurants grâce à un noeud XPath. Les options Setting new column name restaurant Xpath query //dns:div[starts-with(@class,’listing’)]. Cette requête va recherche dans la page html une division dont l’attribut class commence par listing. Xpath data type Node-set(collection of XML Cells). la valeur va être une liste de sous-arbres, définissant chacun un restaurant. XML fragment name fragment Incorporate namespace of the rot element yes Prefix dns. (d) Empiler alors ces sous-arbres restaurant Il y aura une ligne de crée par restaurant grâce au noeud Data Manipulation/Transform/Ungroup. (e) Dans cette suite d’opérations, on extrait différents champs concernant le restaurant. Les valeurs des requêtes Xpath seront du type String. On retournera une valeur manquante si la requête n’a pas aboutie. Restaurant Le nom du restaurant //dns:a[@class="property_title"]. Cuisine Le type de cuisine //dns:a[@class="cuisine"]. Lien Le lien vers les 10 premiers avis sur le restaurant //dns:span[@class="reviewCount"]//@href NB.AVIS le nombre d’avis //dns:span[@class="reviewCount"]. (f) Dans cette question, on va faire la jointure des tables crées à partir des requêtes Xpath. i. Grâce un Noeud Data Manipulation/Column.Split & Combine/Joiner, faire la jointure entre les sorties des requêtes Xpath Restaurant et Cuisine. http://www.math.unicaen.fr/~kauffman/cours 2 [email protected] Université de Caen Basse-Normandie 1er décembre 2015 Département de Mathématiques et Mécanique Joiner Settings La colonne de jointure sera Row ID Column Selection Un choisira pour la table de gauche $ url $ RESTAURANT et $CUSINE pour la table de droite. ii. A l’aide deux autres jointures ajouter les autres champs calculés $lien, $nb.AVIS. (g) Ajouter le noeud Loop End. 3. Ajouter au lien vers les avis la chaı̂ne "http://www.tripadvisor.fr/Restaurant" grâce au noeud String Manipulation. Expression replace($lien$,"/Restaurant" ,"http://www.tripadvisor.fr/Restaurant") Replace Column $lien. 4. Supprimer les passages à la ligne des variables RESTAURANT, CUISINE, à l’aide de l’expression replace($RESTAURANT$,"\n" ,""). 5. Ecrire la table dans un fichier nommé liste_restaurant.csv, écrire le nom des colonnes. 1.3 Création de la liste des pages contenant tous les avis Dans l’étape précédente on a pu créer la liste des pages principales de chaque restaurant, ainsi que le nombre d’avis déposés. Ces résultats sont contenus dans le fichier liste_restaurant.csv. Par exemple, le 30 novembre 2015, il y avait 502 avis déposés pour le restaurant “A contre sens”. Sa page principale est http://www.tripadvisor.fr/Restaurant_ Review-g187182-d970138-Reviews-Le_Sans_Gene-Caen_Calvados_Basse_Normandie_Normandy.html#REVIEWS L’objectif de cette partie est de construire la liste des pages contenant tous les débuts des avis , comme il y 10 avis affichés par page, ce restaurant aura 51 pages : ce sont toutes les pages suites. Les pages sont indexées de la façon suivante : avis 01-10 11-20 21-30 url http://www.tripadvisor.fr/Restaurant_Review-g187182-d970138-Reviews-Le_Sans_Gene-Caen_Calvados_Basse_Normandie_Normandy.html#REVIEWS http://www.tripadvisor.fr/Restaurant_Review-g187182-d970138-Reviews-or10-Le_Sans_Gene-Caen_Calvados_Basse_Normandie_Normandy.html#REVIEWS http://www.tripadvisor.fr/Restaurant_Review-g187182-d970138-Reviews-or20-Le_Sans_Gene-Caen_Calvados_Basse_Normandie_Normandy.html#REVIEWS Table 2 – Fichier résultat pages_restaurants.csv url des avis sur un restaurant Le programme en R construit à partir de la liste des pages contenant les 10 premiers avis de chaque restaurant, la liste des pages contenant tous les avis de chaque restaurant X=read.table('knime-workspace/data/liste_restaurant.csv',header=TRUE,sep=";",stringsAsFactors=FALSE) X$NB.AVIS=as.numeric(gsub(" *avis","",X$NB.AVIS)) X$NB.AVIS[is.na(X$NB.AVIS)]=1 X$RESTAURANT=gsub('\n','',X$RESTAURANT) X$CUISINE=gsub('[\n\\:]|Cuisines','',X$CUISINE) X$FRANCE=as.numeric(grepl('fran',X$CUISINE,ignore.case=TRUE)) X$url=gsub('#EATERY_LIST_CONTENTS','',X$url) Y=data.frame() for (ligne in 1:nrow(X)) { nb.liens=ceiling(X$NB.AVIS[ligne]/10) liens=c(X$lien[ligne]) if( nb.liens>1 ) { chgt=paste("-Reviews-or",(1:(nb.liens-1))*10,"-",sep="") debut=gsub("-Reviews-.*$","",liens[1]) fin=gsub("^.*-Reviews-","",liens[1]) liens=c(liens,paste(debut,chgt,fin,sep="")) tmp=X[rep(ligne,nb.liens),] tmp$lien=liens Y=rbind(Y,tmp) } } names(Y)[1]="root" names(Y)[names(Y)=="lien"]="url" write.table(Y,file="knime-workspace/data/pages_restaurants.csv",row.names=FALSE,col.names=TRUE,sep=";") http://www.math.unicaen.fr/~kauffman/cours 3 [email protected] 1er décembre 2015 Université de Caen Basse-Normandie 1.4 Département de Mathématiques et Mécanique B-Extraction des avis de la clientèle Dans cette partie, on va extraire tous les avis sur tous les restaurants Caennais à l’aide du fichier résultat de l’étape précédente pages_restaurants.csv. Figure 3 – Flux de processus 1. Lire le fichier résultat de l’étape précédente knime://LOCAL/data/pages_restaurants.csv avec le noeud CSV Reader 2. Démarrer une boucle sur les résultats avec le noeud Chunk Loop Start, pour chacune des pages lues (a) Lire le contenu des pages avec le noeud HttpRetriever. (b) Transformer le contenu html en XML grâce au noeud HtmlParser. (c) Grace au noeud Xpath, extraire le champs //dns:div[contains(@class, ’reviewSelector’)], la nouvelle colonne s’appelera complete review et son type sera Node-Set. (d) Grâce au noeud Column Filter retirer les deux champs Result et XML Document. (e) On fait une boucle sur chacun des avis avec le noeud Ungroup. Dans la colonne include on prendra la variable complete review. (f) A l’aide du noeud Xpath et du noeud de jointure de table Joiner par Row ID extraire les champs de types caractères. Les résultats seront du type chaine de caractères. user name grâce à la requête Xpath //dns:div[contains(@class,’username’)] review text grâce à la requête Xpath //dns:p[@class=’partial_entry’] stars grâce à la requête Xpath //dns:img[contains(@class, ’sprite-rating_s_fill rating_s_fill’)]/@alt review title grâce à la requête Xpath //dns:span[@class=’noQuotes’] review id grâce à la requête Xpath //dns:div[contains(@class, ’reviewSelector’)]/@id date grâce à la requête Xpath //dns:span[contains(@class,’ratingDate’)]/@title id identifiant de l’auteur grâce à la requête Xpath //dns:img[contains(@class,’ID’)]/@class (g) Fermer la boucle avec le noeud Loop End. 3. Selectionner les lignes sans valeurs manquantes pour le champs review_id. 4. On veut retirer les passages à la lignes de tous les champs de type chaı̂nes de caractères afin de ne pas avis difficultés dans le fichier de sauvegarde au format csv. A l’aide du noeud String Manipulation en utilisant l’expression replace(variable,"\n",".") remplacer tous les passages à la ligne par un point. La colonne résultat remplacera la colonne d’entrée. Les variables sont review text, cuisine, stars, user name, review title, date. On peut aissi utiliser le module String Replacer avec l’expression régulière [\n\r]+. 5. Grâce à un noeud CSV Writer écrire la table résultat au format csv avec les noms de colonnes, comme séparateur le point virgule. Le nom du fichier sera liste_avis.csv. 1.5 C-Création de la matrice avis -mots cles. Cette partie est un exemple standard d’analyse de texte. http://www.math.unicaen.fr/~kauffman/cours 4 [email protected] 1er décembre 2015 Université de Caen Basse-Normandie Département de Mathématiques et Mécanique Figure 4 – Flux de processus Dans cette partie, et pour chacun des avis, on va — pour chacun des avis annoter chacun des mots : sujets, verbes, compléments — pour chacun des avis filtrer le texte : enlever les chiffres, la ponctuation, mettre en minuscules, lemmatiser, filtrer suivant la nature du mot lemmatiser ( ne prendre que les sujets par exemple). — sélectionner des mots clés parmi les lemmes fréquents — construire la matrice appelée “document-term matrix” dont les colonnes sont les indicatrices de la présence du mot-clé et les lignes sont les avis. Ici on propose une méthode automatique. La difficulté majeure de cette étape est d’introduire les connaissances du demandeur par exemple remplacer plusieurs mots ayant un sens proche par un seul mot. Cette étape peut être longue. 1. Lire le fichier résultat de l’étape précédente knime://LOCAL/data/liste_avis.csv à l’aide du noeud CSV Reader. 2. On construit une nouvelle identifiant chaque avis à l’aide du Noeud String Manipulation. L’expression replace($$ROWID$$,"Row","") remplace dans la colonne ROWID la chaı̂ne ”ROW” par la chaı̂ne vide. La nouvelle colonne s’appelera ID. 3. A l’aide du noeud Row Filter supprimer les lignes ayant le champs review title vide. 4. A l’aide du noeud Strings to Document transformer les avis en documents knime. En respectant les options suivantes : Title Review Title Full text Review text Authors user name Source and Category Choisir les options suivantes Uses sources from column url Use categories from column ID ce champs va servir comme identifiant de l’avis dans la suite, ce n’est pas une utilisation normale. 5. Grâce au noeud Column Filter sélectionner toutes les colonnes exceptées Reviews, Resturant, Category, user name, review title review text. Visualiser le résultat grâce au noeud Document Viewer. Rechercher des expressions régulières dans les avis : qualité.* ( ce sont les mots commenceant par qualité qualité/prix, qualité-prix, ne pas oublier de cliquer sur la loupe. 6. Grâce au noeud POS Tagger on enrichit les documents en annotant à chacun des mots avec son type sémantique : nom, verbe, adjectif, ... 7. Grâce au noeud Bow ”’Bag Of Words” transformer l’avis qui est une chaı̂ne de caractères en liste de mots. 8. Avec le module TF calculer la fréquence relative de mots clés. 9. Avec le noeud Frequency Filter sélectionner les mots clés ayant des fréquences relatives comprises supérieures à 10%. 10. Vous pouvez éventuellement observer le résultat avec le noeud Tag Cloud. On pourra visualiser les mots en fonction de leurs annotations. http://www.math.unicaen.fr/~kauffman/cours 5 [email protected] 1er décembre 2015 Université de Caen Basse-Normandie 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 abbrev CC CD DT EX FW IN JJ JJR JJS LS MD NN NNS NNP NNPS PDT POS PRP PRP$ RB RBR RBS RP SYM TO UH VB VBD VBG VBN VBP VBZ WDT WP WP$ WRB Département de Mathématiques et Mécanique type Coordinating conjunction Cardinal number Determiner Existential there Foreign word Preposition or subordinating conjunction Adjective Adjective, comparative Adjective, superlative List item marker Modal Noun, singular or mass Noun, plural Proper noun, singular Proper noun, plural Predeterminer Possessive ending Personal pronoun Possessive pronoun Adverb Adverb, comparative Adverb, superlative Particle Symbol to Interjection Verb, base form Verb, past tense Verb, gerund or present participle Verb, past participle Verb, non-3rd person singular present Verb, 3rd person singular present Wh-determiner Wh-pronoun Possessive wh-pronoun Wh-adverb Table 3 – Liste des annotations Figure 5 – Nuage de mots par annotation 11. On fait une suite d’opérations relativement constantes dans cette étape de pre-processing. Number Filter On enlève les chiffres en particulier les références à des prix. Punctuation Erasure On enlève toute la ponctuation. N Chars Filter On ne conserve que les mots ayant plus de 3 caractères. Stop word on supprime tous les mots de liaison, pronom, .... Généralement il faut supprimer d’autres mots que ceux prévus par défaut. Case converter mettre tous les caractères en minuscule. Snowball stemmer c’est un lemmatiseur qui travaille avec les textes français. Il est aussi disponible sous R avec le package SnowballC. http://www.math.unicaen.fr/~kauffman/cours 6 [email protected] 1er décembre 2015 Université de Caen Basse-Normandie Département de Mathématiques et Mécanique Pos filter filtrage éventuel par type (nom, adverbe, verbe , ...). 12. Dans cette partie on va créer la matrice appelée “document term matrix”. (a) Avec le noeud Document Vector créer la matrice. Quelle est le nombre de lignes ? Pourquoi a t-on moins de lignes que d’avis ? (b) Avec le noeud Document Data Extrator on va extraire le champs Category on nous avons caché l’identifiant de l’avis. (c) Avec le noeud Column Filter sélectionner toutes les variables quantitatives ( les fonctions indicatrices des mots clés) ainsi que la colonne Category. 13. Dans cette dernière partie on fait une jointure pour avoir une table ayant en ligne l’ensemble des avis et en colonnes les fonctions indicatrices, mais aussi les champs initiaux. (a) Faire une jointure des tables : la table gauche sera sortie du noeud Row Filter ( table sans les review vides) et de la table de droite “document term matrix”. La jointure sera — Left Outer Join pour avoir tous les avis initiaux — La clé de la table de gauche sera ID la clé de la table de droite sera Category. — On sélectionnera toutes les colonnes de la table de droite ainsi que toutes les colonnes de la table de gauche exceptée Category. (b) Comme on va avoir des valeurs manquantes dans la matrice “document term”, on utilise le noeud d’imputation des valeurs manquantes Missing Value. Choisir uniquement l’option pour les colonnes quantitatives Double Columns de remplacer les valeurs manquantes par 0 Fix Value. (c) Terminer enfin en utilisant le noeud Table Writer pour écrire cette table dans un format binaire knime dans le fichier dt-matrix.table. 14. Avec le Document Viewer rechercher les occurences de certains lemmes en utilisant l’expression régulière lemme.*. 1.6 D-Analyse des avis Dans cette partie on essaye de connaı̂tre ce qui influe les clients dans leurs notations en nombre d’étoile. Figure 6 – Flux de processus 1. A l’aide du noeud Table Reader Lire la table knime://LOCAL/data/dt-matrix.table. 2. A l’aide du noeud String Replacer créer une nouvelle colonne baptisée etoiles qui vaut le nombre d’étoiles données au restaurant par le client. On pourra remplacer l’expression régulière [1234]|5 étoiles par la chaine vide et remplacer toutes les occurrences. 3. Proposer un modèle expliquant le nombre d’étoiles en fonctions des variables disponibles. http://www.math.unicaen.fr/~kauffman/cours 7 [email protected]