Nous souhaitons classifier un article du monde selon son contenu,

Nous possèdons pour cela un jeu de données avec la catégorie et le contenu de 10k articles.

Pour mener notre tâche à bien nous allons effectuer un prétraitement des données textuelles par la transformation de données (textuelles) non structurées en un format de données structuré.

Et ce dans l’objectif d’appliquer des algorithmes de classifications, cela inclut la pondération et la sélection des variables(des mots).

Concrètement, il s’agit de la transformation d’un grand nombre de caractéristiques éparses en un nombre significativement plus petit de caractéristiques denses.

Nous utiliserons ainsi 3 algorithmes pour la classification dont un dans une version limitée à 25 variables explicatives.

Nous finirons par l’évaluation des résultats de la prédiction des classifications sur le jeu de test.

Résumé
    • Ensemble variables explicatives Xi : nbre d’occurences des mots dans l’article.
    • Variable à expliquer : la catégorie de l’article.
    • Fonction de perte/évaluation : Matrice de confusion/AUC
    • Algorithmes : CART, RandomForest, SVM
    • Méthode pour éviter le sur-apprentissage : Validation croisée.

Introduction



## Import de la base de données & du jeu test

On utilise l’encodage UTF-8 car le monde est un journal français utilisant des caractères spéciaux. Le jeu de test est fournis, il a pour élément positif le fait d’être un article de type économie

data <- 
   read.csv("le_monde.csv", encoding="UTF-8", sep=";", comment.char="#")
test <- 
  read.csv("lignes_jeux_tests.csv")

Transformation des données



Il est nécessaire de transformer ces données, nous n’avons qu’une unique variable explicative : le texte en entier de l’article. Cette unique variable explicative est inexploitable, nous souhaitons un “bag of words”.

Suppression des deux collones non utiles à la modélisation

data$date <- NULL
data$title <- NULL



Nous n’avons pas à réaliser la gestion des manquants, tâche qui peut s’avérer très complexe. on supprime les lignes avec des valeurs manquantes (normalement aucune supprimmé)

## integer(0)



On applique les bons types de variables

data$category <- as.factor(data$category)
data$content <- as.character(data$content)
str(data)
## 'data.frame':    10000 obs. of  2 variables:
##  $ category: Factor w/ 6 levels "culture","economie",..: 6 5 5 2 5 5 5 5 1 5 ...
##  $ content : chr  "  / L’international français Jérémy Ménez va rejoindre le club de Bordeaux en Ligue 1, en provenance du Milan A"| __truncated__ "  / Le cousin d’un des assassins du Père Jacques Hamel à Saint-Etienne-du-Rouvray, identifié comme étant Farid "| __truncated__ "  / Si le premier ministre Manuel Valls constate que « l’islam a trouvé sa place dans la République », « face à"| __truncated__ "  / Les épargnants français sont choyés. Lundi 1er août, le taux de rémunération du Livret A aurait théoriqueme"| __truncated__ ...



On retire les accents, en effet dans l’une des étapes suivantes où l’on retire les caractères qui ne sont pas des lettres, les lettres avec accents font des trous dans les mots, rendant un grand nombre de mots inexploitable.

Une méthode plus professionel lors de l’import a été découvert à postériori



On a besoin d’un objet de type corpus, on prend là ou sont les données, ici la collone content. On affiche la première ligne

contenu <- Corpus(VectorSource(data$content))
contenu[1]$content
## [1] "  / L'international francais Jeremy Menez va rejoindre le club de Bordeaux en Ligue 1, en provenance du Milan AC, sous reserve de la traditionnelle visite medicale, a annonce le club aquitain dimanche. /  Menez est la troisieme recrue des Girondins apres le milieu de Monaco, Jeremy Toulalan, et l'attaquant guineen de Bastia, Francois Kamano. Bordeaux sort d'une pale saison et repart avec des ambitions nouvelles et l'entraineur Jocelyn Gourvennec, qui jouit d'une grosse cote grace a ses six saisons convaincantes a Guingamp. Age de 29 ans, Menez, qui compte 24 selections (2 buts) chez les Bleus -la derniere en 2013-, evoluait depuis deux ans au Milan AC, ou il lui restait un an de contrat, mais sa derniere saison a ete perturbee par des blessures. Forme a Sochaux, Menez fait partie de la fameuse generation 1987 championne d'Europe des U17 en 2004. Alors considere comme un des plus grands espoirs du foot francais, il avait par la suite rejoint Monaco de 2006 a 2008, puis la Roma pendant quatre saisons avant de revenir en France, au Paris-Saint-Germain en 2012. Son aventure parisienne, avec deux titres de champion a la cle, avait pris fin deux ans plus tard pour un retour en Italie, au Milan AC. Au sein de l'equipe lombarde il a realise sa meilleure saison (16 buts inscrits) en 2014-2015, avant d'etre perturbe par des blessures au dos la saison derniere qui l'ont prive de sept mois de competition, d'aout a janvier, pour ne disputer que 10 matchs (2 buts)."



On supprime les caracteres qui ne sont pas des lettres (cette étape posait problème avec les lettres à accent)

contenu <- tm_map(contenu, content_transformer(gsub), pattern = "[^a-zA-Z]", replacement = " ")
                 
contenu[1]$content
## [1] "    L international francais Jeremy Menez va rejoindre le club de Bordeaux en Ligue    en provenance du Milan AC  sous reserve de la traditionnelle visite medicale  a annonce le club aquitain dimanche     Menez est la troisieme recrue des Girondins apres le milieu de Monaco  Jeremy Toulalan  et l attaquant guineen de Bastia  Francois Kamano  Bordeaux sort d une pale saison et repart avec des ambitions nouvelles et l entraineur Jocelyn Gourvennec  qui jouit d une grosse cote grace a ses six saisons convaincantes a Guingamp  Age de    ans  Menez  qui compte    selections    buts  chez les Bleus  la derniere en        evoluait depuis deux ans au Milan AC  ou il lui restait un an de contrat  mais sa derniere saison a ete perturbee par des blessures  Forme a Sochaux  Menez fait partie de la fameuse generation      championne d Europe des U   en       Alors considere comme un des plus grands espoirs du foot francais  il avait par la suite rejoint Monaco de      a       puis la Roma pendant quatre saisons avant de revenir en France  au Paris Saint Germain en       Son aventure parisienne  avec deux titres de champion a la cle  avait pris fin deux ans plus tard pour un retour en Italie  au Milan AC  Au sein de l equipe lombarde il a realise sa meilleure saison     buts inscrits  en            avant d etre perturbe par des blessures au dos la saison derniere qui l ont prive de sept mois de competition  d aout a janvier  pour ne disputer que    matchs    buts  "



On mets les majuscules en minuscules

contenu <- tm_map(contenu, content_transformer(tolower))
contenu[1]$content
## [1] "    l international francais jeremy menez va rejoindre le club de bordeaux en ligue    en provenance du milan ac  sous reserve de la traditionnelle visite medicale  a annonce le club aquitain dimanche     menez est la troisieme recrue des girondins apres le milieu de monaco  jeremy toulalan  et l attaquant guineen de bastia  francois kamano  bordeaux sort d une pale saison et repart avec des ambitions nouvelles et l entraineur jocelyn gourvennec  qui jouit d une grosse cote grace a ses six saisons convaincantes a guingamp  age de    ans  menez  qui compte    selections    buts  chez les bleus  la derniere en        evoluait depuis deux ans au milan ac  ou il lui restait un an de contrat  mais sa derniere saison a ete perturbee par des blessures  forme a sochaux  menez fait partie de la fameuse generation      championne d europe des u   en       alors considere comme un des plus grands espoirs du foot francais  il avait par la suite rejoint monaco de      a       puis la roma pendant quatre saisons avant de revenir en france  au paris saint germain en       son aventure parisienne  avec deux titres de champion a la cle  avait pris fin deux ans plus tard pour un retour en italie  au milan ac  au sein de l equipe lombarde il a realise sa meilleure saison     buts inscrits  en            avant d etre perturbe par des blessures au dos la saison derniere qui l ont prive de sept mois de competition  d aout a janvier  pour ne disputer que    matchs    buts  "



On retire les lettres isolés et les mots “vides” tel “quand, comme, hors …”

stopwords_fr <- stopwords("french")
stopwords_fr <- c(stopwords_fr, "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t",
                   "u","v","w","x","y","z" )
contenu <- tm_map(contenu, removeWords , stopwords_fr)
contenu[1]$content
## [1] "     international francais jeremy menez va rejoindre  club  bordeaux  ligue     provenance  milan ac  sous reserve   traditionnelle visite medicale   annonce  club aquitain dimanche     menez   troisieme recrue  girondins apres  milieu  monaco  jeremy toulalan    attaquant guineen  bastia  francois kamano  bordeaux sort   pale saison  repart   ambitions nouvelles   entraineur jocelyn gourvennec   jouit   grosse cote grace   six saisons convaincantes  guingamp  age     ans  menez   compte    selections    buts  chez  bleus   derniere         evoluait depuis deux ans  milan ac     restait  an  contrat    derniere saison  ete perturbee   blessures  forme  sochaux  menez fait partie   fameuse generation      championne  europe            alors considere comme   plus grands espoirs  foot francais      suite rejoint monaco              puis  roma pendant quatre saisons avant  revenir  france   paris saint germain         aventure parisienne   deux titres  champion   cle   pris fin deux ans plus tard   retour  italie   milan ac   sein   equipe lombarde   realise  meilleure saison     buts inscrits              avant  etre perturbe   blessures  dos  saison derniere    prive  sept mois  competition   aout  janvier    disputer     matchs    buts  "



Racinisation (sans retirer le premier espace)

contenu <- tm_map(contenu, stemDocument, "french")
#contenu[1]$content
contenu <- tm_map(contenu , stripWhitespace)
contenu <- tm_map(contenu, content_transformer(gsub), pattern = "^\\s+", replacement = "")
contenu[1]$content
## [1] "international franc jeremy men va rejoindr club bordeau ligu proven milan ac sous reserv traditionnel visit medical annonc club aquitain dimanch men troisiem recru girondin apre milieu monaco jeremy toulalan attaqu guineen basti francois kamano bordeau sort pal saison repart ambit nouvel entraineur jocelyn gourvennec jou gross cot grac six saison convainc guingamp age an men compt select but chez bleus dernier evolu depuis deux an milan ac rest an contrat dernier saison ete perturbe blessur form sochal men fait part fameux gener champion europ alor consider comm plus grand espoir foot franc suit rejoint monaco puis rom pend quatr saison avant reven franc paris saint germain aventur parisien deux titr champion cle pris fin deux an plus tard retour ital milan ac sein equip lombard realis meilleur saison but inscrit avant etre perturb blessur dos saison dernier priv sept mois competit aout janvi disput match but"



Vectorisation

Nous ne gardons que les mots avec 1000 occurences minimum



Le traitement de text effectué, on re-ajoute les données au tableau data pour comparer le texte de départ et le texte obtenu :

Le texte obtenu est correct.

Combien de fois les mots (variables) ont d’occurence dans le contenu des articles ?

summary(colSums(base_modele))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1000    1228    1612    2229    2491   18858

On remarque une médiane à 1612 la haute valeur du maximum est surement dû à des mots vides (stop words) non retirer. Nous étudierons un modèle avec moins de variables (mots) dans une prochaine partie.



Testons notre hypothèse des stop words non retirer, en effet, il pourrait s’agir de mots apparaissant beaucoup dans une certaine catégorie d’articles. Regardons dans combien d’articles les mots sont référencés (sur 10k articles)

occurences <- apply(base_modele, 2, function(x) sum(x>0))
summary(occurences)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   364.0   871.5  1101.0  1392.7  1676.5  6237.0

Un maximum à 6237, soit 2/3 des documents. Nous verrons l’importance de ces mots dans le modèle lorsque nous réaliserons un modèle supervisé avec un maximum de 25 variables.



On construit alors notre modèle avec les catégories et les mots en variables.

base_modelisation = cbind.data.frame(data, base_modele)
base_modelisation = base_modelisation[,-2]
base_modelisation = base_modelisation[,-2]



#On prépare le jeu à 25 variables
#Somme <- colSums(base_modele)
#garder <- which(Somme > median(Somme))



# Présentation des données



## Analyse de la dispersion

Variables à expliquer : culture, economie, planete, politique, societe, sport.

439 Variables explicatives : les mots qui apparaissent plus de 1000 fois.

A noter que nous n’effectuons que les dernières partie d’un projet de Data Science, puisque les données nous ont été fournis. Avec ni gestion des manquants, ni gestion des fautes d’orthographes/gestion de mots anglais à réaliser (puisqu’il s’agit d’articles de presse).

Avant de réaliser des modèles de prédictions, détaillons le jeu de données transformé obtenu. Notre plus grande menace serait une corrélation globale de nos variables.

Visualisons graphiquement si nos variables sont très corrélés avec une heatmap :

Les variables sont très peu corrélés !



Pour complèter cela, on réalise une analyse en composante principale avec la catégorie en variable qualitative, ainsi en affichant les ellipse nous verrons les catégories qui s’opposent et quelles variables (les mots dans notre cas) sont les plus responsables des axes, autrement dit les plus importants.

#ces deux lignes sont marginales et ne permettent pas de ce centrer sur les individus.
#base_modelisation_ACP <- base_modelisation[-c(8808,5857), ]
#library(FactoMineR)
#res.pca = PCA(base_modelisation_ACP, scale.unit=TRUE, ncp=5, quali.sup=1, graph=T)

#Essayons de dégager une tendance avec les catégories
#library("factoextra")
#fviz_pca_ind(res.pca, geom.ind = "point", col.ind = base_modelisation_ACP$category, 
 #            palette = c("#00AFBB", "#E7B800", "#FC4E07", "#33FF5E","#CC33FF", "#FFC233"  ),
  #           addEllipses = TRUE, ellipse.type = "confidence",
   #          legend.title = "Catégorie de l'article"
#)



#plot.PCA(res.pca, axes=c(1, 2), choix="ind", habillage=1,label="var",graph.type = "ggplot")

Les deux premières dimensions ne rendent compte que de 10% de la variance, les graphiques sont inexploitables. Nous pouvons affirmer que les données sont très dispersés, leur non-corrélation est très forte.

Nuage de mots pour les catégories



Une fois la non-corrélation globale de nos variables assurés, Examinons graphiquement grâce à la librairie wordcloud les mots les plus fréquents par catégorie par un nuage de mots.

#Preparation des données pour le nuage des catégories
# on concatene tout le texte , on sélectionne la catégorie sport et spécicifie content_modif pour là où on prend le texte.

#motSport <- paste(data[data$category=="sport",'content_modif'],collapse=' ') 
#motSociete <- paste(data[data$category=="societe",'content_modif'],collapse=' ') 
#motEconomie <- paste(data[data$category=="economie",'content_modif'],collapse=' ') 
#motCulture <- paste(data[data$category=="culture",'content_modif'],collapse=' ') 
#motPolitique <- paste(data[data$category=="politique",'content_modif'],collapse=' ') 
#motPlanete <- paste(data[data$category=="planete",'content_modif'],collapse=' ') 


# on compte chaque mot, le motif entre guillemet veut dire qu'on coupe la #chainedecaractère quelque soit le nombre d'espaces entre les mots, decreasing en true car il faut montrer les most les plus fréquents , donc on met en décroissant (voir la doc de sort)

#motsFreqSport <- data.frame(sort(table(strsplit(motSport,"\\s+")),decreasing = TRUE )) 
#motsFreqSociete <- data.frame(sort(table(strsplit(motSociete,"\\s+")),decreasing = TRUE )) 
#motsFreqEconomie <- data.frame(sort(table(strsplit(motEconomie,"\\s+")),decreasing = TRUE )) 
#motsFreqCulture <- data.frame(sort(table(strsplit(motCulture,"\\s+")),decreasing = TRUE )) 
#motsFreqPolitique <- data.frame(sort(table(strsplit(motPolitique,"\\s+")),decreasing = TRUE )) 
#motsFreqPlanete <- data.frame(sort(table(strsplit(motPlanete,"\\s+")),decreasing = TRUE )) 

Création des nuages de mots

Sport

#wordcloud2(data = motsFreqSport[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")



Societe

#wordcloud2(data = motsFreqSociete[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")



Economie

#wordcloud2(data = motsFreqEconomie[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")



Culture

#wordcloud2(data = motsFreqCulture[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")



Politique

#wordcloud2(data = motsFreqPolitique[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")



Planete

#wordcloud2(data = motsFreqPlanete[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")

De nombreux mots semblent spécifiques à une seule catégorie, nous devrions obtenir de bons indicateurs de prédiction. D’un point de vue descriptif, si l’on ommet les mots vides non supprimmés, on peut expliquer Y (la catégorie) selon les mots présent dans l’article. En effet, si l’article parle d’un film, cela sera un article de catégorie culture. Cependant notre objectif n’est pas descriptif mais prédictif.



Avant de passer à la partie suivante, supprimons les données que nous n’utiliserons plus



A noter que nous pouvions effectuer ce changement sur nos données, en affectant 1 si l’article est de type économie et 0 sinon.

Cependant, la prédiction de toute les catégories possible nous semble avoir plus de sens.

Nous concluerons à la fin sur l’impact de cette décision.

#data$category <- gsub("economie", "1", data$category)
#data$category <- gsub("[^1]+", "0", data$category)
#data$category <- as.numeric(data$category)



# Premier modèle : CART



## Introduction Modèle Supervisé Apprentissage supervisé: expliquer/prédire une sortie Y à partir d’entrées X Nous devons éviter le sur-apprentissage, pour cela nous utiliserons la cross validation.

CrossValidation.png

Modèle supervisé utilisés : CART , Randomforest, SVM

Liste d’autres modèles : https://topepo.github.io/caret/available-models.html

La différence essentielle entre l’apprentissage supervisé et l’apprentissage non supervisé est que l’apprentissage supervisé traite la réponse/labels, contrairement à l’apprentissage non supervisé.



On commence par construire un modèle d’apprentissage, composé de 80% des lignes de base_modelisation. Le jeu de test est quand à lui fourni.

#nb_lignes <- sample(1:nrow(base_modelisation), nrow(base_modelisation)*0.80)
training <- base_modelisation[-test$x,]
testing <- base_modelisation[test$x,]

Création du modèle CART

Notre premier modèle est un arbre de décision.

Le principe est que, tant qu’on a pas atteind la taille minimal de noeuds enfants on recherche un seuil qui permet de séparer le noeud parents en 2 noeuds enfants en maximisant notre critère de répartition/de fractionnement.

Notre critère de répartition est le GINI, il est par défaut dans la fonction rpart.

On prend un cp choisi arbitrairement.

modele_CART <-rpart(category~. ,
             data = training,
             cp=0,
             minsplit = 10
            # ,control = rpart.control(minsplit = 10)
             )
visTree(modele_CART)

CP Hyperparamètre selection



On recherche le cp optimal.

plotcp(modele_CART)



On affine la prédiction en choisissant l’arbre avec l’erreur de prédiction la plus basse

Meilleur <- which.min(modele_CART$cptable[,"xerror"])
#Meilleur
cpBest <- modele_CART$cptable[Meilleur, "CP"]
cpBest
## [1] 0.0008685079
#cpBest
Modele_Cart_Arbre <- prune(modele_CART, cp = cpBest)
visTree(Modele_Cart_Arbre)
#Mauvaise méthode puisque le meilleur cp change d'une exécution à l'autre du code
#Besttree <-rpart(category~. ,
#                 data = base_modelisation[nb_lignes,],
#                cp=8e-04,
#               minsplit = 10
                   # ,control = rpart.control(minsplit = 10)
                 
#              )
#visTree(Besttree)
#print(Besttree$cptable)



#attributes(Modele_Cart_Arbre)
#construction plot
#plot(Modele_Cart_Arbre)
#text(Modele_Cart_Arbre, use.n=T)

CART Validation croisée

Ce modèle est très sensible à l’échantillonage, d’où la grande importance de la validation croisée pour lui.

Observons combien faut-il de temps pour calculer un arbre

#debut <- Sys.time()
#tree_temps <-rpart(category~. ,
 #            data = training,
  #           cp=0,
   #          minsplit = 10
            # ,control = rpart.control(minsplit = 10)
    #         )

#TempsArbre <- Sys.time() - debut
#print(paste("Pour générer un arbre, il faut : ", TempsArbre))

11 secondes ! Soit 320 arbres générés à l’heure. Voir plus selon le nombre de coeurs logiques pouvant être utilisés pour des calculs en simultanés.



Quel paramètre devons nous optimiser pour le modèle Cart

Optimisons le cp.

Créons plusieurs modèle avec des cp différents

#cp_expand = expand.grid( .cp = seq(from = 0, to = 0.01, by = 0.00001)) 



On test un grand nbre de cp.

#require(caret)
#require(doSNOW)
  
#parametre du cv
#cv.cntrl <- trainControl(method = "cv", 
#                           number = 8, 
  #                         search = "grid")
  
 #on cree des instances , afin d'executer plus vite par l'utilisation de tout les coeurs
#mon processeur a 8 coeurs logiques , je mets donc 8,

  #cl <- makeCluster(8, 
     #               type = "SOCK") 
  #registerDoSNOW(cl)
  
  
  #set.seed(1234)
 

  #  modele_CART_CV <- train(x = training[,names(base_modelisation[nb_lignes,]) != 'category'],
    #                y = training$category,
    #                 method = 'rpart', trControl = cv.cntrl, 
      #               tuneGrid = cp_expand, metric = "Accuracy")
  

 # stopCluster(cl)
#On calcule ainsi cp expand x k-fold         = nbre d'arbres 
  #                   1000  x     8          = 8000



On affiche le modèle obtenu

#plot(modele_CART_CV)

CP Hyperparametre CV

Il s’agit pour ce modèle de l’unique hyper-parametre à optimiser.

On choisit à nouveau le cp

#modele_Cart_cv_best <- modele_CART_CV$bestTune$cp

#meilleur cp
#modele_Cart_cv_best
#0.00099

#cp_expand = expand.grid( .cp = modele_Cart_cv_best) 

cp_expand = expand.grid( .cp =  0.00099) 

#modele_cart_cv_final <- modele_CART_CV$results %>% filter(cp == modele_Cart_cv_best)



On recherche à nouveau avec le cp optimisé.

require(caret)
require(doSNOW)
## Le chargement a nécessité le package : doSNOW
## Le chargement a nécessité le package : foreach
## Le chargement a nécessité le package : iterators
## Le chargement a nécessité le package : snow
#parametre du cv
cv.cntrl <- trainControl(method = "cv", 
                           number = 8, 
                           search = "grid")
  

  cl <- makeCluster(8, 
                    type = "SOCK") 
  registerDoSNOW(cl)
  
  
  set.seed(1234)
 

    modele_CART_CV <- train(x = training[,names(testing) != 'category'],
                      y = training$category, 
                     method = 'rpart', trControl = cv.cntrl, 
                     tuneGrid = cp_expand, metric = "Accuracy")
  

  stopCluster(cl)
#modele_cart_cv_final
#print(modele_CART_CV$finalModel)



Importance des variables (si l’on choisit ce modèle pour réaliser un modèle limité à 25 variables)

sort(modele_CART_CV$finalModel$variable.importance, decreasing = TRUE)[1:25]
##     match      film     gauch      scen    polici entrepris       loi    joueur 
## 338.25537 266.60970 143.88527 128.96254 125.16730 112.54491  77.13373  74.90513 
##     final     euros      club    terror   ministr       art  festival    saison 
##  72.32423  71.88946  67.37677  60.45084  57.50156  53.68416  50.90831  50.56396 
##     selon      stad   primair     polic   enseign    demand  attentat     contr 
##  48.63564  47.82709  46.65514  40.38253  38.01587  32.66443  30.01506  29.31853 
##      livr 
##  28.68671

Deuxième modèle : Random Forest

Création du modèle RF



Modélisation : Random Forest, algorithme de bagging

Le principe est de créer n arbres non corrélés entre eux puis faire voter chacun d’entre eux.

Pour faire varier un arbre on sélectionne une partie différente des données à chaque noeud et ne construisant des arbres que sur une partie des individus

Les paramètres que nous optimiserons seront le mtry et le maxnodes (nbre de feuilles).

Le paramètre mtry représente le nombre de variables échantillonnées de façon aléatoire comme candidats à chaque fractionnement. et nbtree est le nombre d’arbres générés.

#proximité entre les lignes calculés => afin de visualiser les individus aberrants/ representer en dimension 2 
 
                          
#modele_rf = randomForest(category~. 
  #                       , data=training,
      #                   importance = T,
              #           proximity=TRUE,
                  #       ntree = 5000)
#plot(modele_rf)
#print(modele_rf)
#modele_rf
#plot(modele_rf)

On observe une stagnation de l’erreur à partir de 400 arbres, nous utiliserons cette donnée pour la cross validation(on ne la calcule pas directement sur la cross validation par manque de puissance de calcul)

A noter que pour ce modele, nous sommes passer directement à la cross validation, sans optimiser les hyperparametres de base.



#proximité entre les lignes calculés
 
                          
modele_rf = randomForest(category~. 
                       , data=training,
                       importance = T,
                        proximity=TRUE,
                         ntree = 400)
#plot(modele_rf)
#print(modele_rf)
#modele_rf
plot(modele_rf)

Cross Validation

Quels paramètres devons-nous optimiser pour le modèle randomforest. Optimisons le mtry.



Observons combien faut-il de temps pour calculer 100 arbres à mon ordinateur.

debut <- Sys.time()
cent = randomForest(category~. 
                         , data=training,
                         importance = T,
                         ntree = 100)
TempsCent <- Sys.time() - debut
print(paste("Pour cent arbres, il faut : ", TempsCent))
## [1] "Pour cent arbres, il faut :  1.87542151610057"

1 minute et 45 secondes !

En 3h, il y a 180 minutes, je peux donc générer 10 000 arbres en 3h. et en 20 minutes je peux en calculer 1000. Et ce par coeurs logiques, soit potientiellement 8 fois plus.



Créons plusieurs modèle avec des mtry allant de 1 variables à toutes. En tout 439 configurations seront testés.

#mtry_expand = expand.grid( .mtry = seq(from = 1, to = (ncol(base_modelisation[nb_lignes,])-1), length.out = 439))
#length.out : premier multiplieur



On créé un grand nombre d’arbres par random forest, avec des configurations différentes du mtry, et grace à la librairie doSNOW on execute 8 fois plus vite le code.

#require(caret)
#require(doSNOW)
  
#parametre du cv
#cv.cntrl <- trainControl(method = "cv", 
            #               number = 8, 
                   #        search = "grid")
  

 # cl <- makeCluster(8, 
         #           type = "SOCK") 
 # registerDoSNOW(cl)
  
  
  #set.seed(1234)
 
  
  #méthode random forest 
   # modele_rf_cv <- train(x = base_modelisation[nb_lignes,][,names(base_modelisation[nb_lignes,]) != 'category'],
              #        y = base_modelisation[nb_lignes,]$category, 
                #      method = 'rf', trControl = cv.cntrl, 
                 #     tuneGrid = mtry_expand, metric = "Accuracy",
                   #   ntree = 100)
    #ntree est notre dernier multiplieur.
  
  
 # stopCluster(cl)
#On calcule ainsi length.out x kfold         x ntree = nbre d'arbres de notre modèle
  #                 439      x     8         x 100   = 351 000



Quel est le meilleur paramètre pour mtry

#modele_mtry <- modele_rf_cv$bestTune$mtry
#modele_rf_cv_best <- modele_rf_cv$results %>% filter(mtry==modele_mtry)
#le meilleur mtry est de :
#modele_mtry
mtry_expand <- expand.grid(.mtry = 33.21918)
#33.21918



On affiche le modèle obtenu

#plot(modele_rf_cv)
#plot(modele_rf_cv$finalModel$predicted)



Notre m-try est optimiser, optimisons désormais le maxnodes

#require(caret)
#require(doSNOW)
  
#sauvegarde des résultats
#list_maxnode <- list()

#parametre du cv
#cv.cntrl <- trainControl(method = "cv", 
    #                       number = 8, 
          #                 search = "grid")
  

  #cl <- makeCluster(8, 
     #               type = "SOCK") 
 # registerDoSNOW(cl)
  
  
#  set.seed(1234)
 
#for (maxnodes in c(0: 1)) {
  #méthode random forest 
    #modele_rf_cv <- train(x = training[,names(testing) != 'category'],
                #      y = training$category, 
             #         method = 'rf', 
                 #     trControl = cv.cntrl, 
                  #    tuneGrid = mtry_expand, 
                 #     metric = "Accuracy",
                #      importance = TRUE, 
                #      maxnodes = maxnodes,
                 #     ntree = 100)
    #ntree est notre dernier multiplieur.
    
 #   actuel <- toString(maxnodes)
   # list_maxnode[[actuel]] <- modele_rf_cv
  
  
#  }
# stopCluster(cl)
#results_mtry <- resamples(list_maxnode)
#summary(results_mtry)


#On calcule ainsi length.out x kfold         x ntree = nbre d'arbres de notre modèle
  #                 439      x     8         x 100   = 351 000

Le modèle au maxnode optimiser a des résultats totalement similaire.

En effet, https://topepo.github.io/caret/available-models.html ne précise pas le maxnode dans les tuning parameters.



Créons le modèle final.

require(caret)
require(doSNOW)
  
#parametre du cv
cv.cntrl <- trainControl(method = "cv", 
                           number = 8, 
                           search = "grid")
  

  cl <- makeCluster(8, 
                    type = "SOCK") 
 registerDoSNOW(cl)
  
  
  set.seed(1234)
 
  
  #méthode random forest 
    modele_rf_cv <- train(x = training[,names(testing) != 'category'],
                      y = training$category, 
                      method = 'rf', trControl = cv.cntrl, 
                     tuneGrid = mtry_expand, metric = "Accuracy",
                      ntree = 700)
    #ntree est notre dernier multiplieur.
  
  
  stopCluster(cl)

Troisième modèle

test K-nn



Certains algorithmes sont très sensibles à la variance des variables, ainsi Lasso, k-nn et SVM ont besoin d’une normalisation (voir standardisation) pour obtenir des résultats corrects. Cet aspect a été oublier lors de notre premier test de k-NN

#NROW(training)
# Renvoie 8000 -> racine carré de 8000 = 89.44 -> on créé deux modèles avec un k=89 et un avec k=90 
#library(dplyr)
#data_class <- base_modelisation
#category_outcome <- data_class %>% select(category)
#category_outcome <- category_outcome %>% mutate_if(is.character, as.factor)
#category_outcome_train <- category_outcome[nb_lignes, ]
#category_outcome_test <- category_outcome[-nb_lignes, ]
#knn_89 <- knn(training[-1], testing[-1], cl=category_outcome_train, k=89)
#knn_90 <- knn(training[-1], testing[-1], cl=category_outcome_train, k=90)
#ACC_89 <- 100 * sum(category_outcome_test == knn_89)/NROW(category_outcome_test)
#ACC_90 <- 100 * sum(category_outcome_test == knn_90)/NROW(category_outcome_test)
#confusionMatrix(table(knn_89 ,category_outcome_test))
#confusionMatrix(table(knn_90 ,category_outcome_test))

Création modèle SVM



Création d’un jeu de donnée normalisé.

En effet, ce modèle ainsi que le précèdent obtiennent de bien meilleur résultat avec une transformation des données spécifiques.

Certains modèles requiert une normalization des données (variables explicatives entre 0 et 1 )

tandis que d’autres requiert une standardization ( variables explicatives suivent une loi normale centrée réduite )

training_Scale <- training
testing_Scale <- testing
training_Scale[-1] <- scale(training_Scale[-1])
testing_Scale[-1] <- scale(testing_Scale[-1])



Création du modèle SVM grâce à la librairie e1071

Une fonction kernel transforme les données en trouvant un hyperplan qui sépare les différentes catégories (problème de classification), grâce à cette fonction, nos données sont toujours linéairement séparables.





On test plusieurs fonctions kernel afin de trouver la meilleure.

#install.packages('e1071')
#library(e1071)
 
#modele_SVM = svm(formula = category~.,
#                 data = training_Scale,
  #               type = 'C-classification',
    #             kernel = 'linear')

# radial kernel est meilleur
library(e1071)
## Warning: le package 'e1071' a été compilé avec la version R 4.1.2
modele_SVM = svm(formula = category~.,
                 data = training_Scale,
                 type = 'C-classification',
                 kernel = 'radial')

la fonction kernel radial est la meilleure , comparé aux fonctions linear et poly.

Limite du choix effectué : Nous avons comparer ces fonctions sans optimiser leurs hyperparamètres

Hyperparamètre



On optimise les paramètres (model selection) Nous choississons d’optimiser cost et epsilon

#on recherche dans une grille 
#Tune_SVM <- tune(svm, category~.,  data = training_Scale,
#ranges = list(epsilon = seq(0,1,0.2), cost = 2^(2:9))
#)

# affichage de la recherche.
#print(Tune_SVM)
#plot(Tune_SVM)

Résultat du bloc au dessus :



Recherchons dans une plus grande étendue :



On sélectionne le meilleur modèle.

#SVM_Opti <- Tune_SVM$best.model
#SVM_Opti$cost
# 4 en cost

#SVM_Opti$epsilon
# 0 en epsilon



SVM_Opti = svm(formula = category~.,
                 data = training_Scale,
                 type = 'C-classification',
                 kernel = 'radial',
               cost=4,
               epsilon=0)

Validation croisée

On compare les différentes fonction en cross-validation, on remarque que svmRadial obtient de meilleure résultat.

Quels paramètres devons nous optimiser pour le modèle SvmRadial



Optimisons les paramètres sigma et C.

Mais en prenant en compte les erreurs de l’optimisation du modèle svm simple : l’étendu de recherche était mal défini.

Réalisons une recherche préliminaire pour savoir dans quels interval devons rechercher nos paramètres à optimiser.

#require(caret)
#require(doSNOW)

#library(caret)
#library(dplyr)         
#library(kernlab)  
  
#parametre du cv
#trCtrl <- trainControl(method="repeatedcv",   
      #               repeats=10    ,
               #      summaryFunction=twoClassSummary,  
            #         classProbs=TRUE
            #         )
  

 # cl <- makeCluster(8, 
        #            type = "SOCK") 
 # registerDoSNOW(cl)
  
  
 # set.seed(1234)
 
  
  #méthode SVM avec fonction kernel radial 
 # modele_SVM_CV <- train(
  # category~ .,
  # data = training_Scale,
 #  method = 'svmRadial',
  #   tuneLength = 15,  
  # preProcess = c("center", "scale"),
  #    metric="Accuracy",
  # trCtrl = trCtrl
 #)
    
  
 
   #stopCluster(cl)
 #
 #modele_SVM_CV

On remarque que la zone de recherche correct pour le cost est autour de la valeur 2

Et pour le sigma autour de la valeur 0.002

On recherche les paramètres optimaux dans cette zone de recherche restreinte.

require(caret)
require(doSNOW)
library(caret)
library(dplyr)         
## 
## Attachement du package : 'dplyr'
## L'objet suivant est masqué depuis 'package:randomForest':
## 
##     combine
## Les objets suivants sont masqués depuis 'package:stats':
## 
##     filter, lag
## Les objets suivants sont masqués depuis 'package:base':
## 
##     intersect, setdiff, setequal, union
library(kernlab)  
## 
## Attachement du package : 'kernlab'
## L'objet suivant est masqué depuis 'package:ggplot2':
## 
##     alpha
expand_cost_sigma <- expand.grid(sigma = c(.001, .002, 0.003),
                    C = c(1.5, 1.75, 2, 2.25, 2.5)
)

#parametre du cv
trCtrl <- trainControl(method="repeatedcv",   
                     repeats=10 ,
                     summaryFunction=twoClassSummary,   
                     classProbs=TRUE
                     )
  

  cl <- makeCluster(8, 
                    type = "SOCK") 
  registerDoSNOW(cl)
  
  
  set.seed(1234)
 
  
  #méthode SVM avec fonction kernel radial 
  modele_SVM_CV <- train(
  category~ .,
  data = training_Scale,
  method = 'svmRadial',
  tuneGrid = expand_cost_sigma,
  preProcess = c("center", "scale"),
     metric="Accuracy",
  trCtrl = trCtrl
)
    
  
 
  stopCluster(cl)

modele_SVM_CV
## Support Vector Machines with Radial Basis Function Kernel 
## 
## 8000 samples
##  439 predictor
##    6 classes: 'culture', 'economie', 'planete', 'politique', 'societe', 'sport' 
## 
## Pre-processing: centered (439), scaled (439) 
## Resampling: Bootstrapped (25 reps) 
## Summary of sample sizes: 8000, 8000, 8000, 8000, 8000, 8000, ... 
## Resampling results across tuning parameters:
## 
##   sigma  C     Accuracy   Kappa    
##   0.001  1.50  0.6635317  0.5746915
##   0.001  1.75  0.6640209  0.5756002
##   0.001  2.00  0.6640889  0.5759654
##   0.001  2.25  0.6642238  0.5763886
##   0.001  2.50  0.6644552  0.5768228
##   0.002  1.50  0.6565708  0.5645027
##   0.002  1.75  0.6568310  0.5650595
##   0.002  2.00  0.6564455  0.5647635
##   0.002  2.25  0.6560522  0.5644086
##   0.002  2.50  0.6554451  0.5637814
##   0.003  1.50  0.6357728  0.5351418
##   0.003  1.75  0.6352501  0.5346765
##   0.003  2.00  0.6346026  0.5340215
##   0.003  2.25  0.6338689  0.5332327
##   0.003  2.50  0.6334332  0.5327455
## 
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 0.001 and C = 2.5.





# Comparaison modèle

under-fitting lorsque notre modèle créé prédit avec beaucoup d’erreurs sur le jeu d’entrainement et de test. over-fitting lorsque notre modèle créé prédit avec très peu/aucune erreur le jeu d’entrainement mais avec beaucoup d’erreur le jeu de test.

Evaluation du premier modèle

CART [0.86]



Prédictions

#jeu d'entrainement
p_CART_train <- predict(Modele_Cart_Arbre,
             newdata=training,
           # newdata=test,  
           #trouver un moyen d'utiliser le jeu de test
           # type= "class"
             type= "class"
           )

#jeu de test
p_CART <- predict(Modele_Cart_Arbre,
             newdata=testing,
           # newdata=test,  
           #trouver un moyen d'utiliser le jeu de test
           # type= "class"
           type= "class"
           
           )



Matrices de confusion

#length(p_CART)

#jeu entrainement
conf_CART <- confusionMatrix(data=p_CART_train, reference = training$category)
conf_CART
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      1431      178     169       121     374   181
##   economie      106      931     144       124     288    57
##   planete         7       10      79        17      21     0
##   politique      47       78      39       586     163    13
##   societe       143      217     147       231    1362    58
##   sport          31       35       9        19      35   549
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6172          
##                  95% CI : (0.6065, 0.6279)
##     No Information Rate : 0.2804          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.5174          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.8108          0.6425       0.134583
## Specificity                  0.8359          0.8902       0.992581
## Pos Pred Value               0.5831          0.5642       0.589552
## Neg Pred Value               0.9398          0.9184       0.935418
## Prevalence                   0.2206          0.1811       0.073375
## Detection Rate               0.1789          0.1164       0.009875
## Detection Prevalence         0.3068          0.2062       0.016750
## Balanced Accuracy            0.8233          0.7664       0.563582
##                      Class: politique Class: societe Class: sport
## Sensitivity                   0.53370         0.6072      0.63986
## Specificity                   0.95074         0.8617      0.98194
## Pos Pred Value                0.63283         0.6311      0.80973
## Neg Pred Value                0.92762         0.8492      0.95780
## Prevalence                    0.13725         0.2804      0.10725
## Detection Rate                0.07325         0.1703      0.06863
## Detection Prevalence          0.11575         0.2697      0.08475
## Balanced Accuracy             0.74222         0.7345      0.81090
#jeu de test
conf_CART <- confusionMatrix(data=p_CART, reference = testing$category)
conf_CART
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture       377       51      59        35     127    47
##   economie       27      172      43        39      74    13
##   planete         0        2      17         4       7     1
##   politique      12       25      13       132      61     6
##   societe        33       50      32        68     319    15
##   sport           9        7       1         7       8   107
## 
## Overall Statistics
##                                           
##                Accuracy : 0.562           
##                  95% CI : (0.5399, 0.5839)
##     No Information Rate : 0.298           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.4452          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.8231          0.5603         0.1030
## Specificity                  0.7931          0.8842         0.9924
## Pos Pred Value               0.5417          0.4674         0.5484
## Neg Pred Value               0.9379          0.9173         0.9248
## Prevalence                   0.2290          0.1535         0.0825
## Detection Rate               0.1885          0.0860         0.0085
## Detection Prevalence         0.3480          0.1840         0.0155
## Balanced Accuracy            0.8081          0.7222         0.5477
##                      Class: politique Class: societe Class: sport
## Sensitivity                    0.4632         0.5352       0.5661
## Specificity                    0.9318         0.8590       0.9823
## Pos Pred Value                 0.5301         0.6170       0.7698
## Neg Pred Value                 0.9126         0.8132       0.9559
## Prevalence                     0.1425         0.2980       0.0945
## Detection Rate                 0.0660         0.1595       0.0535
## Detection Prevalence           0.1245         0.2585       0.0695
## Balanced Accuracy              0.6975         0.6971       0.7742



AUC

library(ROCR)
library(pROC)


#jeu d'entrainement
p_CART_train <- predict(Modele_Cart_Arbre,
             newdata=training,
           # newdata=test,  
           #trouver un moyen d'utiliser le jeu de test
           # type= "class"
             type= "prob"
           )[,1]

#jeu de test
p_CART <- predict(Modele_Cart_Arbre,
             newdata=testing,
           # newdata=test,  
           #trouver un moyen d'utiliser le jeu de test
           # type= "class"
           type= "prob"
           
           )[,1]

#AUC jeu d'entrainement
auc(training$category, p_CART_train )
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8916
#AUC jeu de test
auc(testing$category, p_CART )
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8785

Un Auc de 0.86 a été obtenu avec notre jeu test. Et 0.90 avec le jeu d’entrainement.



Visualisation de la prédiction

plot(p_CART ~ category, data=testing, xlab="Observe",
       ylab="Predis")

CART Cross Validation 0.88



Prédiction

#jeu d'entrainement
pCART_CV_train <- predict(modele_CART_CV, newdata=training, type= "prob")
pCART_CV_train <- pCART_CV_train[,1]

#jeu de test
pCART_CV <- predict(modele_CART_CV, newdata=testing, type= "prob")
pCART_CV <- pCART_CV[,1]



Matrice de confusion jeu d’entrainement

MatriceConfu_CART_CV <- confusionMatrix(data = modele_CART_CV,
                                reference = training$category)
#labels <- c("Precision", "Recall", "F1", "Accuracy", "Kappa")
#confu3 <- MatriceConfu_CART_CV$byClass[labels[1:3]]
#confu3 <- c(confu3, MatriceConfu_CART_CV$overall[labels[4:5]])
MatriceConfu_CART_CV
## Cross-Validated (8 fold) Confusion Matrix 
## 
## (entries are percentual average cell counts across resamples)
##  
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      17.3      2.6     2.2       1.4     5.2   2.2
##   economie      1.3      9.9     1.6       1.8     3.8   0.7
##   planete       0.1      0.2     0.8       0.2     0.5   0.0
##   politique     0.9      1.3     0.8       6.9     3.1   0.3
##   societe       2.1      3.5     1.9       3.2    14.9   0.8
##   sport         0.4      0.6     0.1       0.3     0.5   6.7
##                            
##  Accuracy (average) : 0.565



Matrice de confusion Jeu de test

MatriceConfu_CART_CV <- confusionMatrix(data = modele_CART_CV,
                                reference = testing$category)
#labels <- c("Precision", "Recall", "F1", "Accuracy", "Kappa")
#confu3 <- MatriceConfu_CART_CV$byClass[labels[1:3]]
#confu3 <- c(confu3, MatriceConfu_CART_CV$overall[labels[4:5]])
MatriceConfu_CART_CV
## Cross-Validated (8 fold) Confusion Matrix 
## 
## (entries are percentual average cell counts across resamples)
##  
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      17.3      2.6     2.2       1.4     5.2   2.2
##   economie      1.3      9.9     1.6       1.8     3.8   0.7
##   planete       0.1      0.2     0.8       0.2     0.5   0.0
##   politique     0.9      1.3     0.8       6.9     3.1   0.3
##   societe       2.1      3.5     1.9       3.2    14.9   0.8
##   sport         0.4      0.6     0.1       0.3     0.5   6.7
##                            
##  Accuracy (average) : 0.565



AUC

length(testing$category)
## [1] 2000
#Auc Jeu d'entrainement
auc(training$category, pCART_CV_train)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8912
#AUC du jeu de test
auc(testing$category, pCART_CV)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8765

Un Auc de 0.93 a été trouver avec notre jeu de test. Et 0.89 avec le jeu d’entrainement.



#Visualisation de la prédiction
plot(pCART_CV ~ category, data=testing, xlab="Observe",
       ylab="Predis")

Evaluation du deuxième modèle :

Random Forest [0.91]



Predictions

#jeu d'entrainement
predict_rf_train <- predict(modele_rf, newdata=training, type= "prob")[,1]

#jeu de test
predict_rf <- predict(modele_rf, newdata=testing, type= "prob")[,1]



AUC

#length(testing$category)

#jeu d'entrainement
auc(training$category, predict_rf_train)
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.9616
#jeu de test
auc(testing$category, predict_rf)
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.9268

Un AUC de 0.91 a été obtenu avec notre jeu de test. Et 0.99 avec le jeu d’entrainement.

Observons les résultats d’un AUC de grande qualité :

Test Prediction

table(predict_rf, testing$category)[1,]
##   culture  economie   planete politique   societe     sport 
##         0         0         0         0         0         1



Fréquence conditionel

table(predict_rf, testing$category)[1:7,]
##           
## predict_rf culture economie planete politique societe sport
##     0.01         0        0       0         0       0     1
##     0.0125       0        0       0         1       1     2
##     0.015        0        0       0         0       1     1
##     0.0175       0        1       0         1       0     1
##     0.02         0        0       0         3       3     3
##     0.0225       0        0       0         2       1     2
##     0.025        0        1       0         5       4     2



plot(margin(modele_rf, testing$category))



#Visualisation de la prédiction
plot(predict_rf ~ category, data=testing, xlab="Observe",
       ylab="Predis")

Random Forest Cross Validation [0.92]



Prédiction

#jeu d'entrainement
pRF_CV_train <- predict(modele_rf_cv, newdata=training, type= "prob")
pRF_CV_train <- pRF_CV_train[,1]


#jeu de test
pRF_CV <- predict(modele_rf_cv, newdata=testing, type= "prob")
pRF_CV <- pRF_CV[,1]



Matrice de confusion

#jeu d'entrainement
MatriceConfu3 <- confusionMatrix(data = modele_rf_cv,
                                reference = training$category)
MatriceConfu3
## Cross-Validated (8 fold) Confusion Matrix 
## 
## (entries are percentual average cell counts across resamples)
##  
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      18.4      1.9     1.7       1.0     3.6   2.0
##   economie      0.9     12.3     1.5       1.3     2.4   0.3
##   planete       0.0      0.0     0.7       0.0     0.0   0.0
##   politique     0.5      0.8     0.4       8.2     1.7   0.1
##   societe       1.9      2.9     2.9       3.1    20.2   0.8
##   sport         0.3      0.2     0.0       0.0     0.2   7.5
##                             
##  Accuracy (average) : 0.6744
#jeu de test
MatriceConfu3 <- confusionMatrix(data = modele_rf_cv,
                                reference = testing$category)
MatriceConfu3
## Cross-Validated (8 fold) Confusion Matrix 
## 
## (entries are percentual average cell counts across resamples)
##  
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      18.4      1.9     1.7       1.0     3.6   2.0
##   economie      0.9     12.3     1.5       1.3     2.4   0.3
##   planete       0.0      0.0     0.7       0.0     0.0   0.0
##   politique     0.5      0.8     0.4       8.2     1.7   0.1
##   societe       1.9      2.9     2.9       3.1    20.2   0.8
##   sport         0.3      0.2     0.0       0.0     0.2   7.5
##                             
##  Accuracy (average) : 0.6744
#data = modele_rf_cv$finalModel$predicted

#labels <- c("Precision", "Recall", "F1", "Accuracy", "Kappa")
#confu3 <- MatriceConfu3$byClass[labels[1:3]]
#confu3 <- c(confu3, MatriceConfu3$overall[labels[4:5]])



AUC

#length(base_modelisation[-nb_lignes,]$category)

#jeu d'entrainement
auc(training$category, pRF_CV_train)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.9616
#jeu de test
auc(testing$category, pRF_CV)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.926

Un Auc de 0.92 a été trouver avec notre jeu de test, et un AUC de 0.99 avec notre jeu d’entrainement.



#Visualisation de la prédiction
plot(pRF_CV ~ category, data=testing, xlab="Observe",
       ylab="Predis")

Troisième modèle

SVM [0.84]



Predictions

#jeu d'entrainement
SVM_pred_training = predict(SVM_Opti, newdata = training_Scale)
#jeu de test
SVM_pred = predict(SVM_Opti, newdata = testing_Scale)



Matrices de confusion

#Tableau_Pred_SVM = table(testing_Scale[,1], SVM_pred)
#Tableau_Pred_SVM

#jeu d'entrainement
MatriceConfu_SVM <- confusionMatrix(data = SVM_pred_training,
                                reference = training_Scale[,1])
MatriceConfu_SVM
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      1726       82     113        74     225   140
##   economie       16     1316      12        13      23     1
##   planete         0        1     448         2       0     0
##   politique       7       13       0       974      15     1
##   societe        15       35      14        35    1979     4
##   sport           1        2       0         0       1   712
## 
## Overall Statistics
##                                          
##                Accuracy : 0.8944         
##                  95% CI : (0.8874, 0.901)
##     No Information Rate : 0.2804         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.8679         
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.9779          0.9082        0.76320
## Specificity                  0.8983          0.9901        0.99960
## Pos Pred Value               0.7314          0.9529        0.99335
## Neg Pred Value               0.9931          0.9799        0.98159
## Prevalence                   0.2206          0.1811        0.07337
## Detection Rate               0.2157          0.1645        0.05600
## Detection Prevalence         0.2950          0.1726        0.05638
## Balanced Accuracy            0.9381          0.9491        0.88140
##                      Class: politique Class: societe Class: sport
## Sensitivity                    0.8871         0.8823       0.8298
## Specificity                    0.9948         0.9821       0.9994
## Pos Pred Value                 0.9644         0.9505       0.9944
## Neg Pred Value                 0.9823         0.9554       0.9800
## Prevalence                     0.1373         0.2804       0.1072
## Detection Rate                 0.1217         0.2474       0.0890
## Detection Prevalence           0.1263         0.2602       0.0895
## Balanced Accuracy              0.9409         0.9322       0.9146
#jeu de test
MatriceConfu_SVM <- confusionMatrix(data = SVM_pred,
                                reference = testing_Scale[,1])
MatriceConfu_SVM
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture       388       23      33        21      92    37
##   economie       20      214      27        33      39     7
##   planete         0        9      64         2       9     2
##   politique       7       14       9       173      25     1
##   societe        39       46      31        55     430    15
##   sport           4        1       1         1       1   127
## 
## Overall Statistics
##                                           
##                Accuracy : 0.698           
##                  95% CI : (0.6773, 0.7181)
##     No Information Rate : 0.298           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.6167          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.8472          0.6971         0.3879
## Specificity                  0.8664          0.9256         0.9880
## Pos Pred Value               0.6532          0.6294         0.7442
## Neg Pred Value               0.9502          0.9440         0.9472
## Prevalence                   0.2290          0.1535         0.0825
## Detection Rate               0.1940          0.1070         0.0320
## Detection Prevalence         0.2970          0.1700         0.0430
## Balanced Accuracy            0.8568          0.8113         0.6879
##                      Class: politique Class: societe Class: sport
## Sensitivity                    0.6070         0.7215       0.6720
## Specificity                    0.9673         0.8675       0.9956
## Pos Pred Value                 0.7555         0.6981       0.9407
## Neg Pred Value                 0.9368         0.8801       0.9668
## Prevalence                     0.1425         0.2980       0.0945
## Detection Rate                 0.0865         0.2150       0.0635
## Detection Prevalence           0.1145         0.3080       0.0675
## Balanced Accuracy              0.7872         0.7945       0.8338



AUC

library(ROCR)
library(pROC)

#auc(testing_Scale[,1], SVM_pred )
#plot(AUC_SVM, add = TRUE,col = "red", print.auc=TRUE, print.auc.x = 0.5, print.auc.y = 0.3)
#legend(0.3, 0.2, legend = c("auc svm"), lty = c(1), col = c("blue"))

#jeu d'entrainement
AUC_SVM_train <- roc(response =training_Scale$category, predictor =as.numeric(SVM_pred_training))
## Setting levels: control = culture, case = economie
## Setting direction: controls < cases
AUC_SVM_train
## 
## Call:
## roc.default(response = training_Scale$category, predictor = as.numeric(SVM_pred_training))
## 
## Data: as.numeric(SVM_pred_training) in 1765 controls (training_Scale$category culture) < 1449 cases (training_Scale$category economie).
## Area under the curve: 0.9549
#jeu de test
AUC_SVM <- roc(response =testing_Scale$category, predictor =as.numeric(SVM_pred))
## Setting levels: control = culture, case = economie
## Setting direction: controls < cases
AUC_SVM
## 
## Call:
## roc.default(response = testing_Scale$category, predictor = as.numeric(SVM_pred))
## 
## Data: as.numeric(SVM_pred) in 458 controls (testing_Scale$category culture) < 307 cases (testing_Scale$category economie).
## Area under the curve: 0.85

AUC de 0.84 pour un SVM avec une fonction kernel en radial sur notre jeu de test, un AUC de 0.96 sur notre jeu d’entrainement.

SVM Validation croisée [0.86]



Prediction

SVM_pred_CV_train = predict(modele_SVM_CV, newdata = training_Scale)

SVM_pred_CV = predict(modele_SVM_CV, newdata = testing_Scale)



Matrice de confusion

#Tableau_Pred_SVM = table(testing_Scale[,1], SVM_pred)
#Tableau_Pred_SVM

#jeu d'entrainement
MatriceConfu_SVM <- confusionMatrix(data = SVM_pred_CV_train,
                                reference = training_Scale[,1])
MatriceConfu_SVM
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture      1658      162     141       108     288   170
##   economie       41     1170      46        48      83    14
##   planete         0        1     333         4       2     1
##   politique      23       26      13       836      60     5
##   societe        40       87      54       102    1810    15
##   sport           3        3       0         0       0   653
## 
## Overall Statistics
##                                           
##                Accuracy : 0.8075          
##                  95% CI : (0.7987, 0.8161)
##     No Information Rate : 0.2804          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.7582          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.9394          0.8075        0.56729
## Specificity                  0.8606          0.9646        0.99892
## Pos Pred Value               0.6561          0.8345        0.97654
## Neg Pred Value               0.9804          0.9577        0.96684
## Prevalence                   0.2206          0.1811        0.07337
## Detection Rate               0.2072          0.1462        0.04163
## Detection Prevalence         0.3159          0.1752        0.04263
## Balanced Accuracy            0.9000          0.8860        0.78311
##                      Class: politique Class: societe Class: sport
## Sensitivity                    0.7614         0.8070      0.76107
## Specificity                    0.9816         0.9482      0.99916
## Pos Pred Value                 0.8681         0.8586      0.99090
## Neg Pred Value                 0.9628         0.9265      0.97207
## Prevalence                     0.1373         0.2804      0.10725
## Detection Rate                 0.1045         0.2263      0.08163
## Detection Prevalence           0.1204         0.2635      0.08238
## Balanced Accuracy              0.8715         0.8776      0.88012
#jeu de test
MatriceConfu_SVM <- confusionMatrix(data = SVM_pred_CV,
                                reference = testing_Scale[,1])
MatriceConfu_SVM
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  culture economie planete politique societe sport
##   culture       404       35      36        28      98    45
##   economie       16      204      26        41      45     5
##   planete         0        6      65         0       6     2
##   politique       7       19       8       167      31     2
##   societe        28       42      28        49     415     9
##   sport           3        1       2         0       1   126
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6905          
##                  95% CI : (0.6697, 0.7107)
##     No Information Rate : 0.298           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.6077          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
## 
## Statistics by Class:
## 
##                      Class: culture Class: economie Class: planete
## Sensitivity                  0.8821          0.6645         0.3939
## Specificity                  0.8431          0.9214         0.9924
## Pos Pred Value               0.6254          0.6053         0.8228
## Neg Pred Value               0.9601          0.9381         0.9479
## Prevalence                   0.2290          0.1535         0.0825
## Detection Rate               0.2020          0.1020         0.0325
## Detection Prevalence         0.3230          0.1685         0.0395
## Balanced Accuracy            0.8626          0.7930         0.6932
##                      Class: politique Class: societe Class: sport
## Sensitivity                    0.5860         0.6963       0.6667
## Specificity                    0.9609         0.8889       0.9961
## Pos Pred Value                 0.7137         0.7268       0.9474
## Neg Pred Value                 0.9332         0.8733       0.9663
## Prevalence                     0.1425         0.2980       0.0945
## Detection Rate                 0.0835         0.2075       0.0630
## Detection Prevalence           0.1170         0.2855       0.0665
## Balanced Accuracy              0.7734         0.7926       0.8314



AUC

library(ROCR)
library(pROC)


#auc(testing_Scale[,1], SVM_pred )

#jeu d'entrainement
AUC_SVM <- roc(response =training_Scale$category, predictor =as.numeric(SVM_pred_CV_train))
## Setting levels: control = culture, case = economie
## Setting direction: controls < cases
AUC_SVM
## 
## Call:
## roc.default(response = training_Scale$category, predictor = as.numeric(SVM_pred_CV_train))
## 
## Data: as.numeric(SVM_pred_CV_train) in 1765 controls (training_Scale$category culture) < 1449 cases (training_Scale$category economie).
## Area under the curve: 0.8998
#jeu de test
AUC_SVM <- roc(response =testing_Scale$category, predictor =as.numeric(SVM_pred_CV))
## Setting levels: control = culture, case = economie
## Setting direction: controls < cases
AUC_SVM
## 
## Call:
## roc.default(response = testing_Scale$category, predictor = as.numeric(SVM_pred_CV))
## 
## Data: as.numeric(SVM_pred_CV) in 458 controls (testing_Scale$category culture) < 307 cases (testing_Scale$category economie).
## Area under the curve: 0.8582
#plot(AUC_SVM, add = TRUE,col = "red", print.auc=TRUE, print.auc.x = 0.5, print.auc.y = 0.3)
#legend(0.3, 0.2, legend = c("auc svm"), lty = c(1), col = c("blue"))

Auc de 0.81 et 0.93 avec le jeu d’entrainement.

Mise en œuvre d’un modèle supervisé avec maximum 25 variables [0.87]



On sélectionne les 25 variables les plus importantes parmis le 2ème modèle (random Forest) Ainsi qu’une visualisation graphique de leur importance.

#class (modele_rf$importance[order(modele_rf$importance[,1], decreasing = TRUE)[1:25], ])
#"matrix" "array" 
modele_rf$importance[order(modele_rf$importance[,1], decreasing = TRUE)[1:25], ]
##              culture      economie       planete    politique       societe
## selon     0.04233113 -0.0056529859 -6.557051e-04 0.0002403207 -1.150051e-03
## loi       0.03625971  0.0004948117  2.390326e-03 0.0144943846  3.193997e-04
## entrepris 0.03587045  0.0129814835  9.580786e-04 0.0037119029  1.866190e-03
## film      0.03524739  0.0081722045  2.559115e-03 0.0059068848  4.590501e-03
## euros     0.03351486  0.0095292731  1.413091e-03 0.0051062098  3.703370e-05
## president 0.02965685  0.0021679007  2.744837e-04 0.0022425023 -1.114611e-04
## ministr   0.02893321  0.0093286356  2.104903e-03 0.0064806889 -9.370862e-04
## ete       0.02572021  0.0036639727 -2.503179e-03 0.0017633177 -4.640795e-03
## scen      0.02509302  0.0086918553  2.541916e-03 0.0024304029  3.570856e-03
## festival  0.02488781  0.0051220030  1.314420e-03 0.0041318080  6.057168e-03
## gouvern   0.01768504  0.0039010528  8.399630e-04 0.0093475162 -1.443142e-03
## person    0.01741568 -0.0016191035  7.795605e-04 0.0016403902 -5.722634e-04
## match     0.01715426  0.0063442293  2.680138e-03 0.0030934373  5.912692e-03
## contr     0.01678982  0.0025521359 -2.786247e-05 0.0002116286 -1.949168e-03
## art       0.01549075  0.0034388268  1.081092e-03 0.0025201944  3.132896e-03
## equip     0.01481243  0.0003634368  5.970943e-04 0.0027710750  1.937659e-03
## franc     0.01468259 -0.0002880556 -1.806405e-04 0.0006202630 -1.263119e-03
## general   0.01442796 -0.0023106453  5.336896e-04 0.0002277300 -7.021815e-06
## etat      0.01429880 -0.0002554362  1.807750e-03 0.0016063385 -5.885805e-04
## droit     0.01401475  0.0033158147  1.494757e-03 0.0064739134 -1.376392e-03
## plus      0.01257191  0.0002448524 -1.797914e-03 0.0007135340 -2.682477e-03
## econom    0.01182770  0.0001347840 -1.114672e-04 0.0025542286  2.233493e-03
## final     0.01149684  0.0028269933  1.305018e-03 0.0013618042  1.306513e-03
## social    0.01116467 -0.0003633719  1.152377e-03 0.0072713759 -1.631635e-03
## plac      0.01021420  0.0008569198 -2.152585e-04 0.0008193446 -3.978915e-03
##                   sport MeanDecreaseAccuracy MeanDecreaseGini
## selon      0.0061214645          0.008624889         37.43428
## loi        0.0159110900          0.012045998         53.72284
## entrepris  0.0134882790          0.012795543         71.70260
## film       0.0079701938          0.012394732        114.82977
## euros      0.0057480938          0.010531464         54.76406
## president  0.0023422392          0.007473186         32.69486
## ministr    0.0101875402          0.009934898         46.91646
## ete        0.0009555433          0.005191103         40.34358
## scen       0.0029827593          0.008934673         84.67867
## festival   0.0036628454          0.009155324         85.18917
## gouvern    0.0084540558          0.006449784         36.87369
## person     0.0036169617          0.004049316         27.57035
## match      0.0763050959          0.015394234        117.37638
## contr      0.0020654351          0.003872569         28.17711
## art        0.0038505318          0.005745999         55.01054
## equip      0.0193171651          0.006381798         43.29206
## franc     -0.0029362688          0.002589715         30.56166
## general    0.0011192786          0.002943756         18.47944
## etat       0.0058222958          0.003930975         26.99819
## droit      0.0010166018          0.004399543         28.41918
## plus       0.0002103737          0.002038644         29.89157
## econom     0.0031704293          0.003928532         27.88980
## final      0.0199566909          0.005835996         48.87829
## social     0.0029405523          0.003336694         27.06720
## plac      -0.0006938705          0.001307855         16.87219
varImpPlot(modele_rf)



 #copie des termes dans l'attente de trouver une méthode pour récup les variables d'une matrice.
# sachant que les mots ne sont pas constant d'une éxécution du code à l'autre
modele_25 = randomForest(category~ selon + film + loi + entrepris + president + ete + ministr + festival + scen + gouvern + contr + franc + match + person + art + general + social + equip + droit + national + etat + final + econom + plac
                         , data=training,
                         importance = T,
                         proximity=TRUE,
                         ntree = 100)
plot(modele_25)



Prediction

#jeu d'entrainement
predict_25_train <- predict(modele_25, newdata=training, type= "prob")[,1]
#jeu de test
predict_25 <- predict(modele_25, newdata=testing, type= "prob")[,1]



AUC

library(ROCR)
library(pROC)
#length(base_modelisation[-nb_lignes,]$category)

#jeu d'entrainement
auc(training$category, predict_25_train)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.9335
#jeu de test
auc(testing$category, predict_25)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.886

AUC jeu d’entrainement : 0.93 AUC jeu de test : 0.87

L’AUC augmente de 0.01 pour un passage de 440 variables à 25.

NB: Par rapport à un modèle rf similaire (sans CV ni tune du mtry)



Test Prediction

table(predict_25, testing$category)[1,]
##   culture  economie   planete politique   societe     sport 
##         1        10         8        20        36        36



Fréquence conditionel (prédiction avec jeu d’entrainement)

table(predict(modele_25), training$category)
##            
##             culture economie planete politique societe sport
##   culture      1427      279     160       118     429   196
##   economie      106      707     101       135     280    43
##   planete         2        5      19        11      12     1
##   politique      42      114      49       439     216    16
##   societe       162      309     251       385    1267    69
##   sport          26       35       7        10      39   533



#Visualisation de la prédiction
plot(predict_25 ~ category, data=testing, xlab="Observe",
       ylab="Predis")

Conclusion



Nos 3 modèles sont utilisables.

La forte réduction du nombre de variable sur le modèle randomForest a eu un impact mineur sur l’AUC.( à modèle comparable)

Bilan des prédictions en multi-classes :

    • CART : 0,86 / 0,90 ; cv 0,93 / 0,89
    • RF : 0,99 / 0,91 ; cv 0,99 / 0,92
    • SVM : 0,96 / 0,84 ; cv 0,93 / 0,87

25 variables (RF) : 0,93 / 0,87

Nous avons choisis de réaliser d’effectuer des classification multi-classes au lieu d’une classification binaire(Economie ou non Economie).

Après optimisation de chacun de nos modèles par cross-validation & hyperparamètres, la probabilité qu’un article d’une telle catégorie soit classé dans cette catégorie est proche de 90% pour chacun de nos modèles optimisés.

Afin d’amèliorer les résultats, nous aurions pu baisser le minfreq afin d’avoir plus de variables explicatives. Cela aurait augmenter les temps de calculs, et particulièrement lors de l’amélioration des modèles.

Le choix de la metric "Accuracy" pour l'optimisation de nos modèles a été arbitraire, après visualisation des matrices de confusion, on remarque que les proportions des catégories a eu beaucoup d'influence. Ainsi les articles de catégorie "planete" sont très mal prédis. Une metric qui pénalise plus les erreurs sur cette catégorie aurait éviter ce problème.

Nous avons réaliser des modèles “simples” pour tester les modèles, puis des modèles optimisé où nous réalisions une cross-validation et une optimisation des hyperparamètres. Nous pouvons observer une amélioration entre les modèles simples et leurs modèles optimisé.

Le projet est réussi et nous vous remercions pour les réponses rapides à nos mails.