ClassificationRTexte

Classification Bayésienne Naïve avec R

Pour faire suite au billet précédent, une analyse similaire est réalisée cette fois-ci à l’aide de R.

La mise en forme textuelle est réalisée à l’aide des fonctions de la librairie tm (text mining) et l’analyse bayésienne à l’aide de l’implémentation disponible dans la librairie e1071.

Chargement des données

A partir des données stockées en base, on récupère sous forme de data-frames le dataset d’apprentissage (train_set), celui de test (test_set) ainsi que la liste des mots vides.

> library(ROracle)
Le chargement a nécessité le package : DBI
Warning message:
le package ‘DBI’ a été compilé avec la version R 3.2.1 
> ora = Oracle()
> cnx = dbConnect(ora, username="rafa", password="rafa", dbname="S1401037:1521/STATPDB")
> train_set <- dbGetQuery(cnx, "select * from TRAIN_SET_BOOKS")
> test_set <- dbGetQuery(cnx, "select * from TEST_SET_BOOKS")
> mots_vides <- dbGetQuery(cnx, "select * from MOTS_VIDES")
> dbDisconnect(cnx)
[1] TRUE
> 

Mise en forme des données

> train_set$CATEGORIE <- as.factor(train_set$CATEGORIE)
> test_set$CATEGORIE <- as.factor(test_set$CATEGORIE)
> summary(train_set)
                    CATEGORIE      EXTRAIT         
 litterature-sentimentale:5419   Length:16104      
 philo-socio             :4578   Class :character  
 polar                   :6107   Mode  :character  
Warning message:
In summary(train_set) : bytecode version mismatch; using eval
>

On crée ensuite une fonctions CreeCorpus permettant de mettre en forme le texte sous la forme d’une représentation appelée Corpus.

Les appels à tm_map permettent d’appliquer des transformations (minuscule, suppression de la ponctuation, des nombres, des mots vides et des espaces) aux tokens. A noter qu’on préfère créer notre propre fonction replacePunctuation plutôt que d’utiliser la méthode removePunctuation de tm_map dans la mesure où cette dernière ne remplace pas les symboles par un espace (celui-ci -> celuici).

> library(tm)
Le chargement a nécessité le package : NLP
>
> replacePunctuation <- function(x) {
+ gsub("[[:punct:]]+", " ", x)
+ }
> 
> CreeCorpus <- function(x) {
+ Crp <- Corpus(VectorSource(x))
+ Crp <- tm_map(Crp, content_transformer(tolower))
+ Crp <- tm_map(Crp, content_transformer(replacePunctuation))
+ Crp <- tm_map(Crp, removeNumbers)
+ Crp <- tm_map(Crp, removeWords, mots_vides$MOT)
+ Crp <- tm_map(Crp, stripWhitespace)
+ return(Crp)
+ }
> 

L’échantillon d’apprentissage ainsi que celui de test sont convertis sous la forme de Corpus de mots:

> TrainCorpus <- CreeCorpus(train_set$EXTRAIT)
> TestCorpus <- CreeCorpus(test_set$EXTRAIT)
> 

Les Corpus sont ensuite transformés en matrices Documents-Termes (on supprime au passage les mots de moins de 3 lettres):

> TrainDTM <- DocumentTermMatrix(TrainCorpus, control=list(minWordLength=3))
> TestDTM <- DocumentTermMatrix(TestCorpus, control=list(minWordLength=3))
>
> TrainDTM
<<DocumentTermMatrix (documents: 16104, terms: 73329)>>
Non-/sparse entries: 1091034/1179799182
Sparsity           : 100%
Maximal term length: 29
Weighting          : term frequency (tf)
> 

On voit que la matrice d’apprentissage contient 16104 documents représentant plus de 74429 mots. L’essentiel de cette matrice est vide (Sparsity 100%) dans la mesure ou peu de mots se retrouvent dans beaucoup de documents.

On va donc essayer de réduire cette matrice en se focalisant sur les mots les plus fréquents. Pour cela on utilise la fonction findFreqTerms – ici on s’intéresse aux termes présents dans plus de 100 documents, il y en a 2170 que l’on stocke dans le vecteur mots_freq:

> length(findFreqTerms(TrainDTM, 100))
[1] 2170
> mots_freq <- findFreqTerms(TrainDTM, 100)
> 

On restreint ensuite les matrices Termes-Documents sur la base de cette liste de mots fréquents:

> TrainDTMFreq <- TrainDTM[,mots_freq]
> TestDTMFreq <- TestDTM[,mots_freq]
> 

Finalement, pour pouvoir réaliser une analyse Bayésienne, il faut « binariser » les données : on ne conserve pas l’information du nombre d’occurrence d’un mot dans un document mais plutôt l’information de sa présence ou non.

Le résultat est stocké sous forme de dataframes:

> TrainDTMFreq.bin <- TrainDTMFreq > 0
> TrainDTMFreq.bin <- apply(TrainDTMFreq.bin, MARGIN = 2, as.factor)
> 
> TestDTMFreq.bin <- TestDTMFreq > 0
> TestDTMFreq.bin <- apply(TestDTMFreq.bin, MARGIN = 2, as.factor)
> 
> TrainDTMFreq.bin[c(222,900,281),c(10,200,800)]
     Terms
      accepte beauté  force  
  222 "TRUE"  "FALSE" "FALSE"
  900 "FALSE" "FALSE" "TRUE" 
  281 "FALSE" "TRUE"  "FALSE"
> 

Classification Bayésienne

On construit le classifieur à l’aide de la fonction naiveBayes de e1071:

> library(e1071)
> nb_classifier <- naiveBayes(TrainDTMFreq.bin,train_set$CATEGORIE, laplace=1)
> 

Le scoring est effectué sur l’échantillon de test:

> nb_predict <- predict(nb_classifier, TestDTMFreq.bin)
>

La performance du classifieur est très bonne avec un taux de réussite de prédiction de ~92%:

> table(nb_predict,test_set$CATEGORIE)
                          
nb_predict                 litterature-sentimentale philo-socio polar
  litterature-sentimentale                     1599           3   143
  philo-socio                                     4        1513    12
  polar                                         229          47  1878
> 
> 100*sum(diag(table(nb_predict,test_set$CATEGORIE)))/dim(test_set)[1]
[1] 91.93073
> 

Laisser un commentaire

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