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]