Text mining avec R

De EduTech Wiki
Aller à la navigation Aller à la recherche

Cet article est une ébauche à compléter. Une ébauche est une entrée ayant un contenu (très) maigre et qui a donc besoin d'un auteur.

Voir aussi:

Il faudrait diviser la page en:

  • Concepts et survol d'outils (laisser ici)
  • Analyses et/ou bibliothèques spécifiques à mettre ailleurs

- Daniel K. Schneider (discussion) 8 octobre 2014 à 14:48 (CEST)

Introduction

Paquets R

Il existe plusieurs paquets utiles pour effectuer des analyses exploratoires de textes

  • tm (paquet text mining populaire)
    • tm.plugin.mail
    • tm.plugin.webmining
  • stringi (permet de manipuler des chaines de caractères)
  • proxy (analyses de proximités)
  • mallet (apprentissage machine, utile pour topic modeling)
  • lda (similaire à mallet)
  • XML (manipulation de fichiers XML/HTML)
  • sentiment (analyse de sentiments)
  • RTextTools (classification automatique de textes, 9 méthodes à choix)
  • maxent (classification automatique de textes avec "maximum entropy" akd multinomial logistic regression)
  • lsa (latent semantic analysis)
  • koRpus (plusieurs outils, notamment des opérations de bases, des indices populaires de "readabilité" et de diversité, une interface avec TreeTagger)
  • ....

Sources de données

R permet de digérer des formats de documents divers. Dans nos examples, nous allons nous concentrer sur:

Importer des fichiers avec le paquet tm

tm est le paquet "text mining" le plus populaire de R. Comme on va surtout travailler avec ce paquet, il va falloir l'installer si nécessaire.

Le paquet tm est conçu pour marcher avec une variété de formats: textes simples, articles/papiers en PDF ou Word, documents Web (HTML, XML, SGML), etc. Il fournit entre autre les fonctionnalités suivantes:

  • Un dispositif pour analyser des corpus (une structure de données avec des fonctions de construction)
  • Une fonction pour appliquer des fonctions à l'ensemble des textes d'un corpus.
  • Des fonctions nouvelles pour l'analyse de textes

Pour utiliser tm: library(tm)

Si nécessaire, installez ce paquet avec R-Studio ou tapez: install.packages("tm")

Importation de documents et corpus

Le Corpus est la structure R qui représente une collection de documents que l'on veut analyser. Cette structure doit être construite en important des textes.

Il existe 2 versions:

  • VCorpus alias >code>Corpus (volatile, lorsqu'on arrête R, il faut reconstruire le corpus ...
  • PCorpus (persistant, définit un endroit unique où le corpus est stocké)

Syntaxe de Vcorpus:

Vcorpus(Objet source, 'reader)
par exemple:
VCorpus( DirSource(txt, encoding = "UTF-8"), readerControl = list(language = "fr") )

Pour construire un corpus, il faut donc donner deux arguments

  1. Identifier un type de 'source de données: soit DataframeSource, DirSource, URISource, vectorSource ou XMLSource
  2. Definir le reader, c-a-d. on manière dont le texte est lu avec readerControl, notamment readDOC, readPDF, readPlain, readXML, readTabular.

Le type de sources et de readers de votre installation R peut être affiché avec les commandes suivantes:

 getReaders() # affiche toute la liste de readers
 getSources() # affiche la liste des types de sources

Chaque source possède un lecteur (reader) par défaut. Par exemple pour DirSource, c'est readPlain.

Exemple lecture de fichiers textes du tutoriel officiel en format UTF-8

Ces fichiers se trouvent déjà dans l'installation de R, d'où l'utilisation de system.file

# Tester si un répertoire existe et retourner son nom complet
# Tester et stocker le nom d´un sous-répertoire tm/texts/txt dans votre bibliothèque système
txt <- system.file("texts", "txt", package = "tm")
# Charger le texte de chaque fichier
ovid <- VCorpus(DirSource(txt, encoding = "UTF-8"), readerControl = list(language = "lat"))

Inspection et utilisation de corpus

Pour vérifier les contenus on peut afficher le tout ou encore juste quelques éléments, par exemple:

# print a short overview
print(ovid)

# show all
inspect(ovid)
ovid

# display the second document
ovid[[2]]

Lecture de fichiers locaux

Pour lire un ensemble de fichier locaux,on conseille de les mettre dans un sous-répertoire d'un répertoire pour le text mining.

le "working directory" définit le répertoire de travail par défaut, selon la logique de votre plateforme. On peut modifier ce working directory.

# Afficher le répertoire de travail courrant
getwd()
[1] "C:/Users/dschneid/Documents"
# changer le répertoire de travail
setwd "C:/dks/R"

On peut utiliser la fonction file.path pour indiquer ou trouver des fichiers d'une façon indépendante de la plateforme. Si sous Windows, les fichiers se trouvent dans D:\data\exemples\txt, utilisez du code comme chemin <- file.path("d:", "data", "exemples", "txt") . Pour indiquer un sous-répertoire du répertoire courant, utilise qc. comme file.path (".", "textes").

Enfin, on peut aussi utiliser une syntaxe symple de type "Unix": D:/data/exemples/txt. Les "/" marchent sous Unix, Mac et Windows, les "\" ne marcheront pas tels quels.

Exemple: Lire plusieurs fichiers "text" dans un corpus

Voici un exemple plus concret pour Unix. Quelques documents, c-a-d. des fichiers *.text/txt simples, se trouvent dans un répertoire /home/schneide/schneide/methodo/R/ex. On va les importer dans un corpus "tm".

On vérifie le working directory et on charge la bibliothèque tm

getwd()
 [1] "/home/schneide"
library(tm)

On définit le chemin:

archive_test <- file.path ("schneide", "methodo", "R", "ex")

On affiche les fichiers du répertoire:

dir (archive_test)
 [1] "how-to-get-a-phd.text"                               
 [2] "In-the-beginning-was-the-command-line-Stephenson.txt"
 [3] "logic-and-qual-res.text"  
 ...

On crée un corpus

library(tm)
corpus.source <- Corpus(DirSource(archive_test))

On examine le corpus

# short summary information
show (corpus.source)
print (corpus.source)
 <<VCorpus (documents: 6, metadata (corpus/indexed): 0/0)>>

On peut aussi examiner des détails

#Affiche tout (inutile, car trop)
inspect(corpus.source)
# Afficher le premier document, 
inspect(corpus.source[1])

Lire du PDF et du WORD

Il existe des filtres (readers) pour ces 2 types de documents (pas testés). A tester: il est possible qu'il vaut mieux enregistrer Word comme PDF et ensuite utiliser le filtre PDF.

Installation de xpdf

Sous Windows:

  • Téléchargez l'archive zip de sourceforge (download)
  • Dézippez et copiez soit les fichiers 32bit, soit les 64 bit dans un répertoire. Je conseille c:\soft\xpdf. Donc après l'opération vous devriez y voir 9 fichiers, dont pdftotext.exe.
  • Editez le chemin d'exécutables de Windows et ajoutez ce répertoire. Lire Fichier_de_commande si vous ne savez pas le faire.
  • Finalement, dans notre installation il manquait jpeg8.dll. On a copié/collé un fichier trouvé dans l'installation de calibre dans ce répertoire ....


Résumé de la syntaxe:

 chemin <- file.path ("...")
 corp <- Corpus (DirSource (chemin), readerControl=list (reader=readDOC))  
 corp <- Corpus (DirSource (chemin), readerControl=list (reader=readPDF))

Exemple:

library(tm)
# CHANGEZ ICI si nécessaire
# setwd ("./R")
# setwd("/home/schneide/schneide/methodo/R")
setwd("s:/methodo/R")
getwd()
archive_test <- file.path (".", "PDF")
dir (archive_test)
corpus.source_de_PDF <- Corpus(DirSource(archive_test), readerControl=list (reader=readPDF))
show (corpus.source_de_PDF)
# A la fin de ces fichiers il y a un form feed (ctrl-L) 
# qu'on devrait éliminer. \r représente ce caractère
for (j in seq (corpus.source_de_PDF)) {
  corpus.source_de_PDF[[j]] <- gsub ("\r","", corpus.source_de_PDF[[j]])
}
inspect (corpus.source_de_PDF[1])
# On écrit les fichiers txt dans un répertoire. Facilite la vérification.
writeCorpus(corpus.source_de_PDF, path="./PDF_txt")

Aspirer des pages web

Il existe plusieurs méthodes et libraries pour lire des pages web. Selon le type de de besoin on peut travailler avec les fonctions R "standardes" ou avec des bibliothèques ou une combinaison des deux. Une fois qu'on a constitué un corpus, il faut "nettoyer" les textes, voir le chapitre suivant.

Création d'un corpus avec tm

Les fonctions "Corpus" du paquet tm permettent de lire des URLs (voir les exemple Mediawiki ci-dessous).

Principe:

  • On définit une liste d'URLS et on la donne comme paramètre à la fonction Corpus
liste_URLs <- c("http://tecfa.unige.ch", "http://unige.ch/")
#On construit le corpus
Corpus.brut <- Corpus(URISource(list_URLs), readerControl = list(language="fr"))

La librairie tm.plugin.webmining

On conseille d'installer le paquet tm.plugin.webmining car il combine l'aspiration avec des filtres HTML/XML et des fonctions toutes prêtes pour analyses des contenus qui viennent de Reuters, Yahoo, etc. Ce plugin nécessite également les paquets "XML" et "CURL" et qui seront installés automatiquement si tout va bien.

  • Ce package nécessite Java, probablement une version de développement. Sous Unix il faut aussi dire à R où Java se trouve (sous root)
  • Sous Win8, le package s'installe sans problème, mais ne trouve pas Java (Win8). Il faut soit bricoler les chemins d'environnement soit (plus facile) installer Java JDK, donc le kit de développement.

Dans une console Linux (sous root), pour indiquer l'emplacement de Java, taper:

sudo R CMD javareconf.

Dans Linux, il faut également installer préalablement des bibliothèques de développement Curl et XML, sinon vous allez recevoir des messages d'erreurs comme ERROR: configuration failed for package ‘RCurl’, rm: cannot remove 'a.out.dSYM': Is a directory

sudo apt-get install libcurl4-openssl-dev
sudo apt-get install libxml2-dev

Ensuite, on peut installer le paquet. Alternativement, utilisez la facilité "Install" de RStudio.

install.packages("tm.plugin.webmining")

Il existe d'autres logiciels de web scraping (trois sont listés dans la vignette R Short Introduction to tm.plugin.webmining. Il faut envisager d'utiliser ces outils externes lorsque vous téléchargez des gros volumes.

Charger la bibliothèque

library("tm.plugin.webmining")

On peut assez facilement enregistrer une page web. La solution pour débutant est un simple "save as". Par contre il est moins simple d'éliminer les contenus inutiles (menus, etc). Donc déjà pour commencer, il faut chercher a télécharger une version "print".

Le package tm.plugin-webmining contient un certain nombre de fonctions utiles, et notamment:

extractContentDOM (url, threshold, asText ...)
  • url définit la source, par exemple une URL
  • theshold définit une sorte de "force" de filtrage de div's inutiles
  • asText est une variable booléenne, mettre à FALSE pour un URL

Examples:

# threshold pour une page classique
test1 <- extractContentDOM("http://tecfa.unige.ch",0.1,FALSE)
# threshold qui marche pour edutechwiki
test2 <- extractContentDOM("http://edutechwiki.unige.ch/fr/Happy_Night",0.5,FALSE)
# identique à test2
test3 <- extractContentDOM("http://edutechwiki.unige.ch/fmediawiki/index.php?title=Happy_Night&printable=yes",0.5,FALSE)

Avec la bibliothèque XML

Selon les explications de Reading HTML pages in R for text processing, par Luis, 2011

  • htmlTreeParse permet de lire une page HTML
  • On peut ensuite extraire des listes de paragraphes basés sur une balise
library(XML)
doc = htmlTreeParse("http://tecfa.unige.ch/", useInternal=TRUE)
# Extraction des contenus des balises p, li, h1 et td
doc2 = unlist(xpathApply(doc, "//p|//li|//h1|//td", xmlValue))
# Virer les retour de lignes et tabs \n\t
doc3 = gsub('\\n', ' ', doc2)
doc3 = gsub('\\t', ' ', doc3)
# Joindre tout dans un seul string
doc.text = paste(doc3, collapse = ' ')

Créer un corpus avec des pages MediaWiki

Selon les besoins d'analyse on choisira une ou une autre méthode pour lire des pages Mediawiki. Il nous semble qu'il est préférable d'utiliser la méthode "XML" expliquée dans la sous-section suivante.

Utilisation de fonctions R de base pour lire dans des vecteurs

Cette méthode marchera avec n'importe quelle page HTML.
library(tm)
library(stringi)
library(proxy)
# le nom du wiki
wiki <- "http://edutechwiki.unige.ch/fr/"
# une liste de noms de pages
titles <- c("STIC:STIC_I_-_exercice_1_(Utopia)", "STIC:STIC I - exercice 1 (Nestor-Pixel)", 
            "STIC:STIC_I_-_exercice_2_(Utopia)",
            "STIC:STIC III (2012)/Module 1",  "STIC:STIC III (2012)/Module 2")

# un vecteur qui contient 5 strings vides ("")
articles <- character(length(titles))

# lecture des contenus des pages wiki. Chaque article se trouvera dans un des string ci-dessous.
for (i in 1:length(titles)) {
    articles[i] <- stri_flatten(readLines(stri_paste(wiki, titles[i])), col = "")
}

# Création d un corpus avec les articles
docs <- Corpus(VectorSource(articles))

Aspirer les pages en HTML brut avec tm

(ne semble pas marcher sous Linux, OK sous Windows)

library(tm)
#Une longue procédure pour avoir une liste d'articles dans un string
wiki <- "http://edutechwiki.unige.ch/fr/"
titles <- c("Activate", "Cité romaine", "Citéjob-négo", "Darfur is dying", 
            "Eonautes", "FacteurAcademy", "Happy Night", "InfinITy",
            "J'apprends J'entreprends", "Mon entretien d'embauche", 
            "Timeout", "Tree Frog")
# un vecteur qui contient 12 strings vides ("")
article_list <- character(length(titles))
# on remplace par les URLs ci-dessus
for (i in 1:length(titles)) {
  article_list[i] <- (paste (wiki,titles[i], sep=""))
}
#Vérification
article_list

#On construit le corpus
# wiki.source <- URISource(article_list)
wiki.source <- Corpus(URISource(article_list), readerControl = list(language="fr"))
# Vérification
wiki.source

#Inspecter le corpus
inspect(VCorpus(wiki.source))

Méthode "XML" pour Mediawiki

Les MediaWiki ont une API qui autorise l'extraction de contenus de pages sans les textes qui font partie des menus. Un bon exemple est ce wiki. On peut afficher son API:

http://edutechwiki.unige.ch/fmediawiki/api.php

Cette montre quel type d'informations on peut exporter facilement

Nous allons nous intéresser à l'extraction du contenu d'une page sous format XML. Il va aussi falloir la nettoyer, mais moins qu'avec les méthodes qui lisent toute la page ou qui se basent sur des algorithmes de détection du corps. Voici un exemple:

http://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page=Civilization&format=xml

Le script R ci-dessous fait l'extraction d'un ensemble de pages crées par des étudiants dans le cadre d'un.

library(tm)
#Une longue procédure pour avoir une liste d'URLs d'articles wiki dans un string
url_start <- "http://edutechwiki.unige.ch/fmediawiki/api.php?action=parse&page="
url_end <- "&format=xml"
titles <- c("Activate", "Cité romaine", "Citéjob-négo", "Darfur is dying", 
            "Eonautes", "FacteurAcademy", "Happy Night", "InfinITy",
            "J'apprends J'entreprends", "Mon entretien d'embauche", 
            "Timeout", "Tree Frog")
# un vecteur qui contient 12 strings vides ("")
article_list <- character(length(titles))
# on remplace par les URLs ci-dessus
for (i in 1:length(titles)) {
  article_list[i] <- (paste (url_start,titles[i],url_end, sep=""))
}
#Vérification
article_list

# On construit le corpus en utilisant un reader fait par nous et
# extrait juste l'élément "text" 
readMWXML <- 
  readXML (spec = list (content = list ("node", "//text"),
                        category = list ("node", "//categories/cl")
                        ),
                        doc=PlainTextDocument())

wiki.source <- Corpus(URISource(article_list, encoding="UTF-8"),
                      readerControl=list(reader=readMWXML)
                    )

#Inspecter le corpus
wiki.source
inspect(wiki.source)
inspect(wiki.source[1])

#Avant d'enregistrer (pas nécessaire),
# il faut changer les "id" sinon on obtient des noms de fichiers illégaux
for (j in seq.int (wiki.source)) {
  meta(wiki.source[[j]],"id") <- titles[j]
}
writeCorpus(wiki.source, path="./wiki_txt")

On a maintenant une série de documents "bruts" qui incluent le "corps" d'une page wiki et qu'il va falloir nettoyer. Voici le début d'un fichier

<div style="border:1px solid grey;background-color:#FFAABB;padding:7px; margin-bottom: 10px;">
<p style="text-align:center;font-weight:bold;">
Page  réalisée dans le cadre du cours <a rel="nofollow" class="external text" href="http://vip-tetris.mixxt.com/">Jeux Vidéo Pédagogiques (VIP)</a><br /> (volée  "Tetris" 2013-2014) de la formation <a rel="nofollow" class="external text" href="http://tecfalabs.unige.ch/maltt/master/qui-sommes-nous/">maltt</a>, au <a rel="nofollow" class="external text" href="http://tecfa.unige.ch/">TECFA</a>.</p>
<p style="text-align:center;font-weight:bold;">
Cette page est une ébauche en cours de réalisation. Ne pas citer.</p>
</div>
.....

On va réutiliser ces données dans le chapitre suivant.

Transformations de Corpus "tm"

Il existe un certain nombre de fonctions qui permet de "nettoyer" le texte d'un Corpus. La construction <tm_map> permet de appliquer une transformation à l'ensemble des textes d'un corpus. Parfois les fonctions fournies par "tm" ne suffisent pas et on doit faire des calculs plus "manuels".

Les fonctions de transformation

Partant avec un corpus, appelé corpus0, on peut effectuer plusieurs opérations de transformation, par exemple:

stripWhitespace()
Enlève les blancs en trop
corpus1 <- tm_map(corpus0, stripWhitespace)
tolower();
Met tous les mots en minuscules
corpus2 <- tm_map(corpus1, tolower)
removeWords(....),
Enlever des mots
Par exemple des stopwords en Anglais: corpus3 <- tm_map(corpus2, removeWords, stopwords("english"))
ou en français: corpus5 <- tm_map(corpus3, removeWords, stopwords("french"))
ou une liste explicite de mots: xxx = tm_map(corpus2, removeWords, c("Daniel", "Kaspar", "TECFA"))
removePunctuation()
Enlever les ponctuations
removeNumber()
Enlever des nombres
stemDocument()
Faire du stemming
  library(SnowballC)
  corpus9 = stemDocument(corpusx, language = meta(corpusx, "language"))

On peut obtenir cette liste des transformations de tm avec la fonction:

getTransformations()

Certaines manipulations doivent se faire avec d'autres paquets ou encore avec les fonctions de base de R. Notamment la substitution de caractères:

Remplacer des caractères (merci à Graham Williams)
for (j in seq (corpus0)) {
  corpus0[[j]] <- gsub ("/", " ", corpus0[[j]])
  corpus0[[j]] <- gsub ("@", " ", corpus0[[j]])
 ......
}

On peut aussi utiliser des expression régulières, par exemple une qui tue une balise XML/HTML dans un string.

gsub("<.*/>","",string)

Ceci dit, les regexp ne marchent pas très bien pour enlever des balises HTML. Il vaut mieux utiliser une fonction du plugin tm.plugin.webmining

wiki.clean <- tm_map (wiki.source, extractHTMLStrip, encoding="UTF-8")

Exemple EduTechWiki (suite)

L'exemple suivant transforme les textes d'un corpus qu'on a crée ci-dessus avec la méthode "XML".

library(tm)
library(tm.plugin.webmining)

#VOIR CI-DESSUS, il nous faut un corpus sous forme de simples vecteurs de caractères.
wiki.source

#---------- Transformer des pages wiki en listes de mots 
# On va gaspiller de la mémoire, c-a-d créer un nouveau corpus pour chaque opération
# Avantage: On peut revenir plus facile, explorer des alternatives, etc.

# Tuer les balises. Attention à l'encodage !! 
wiki.clean1 <- tm_map (wiki.source, extractHTMLStrip, encoding="UTF-8")

# Alternative
# for (j in seq.int (wiki.source)) {
#  wiki.source[[j]] <- extractHTMLStrip(wiki.source[[j]])
# }

# Une expression régulière simple ne trouve qu'un élément: inutile
# for (j in seq.int (wiki.source)) {
#  wiki.source[[j]] <- gsub("<.*/>","",wiki.source[[j]])
# }

# Tuer les blancs, les ponctuations, les apostrophes du texte
# le mot "[modifier]", manque encore les URLs

wiki.clean2a <- tm_map (wiki.clean1, stripWhitespace)

# Replacing curly quotes does not work because it can't distinguish from straight quotes)
# Such behavior is not acceptable whatever the programmer's reasons could be.
# Anyhow, if you use some UTF-8 hex code it may work.
# U+2019 = ’
# \0xE2\0x80\0x98
for (j in seq.int (wiki.clean2a)) {
  wiki.clean2a[[j]] <- gsub("\u2019"," ",wiki.clean2a[[j]])
}
# test
wiki.clean2a[[5]]

for (j in seq.int (wiki.clean2a)) {
  wiki.clean2a[[j]] <- gsub("'"," ",wiki.clean2a[[j]])
}

for (j in seq.int (wiki.clean2a)) {
  wiki.clean2a[[j]] <- gsub("[«»”“\"]"," ",wiki.clean2a[[j]])
  wiki.clean2a[[j]] <- gsub("\\[modifier\\]"," ",wiki.clean2a[[j]])
}

# enlever les ponctuations qui restent
wiki.clean2b <- tm_map (wiki.clean2a, removePunctuation)

# encore une fois
wiki.clean2c <- tm_map (wiki.clean2b, stripWhitespace)

# Mettre tout en minuscules
wiki.clean3 <- tm_map (wiki.clean2c, tolower)
# Tuer les mots fréquents (stop words)
wiki.essence <- tm_map (wiki.clean3, removeWords, stopwords("french"))

# Extraire les racines. La bibliothèque SnowballC doit être installée.
getStemLanguages()
wiki.racines <- tm_map (wiki.essence, stemDocument, language="french")
wiki.racines <- tm_map (wiki.racines, stripWhitespace)

Méthodes d'analyse

Analyses basées sur une matrice documents X termes

Créer des matrices

Une matrice documents-termes (Angl: Document Term Matrix (DTM) liste la fréquence de mots par document. Il existe deux variantes, un matrice "documents par termes" ou une matrice "termes par documents" comme c'est expliqué dans l'article text mining.

Pour construire une matrice il faut utiliser soit DocumentTermMatrix, soit TermDocumentMatrix. Le corpus doit inclure les meta data qui on pu disparaître lors d'opérations de transformation, donc il faut les remettre comme ci-dessous

# Du Vodoo pour de nouveau créer un "vrai corpus"
wiki.mots <- Corpus(VectorSource(wiki.racines))
matrice_docs_termes <- DocumentTermMatrix(wiki.mots)

Reduction de la matrice

Notre matrice_termes_docs contient environ 2400 mots et que l'on pourra réduire

inspect(matrice_termes_docs)

removeSparseTerms enlève les mots que l'on retrouve dans moins de 40 et 60% des documents. Autrement dit, plus on réduit la proportion, moins on des mots.

inspect(removeSparseTerms(matrice_termes_docs, 0.4))
inspect(removeSparseTerms(matrice_termes_docs, 0.6))

Voilà les mots aimés par tous les auteurs ....

inspect(removeSparseTerms(matrice_termes_docs, 0.01))
<<TermDocumentMatrix (terms: 32, documents: 12)>>
Non-/sparse entries: 384/0
Sparsity           : 0%
Maximal term length: 12
Weighting          : term frequency (tf)

              Docs
Terms           1  2  3  4  5 6  7  8  9 10 11 12
  20132014      1  1  1  1  1 1  1  1  1  1  1  1
  cadre         1  1  1  1  4 1  1  1  1  6  3  1
  citer         1  1  1  1  1 1  1  2  1  1  1  1
  contenu       5 10  2  7  6 3  6  7  4  6  5  2
  cours         4  3  2  2  4 3  4  5  2  5  2  2
  description   2  2  2  2  2 2  3  2  2  5  3  2
  doit          5  6  2  1 16 2  8  8  2  5 10  9
  ébauche       1  1  1  1  1 1  1  1  1  1  1  1
  enseigné      4  8  2  4  6 2  5  5  3  2  5  2
  fait          3  8  1  1  1 1  3  1  2  4  3  2
  formation     1  1  1  1  1 3  1  1  1  1  1  1
  forts         4  3  2  2  4 2  4  4  3  4  4  4
  intégration   2  3  2  3  4 2  4  5  2  3  3  3
  jeu          37 38 14 20 26 8 46 50 33 69 29 14
  jeux          4 11  1  3  3 1  5  3  1  4  1  2
  joueur       33 15  1  2 35 2 22 25 13 23  1 22
  logiciels     2  2  2  2  2 2  3  4  4  2  2  4
  maltt         1  1  1  1  1 1  1  1  1  1  1  1
  page          2  2  2  2  2 2  4  2  2  4  2  2
  pédagogiques  3  5  3  3  3 3  4  3  3  5  3  4
  point         2  1  2  3  2 2  2  1  6  7  5  5
  points        6  6  2  3  6 2  9  6  5 12  4  6
  principes     2  2  2  3  3 2  2  2  3  3  3  3
  réalisation   1  1  1  1  1 1  1  1  1  1  1  1
  réalisée      1  1  1  1  1 1  1  1  1  1  1  1
  similaires    2  2  2  2  3 2  2  2  2  2  2  2
  sommaire      1  1  1  1  1 1  1  1  1  1  1  1
  tecfa         1  1  1  1  1 1  1  1  1  1  1  1
  tetris        1  1  1  1  1 1  1  1  1  1  1  1
  vidéo         1  1  1  1  1 1  2  3  1  3  2  1
  vip           1  1  1  1  3 1  1  1  1  1  1  1
  volée         1  1  1  1  1 1  1  1  1  1  1  1

Voici une liste de mots que l'on retrouve dans au moins 40% des documents:

Non-/sparse entries: 848/160
Sparsity           : 16%
Maximal term length: 13
Weighting          : term frequency (tf)

               Docs
Terms            1  2  3  4  5 6  7  8  9 10 11 12
  20132014       1  1  1  1  1 1  1  1  1  1  1  1
  accès          2  2  0  3  8 1  4  2  1  1  2  0
  actions        1  1  0  1  3 0  3  0  1  1  3  0
  agit           5  0  1  1  0 1  3  0  2  2  1  4
  ainsi          4  0  1  0  2 0  5  3  0  4  1  1
  apprentissage  6  8  0  0 11 0  1  4  1  4  4  5
  aussi          6  2  1  1  0 1  0  3  1  5  3  1
  avant          1  3  1  0  1 0  1  1  0  3  1  0
  bien           3  6  0  1  5 3  6  1  0  5  2  0
  but            6  1  0  0  2 0  4  1  1  3  1  3
  cadre          1  1  1  1  4 1  1  1  1  6  3  1
  cas            1  2  0  1  2 0  0  2  1  3  5  0
  certains       1  1  0  2  2 0  0  0  1  3  2  1
  chaque         3  1  0  0  5 2  3  8  3  1  0  1
  choisir        6  1  1  2  2 0  2  1  3  2  0  0
  choix          9  0  1  0  0 0 10  1  6  8  2  1
  citer          1  1  1  1  1 1  1  2  1  1  1  1
  comme          2  3  0  0  3 0 12  5  0 11  1  1
  connaissances  5  0  0  1  3 0  1  2  1  1  4  0
  contenu        5 10  2  7  6 3  6  7  4  6  5  2
  cours          4  3  2  2  4 3  4  5  2  5  2  2
  description    2  2  2  2  2 2  3  2  2  5  3  2
  deux           5  3  0  1  0 0  2  1  2 11  6  1
  différents     3  2  1  0  0 0  4  9  3  1  3  0
  doit           5  6  2  1 16 2  8  8  2  5 10  9
  donc           2  3  0  0  6 1  3  0  1  1  4  7
  ébauche        1  1  1  1  1 1  1  1  1  1  1  1
  écran          0  2  1  3  2 0  2  3  3  2  5  0
  enseigné       4  8  2  4  6 2  5  5  3  2  5  2
  entre          1  2  1  0  0 0  4  2  6  3  0  3
  environnement  4  2  0  1  3 1  1  1  1  3  2  0
  être           8  2  0  0  0 1  4  5  1  5  4  1
  exemple        8  5  0  1  4 1  7  6  3  6  4  2
  faibles        4  3  2  2  4 2  0  4  3  4  4  4
  faire          5  0  1  1  4 1  8  2  3  9  1  4
  fait           3  8  1  1  1 1  3  1  2  4  3  2
  faut           9  2  0  1  2 0  3  3  1  2  1  4
  feedback       0  7  0  0  5 0  6  3  2  7  9  4
  fin            3  0  0  0  5 1  4  5  1 11  1  1
  fois           3  4  3  0  0 0  2  4  2  4  2  1
  formation      1  1  1  1  1 3  1  1  1  1  1  1
  forts          4  3  2  2  4 2  4  4  3  4  4  4
  informatique   2  2  0  1  3 1  0  5  1  2  2  0
  intégration    2  3  2  3  4 2  4  5  2  3  3  3
  internet       2  1  0  1  2 0  0  1  1  1  0  1
  jeu           37 38 14 20 26 8 46 50 33 69 29 14
  jeux           4 11  1  3  3 1  5  3  1  4  1  2
  jouer          0  3  2  0  2 1  2  2  0  1  0  2
  joueur        33 15  1  2 35 2 22 25 13 23  1 22
  logiciels      2  2  2  2  2 2  3  4  4  2  2  4
  long           1  2  0  1  1 0  4  1  0  1  0  1
  lors           5  1  0  0  2 0  1  4  1  9  1  0
  maltt          1  1  1  1  1 1  1  1  1  1  1  1
  manière        2  5  1  0  6 0  2  1  0  0  1  2
  mécanique      2  3  0  3  4 2  9  4  2  7  3  0
  niveau        28  1  0  2  2 0  3  8  3  0  3  1
  objectif       2  2  0  1  1 1  3  2  2  7  0  2
  page           2  2  2  2  2 2  4  2  2  4  2  2
  passer         1  2  0  0  3 0  1  2  0  2  1  3
  pédagogique    4  9  1  3  1 0  0  2  1  2  1  3
  pédagogiques   3  5  3  3  3 3  4  3  3  5  3  4
  permet         2  1  0  0 10 0  2  6  4  2  1  4
  personne       2  0  1  0  1 0  2  1  3  2  1  0
  peut           4 11  1  2 12 0  4  5  4 17  4  3
  plus          11 11  2  0  4 0  9  2  1 13  2  5
  point          2  1  2  3  2 2  2  1  6  7  5  5
  points         6  6  2  3  6 2  9  6  5 12  4  6
  possible       5  1  1  0  3 0  2  1  0  1  1  1
  prendre        0  2  1  0  2 1  2  1  1  1  0  0
  principes      2  2  2  3  3 2  2  2  3  3  3  3
  quelques       1  3  1  0  2 0  1  2  0  2  0  1
  réalisation    1  1  1  1  1 1  1  1  1  1  1  1
  réalisée       1  1  1  1  1 1  1  1  1  1  1  1
  similaires     2  2  2  2  3 2  2  2  2  2  2  2
  sommaire       1  1  1  1  1 1  1  1  1  1  1  1
  sous           1  2  1  1  0 2  2  5  0  7  1  1
  tecfa          1  1  1  1  1 1  1  1  1  1  1  1
  temps          1  3  0  3  7 1  1  0  0  2  8  0
  tetris         1  1  1  1  1 1  1  1  1  1  1  1
  tout           2  7  1  4  4 0  6  1  0  3  2  3
  type           0  1  0  0  1 0  1  1  2  1  1  2
  vidéo          1  1  1  1  1 1  2  3  1  3  2  1
  vip            1  1  1  1  3 1  1  1  1  1  1  1
  volée          1  1  1  1  1 1  1  1  1  1  1  1

Visualisation d'une matrice termes-documents

La matrice suivante donne la même vision que ci-dessus, mais avec un graphique. Enfin pour augmenter la lisibilité on baissé le seuil de mots à montrer à la présence d'au moins 80% des documents (0.2 = absent dans moins que 20%).

Pour créer ces visualisations, on ne peut pas utiliser les données brutes (enfin j'imagine qu'il doit bien exister une bibliothèque pour cela). A la place on fait une transformation qui nous ramène à des valeurs < 1 et qui représentent le "poids" d'un terme comme expliqué dans l'article text mining. Mais attention, on ne s'est pas documenté sur l'algorithme (weightTf) utilisé, il y a peut-être mieux à faire....

# Créer une DTM avec des poids normalisées
mtd.norm <- as.matrix(removeSparseTerms(
  TermDocumentMatrix(wiki.mots, control=list(weighting=weightTf)),
  0.2))
corrplot (mtd.norm, is.corr=FALSE)
Plot "Weighted term-document matrix by term frequency"

On voit que le mot "jeu" domine largement "le débat" dans tous les textes. Pour mieux faire ressortir les autres distributions, on peu éliminer ces mots. Ci-dessous on utilise un style de "programmation" plus dense. On commence par le corpus "wiki-mots" et on enlève 3 mots. Ensuite le tout est est transformé en matrice termes-documents "weighted" (qui donne des "poids" aux termes", puis on l'a épuré de tous les mots qui se trouvent dans moins de 40% de documents.

# Créer une DTM avec des poids normalisées inverses
mtd.norm_sans <- as.matrix(
  removeSparseTerms(
    TermDocumentMatrix(
      tm_map(wiki.mots, removeWords, c("jeu", "jeux", "joueur")),
      control=list(weighting=weightTfIdf)
    ),
    0.4)
)
corrplot (mtd.norm_sans, is.corr=FALSE)
Plot "Weighted term-document matrix by term frequency"

Voici une matrice qui montre les poids inversés (ne sais pas à quoi cela pourrait servir dans ce contexte)

library(corrplot)
# Créer une DTM avec des poids normalisés
mtd.norm <- as.matrix(removeSparseTerms(
  TermDocumentMatrix(wiki.mots, control=list(weighting=weightTfIdf)),
  0.4))
# Plot simple
corrplot (mtd.norm, is.corr=FALSE)
Plot "Weighted term-document matrix by term frequency - inverse document frequency"

Tableaux de termes fréquents

Rappelons que nos textes on été épurés (pas de stop words, des racines). Ceci dit, il nous semble que le "stemming" ne marche pas bien (à vérifier pourquoi). Le code suivant liste tous les mots qui sont utilisé au moins 30 fois.

 findFreqTerms(matrice_docs_termes, 30)

Résultat:

 [1] "apprentissage" "bien"          "choix"         "comme"        
 [5] "contenu"       "cours"         "deux"          "doit"         
 [9] "enseigné"      "être"          "exemple"       "faibles"      
[13] "faire"         "fait"          "feedback"      "fin"          
[17] "forts"         "intégration"   "jeu"           "jeux"         
[21] "joueur"        "logiciels"     "mécanique"     "mission"      
[25] "niveau"        "pédagogiques"  "permet"        "peut"         
[29] "plus"          "point"         "points"        "principes"    
[33] "tout"          "utilisateur"

Associations mot avec un mot

Quels mots sont utilisés souvent avec "feedback" dans un document ?

# find associations with a word
findAssocs(matrice_termes_docs, "feedback", 0.8)
            feedback
explication     0.84
haut            0.83
milieu          0.80

findAssocs(matrice_termes_docs, "feedback", 0.7)
            feedback
explication     0.84
haut            0.83
milieu          0.80
premier         0.77
car             0.76
expérience      0.76
etc             0.71
travers         0.71

Corroboration des lois de Zipf et de Heap

Lire:

Zipf_plot(matrice_termes_docs)
 (Intercept)          x 
  6.6338162  -0.8466039
Zipf plot d'un corpus de fiches sur les jeux pédagogiques
Heaps_plot(matrice_termes_docs)
 (Intercept)          x 
  0.9737307   0.7676657
Heaps plot d'un corpus de fiches sur les jeux pédagogiques

Word Clouds

Les words clouds peuvent utiliser des palettes.

# Afficher les palettes des couleurs pour pouvoir mieux choisir
display.brewer.all()
Palettes du brewer

La fonction wordcloud(...) de la bibliothèque wordcloud permet de créer des wordcloud en utilisant plusieurs paramètres, par exemple:

scale=vecteur avec 2 nombres
Définit l'empan de la taille des mots (plus grand/ plus petit)
min.freq = nombre
Définit un seul de fréquence. Au-dessous les mots sont éliminés
colors = liste de couleurs
du plus fréquent au moins fréquent
max.words = nombre
Max. mots à afficher. Les moins fréquents sont éliminés.
vfont=c("nom","variante"))
définit la fonte.

Ci-dessous on crée plusieurs words clouds pour des documents invidiuels

# Wordclouds
library(wordcloud)
wordcloud(wiki.racines[[5]],
          scale=c(5,0.1), rot.per=0.35, 
          min.freq=3, use.r.layout=FALSE,
          colors= brewer.pal(8,"Spectral")
          )
wordcloud(wiki.racines[[8]],
          scale=c(5,0.1), rot.per=0.35, 
          min.freq=3, use.r.layout=FALSE,
          colors= brewer.pal(8,"Spectral")
)
wordcloud(wiki.racines[[9]],
          scale=c(5,0.1), rot.per=0.35, 
          min.freq=3, use.r.layout=FALSE,
          colors= brewer.pal(8,"Spectral")
)
wordcloud(wiki.racines[[3]],
          scale=c(5,0.1), rot.per=0.35, 
          min.freq=3, use.r.layout=FALSE,
          colors= brewer.pal(8,"Spectral")
)
Word cloud d'une fiche (page wiki) sur un jeu pédagogique

Ci-dessous des clouds qui résument et comparent à travers le corpus

#Communality clouds

mtd <- as.matrix(matrice_termes_docs)
comparison.cloud(mtd,random.order=FALSE,
                 scale=c(5,0.5), rot.per=0.35, 
                 max.words=50, use.r.layout=FALSE,
                 colors= brewer.pal(8,"Spectral")
)
commonality.cloud(mtd,random.order=FALSE,
                  scale=c(5,0.5), rot.per=0.35, 
                  max.words=50, use.r.layout=FALSE,
                  colors= brewer.pal(8,"Spectral")
)

Etant donne que le mot "jeu" domine trop, on pourrait l'éliminer

#Without the "jeu"

wiki.sans_jeu <- tm_map(wiki.mots, removeWords, c("jeu", "jeux"))
mtd2 <- TermDocumentMatrix(wiki.sans_jeu)
mtd2 <- as.matrix(mtd2)
commonality.cloud(mtd2,random.order=FALSE,
                  scale=c(2,0.5), rot.per=0.35, 
                  max.words=50, use.r.layout=FALSE,
                  colors= brewer.pal(8,"Spectral")
)
Word cloud commune d'un corpus

Topic Modeling

(à faire)

Liens

Articles d'introduction

  • Ingo Feiner (2014). Introduction to the tm Package Text Mining in R, http://cran.r-project.org/web/packages/tm/vignettes/tm.pdf
    • Official "vignette" (introductory text included with the package). Quote: “This vignette gives a short introduction to text mining in R utilizing the text mining framework provided by the tm package. We present methods for data import, corpus handling, preprocessing, metadata management, and creation of term-document matrices.”
  • Ingo Feinerer, Kurt Hornik, David Meyer (2008). Text Mining Infrastructure in R, Journal of Statistical software, Vol. 25, Issue 5, http://www.jstatsoft.org/v25/i05/ (open contents)
    • Article complet par les auteurs du package et qui introduit le paquet tm (version 2008). Il contient aussi des exemples.

Exemples et/ou textes informels

  • Text mining with R (slides) by Aleksei Beloshytski
    • Montre (superficiellement) notamment comment analyser un blog, c'est à dire extraire les contenus, puis extraire les thèmes les plus populaires, clustering, etc.

Statistiques

Q/A Stackoverflow

Lire du XML
HTML scraping