Classification des articles du monde en fonction de leur contenu
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é
## 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")
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.
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,]
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)
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)
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)
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
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)
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)
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 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
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)
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.
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")
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")
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")
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")
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.
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.
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")
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 :
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.