ANNClassificationRRégression

Réseaux de neurones avec R (#1)

On parle beaucoup de l’utilisation des réseaux de neurones dans des domaines variés (diagnostic médical, analyse financière, reconnaissance d’image ou vocale etc…). Les fondements mathématiques sont connus depuis longtemps et les premières mise en oeuvre comme le perceptron datent des années 50. Ce n’est pourtant que ces dernières années que ces techniques se sont démocratisées grâce notamment aux capacités de calcul des processeurs actuels et à la profusion des données disponibles (nécessaires à leur entrainement).

On trouve sur internet d’innombrables sources d’information sur les ANN (Artificial Neural Network). Une bonne introduction se trouve sur Wikiversité.

Dans les grandes lignes, un ANN est constitué d’une succession de couches de neurones interconnectés. Chaque interconnexion est caractérisée par un poids synaptique, et chaque neurone met en oeuvre une fonction d’activation.

La phase d’apprentissage consiste dans l’ajustement progressif des poids synaptique en utilisant un algorithme de rétropropagation (back-propagation) du gradient.

La structure du réseau (nombre de couches, nombre de neurones et fonctions d’activation) est en revanche fixée à priori.

Ici, je me suis intéressé à l’implémentation des ANN avec R. Pour cela, j’ai utilisé des données mises à disposition sur le site de l’UCI et relatives au diagnostic du cancer du sein pour une cohorte du Wisconsin.

Plusieurs jeux de données sont disponibles, je me suis initialement intéressé au dataset breast-cancer-wisconsin.data dont le format est détaillé ici: breast-cancer-wisconsin.names.

Celui-ci contient 699 instances. 9 attributs numériques sont exploitables. 2/3 des enregistrements correspondent à des tumeurs bégnines, 1/3 a des tumeurs malignes.

 
> breastcancer <- read.csv(url("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"), header=FALSE)
> summary(breastcancer)
       V1                 V2               V3               V4               V5               V6               V7            V8               V9        
 Min.   :   61634   Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   1      :402   Min.   : 1.000   Min.   : 1.000  
 1st Qu.:  870688   1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 1.000   1st Qu.: 1.000   1st Qu.: 2.000   10     :132   1st Qu.: 2.000   1st Qu.: 1.000  
 Median : 1171710   Median : 4.000   Median : 1.000   Median : 1.000   Median : 1.000   Median : 2.000   2      : 30   Median : 3.000   Median : 1.000  
 Mean   : 1071704   Mean   : 4.418   Mean   : 3.134   Mean   : 3.207   Mean   : 2.807   Mean   : 3.216   5      : 30   Mean   : 3.438   Mean   : 2.867  
 3rd Qu.: 1238298   3rd Qu.: 6.000   3rd Qu.: 5.000   3rd Qu.: 5.000   3rd Qu.: 4.000   3rd Qu.: 4.000   3      : 28   3rd Qu.: 5.000   3rd Qu.: 4.000  
 Max.   :13454352   Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.000   8      : 21   Max.   :10.000   Max.   :10.000  
                                                                                                         (Other): 56                                    
      V10              V11      
 Min.   : 1.000   Min.   :2.00  
 1st Qu.: 1.000   1st Qu.:2.00  
 Median : 1.000   Median :2.00  
 Mean   : 1.589   Mean   :2.69  
 3rd Qu.: 1.000   3rd Qu.:4.00  
 Max.   :10.000   Max.   :4.00  
                                
> 

On opère quelques ajustements sur le dataset :

  • Suppression de la premiere colonne (V1) qui correspond à un ID patient.
  • Binarisation (0/1) de la colonne V11 qui correspond au diagnostic (codification initiale: 2 pour une tumeur benigne, 4 pour une tumeur maligne)
  • Suppression des lignes pour lesquelles le champ V7 est inconnu (« ? »)
  • Conversion de la colonne V7 de facteur à numérique.
  • Centrage/réduction à l’aide de la fonction « scale » de toutes les valeurs du dataframe (sauf celles de la colonne V11 qui est binarisée)
 
> breastcancer <- breastcancer[-1]
> breastcancer$V11 <- ifelse(breastcancer$V11==2,0,1)
> breastcancer <- breastcancer[-which(breastcancer$V7=="?"),]
> breastcancer$V7 <- as.numeric(levels(breastcancer$V7))[breastcancer$V7]
Warning message:
NAs introduced by coercion 
> breastcancer[,-10] <- scale(breastcancer[,-10])[,]
> summary(breastcancer)
       V2                V3                V4                V5                V6                V7                V8                V9         
 Min.   :-1.2203   Min.   :-0.7017   Min.   :-0.7412   Min.   :-0.6389   Min.   :-1.0050   Min.   :-0.6983   Min.   :-0.9981   Min.   :-0.6125  
 1st Qu.:-0.8658   1st Qu.:-0.7017   1st Qu.:-0.7412   1st Qu.:-0.6389   1st Qu.:-0.5552   1st Qu.:-0.6983   1st Qu.:-0.5899   1st Qu.:-0.6125  
 Median :-0.1568   Median :-0.7017   Median :-0.7412   Median :-0.6389   Median :-0.5552   Median :-0.6983   Median :-0.1817   Median :-0.6125  
 Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000  
 3rd Qu.: 0.5523   3rd Qu.: 0.6033   3rd Qu.: 0.5972   3rd Qu.: 0.4084   3rd Qu.: 0.3444   3rd Qu.: 0.6738   3rd Qu.: 0.6347   3rd Qu.: 0.3703  
 Max.   : 1.9703   Max.   : 2.2345   Max.   : 2.2702   Max.   : 2.5029   Max.   : 3.0434   Max.   : 1.7716   Max.   : 2.6758   Max.   : 2.3358  
      V10               V11        
 Min.   :-0.3481   Min.   :0.0000  
 1st Qu.:-0.3481   1st Qu.:0.0000  
 Median :-0.3481   Median :0.0000  
 Mean   : 0.0000   Mean   :0.3499  
 3rd Qu.:-0.3481   3rd Qu.:1.0000  
 Max.   : 4.8461   Max.   :1.0000  
> 

On divise ensuite le dataset breastcancer en un échantillon d’apprentissage (70%) et un échantillon de test (30%). L’appel a set.seed permet d’obtenir des résultats reproductibles.

 
> set.seed(1234)
> sub <- sample(nrow(breastcancer), floor(nrow(breastcancer) * 0.70))
> breastcancer_train <- breastcancer[sub,]
> breastcancer_test <- breastcancer[-sub,]
>

A ce stade, un premier ANN est créé à l’aide du package nnet qui est inclus par défaut dans la distribution R. Ce package ne permet néanmoins que la création d’un réseau simple contenant  une unique couche cachée.

Ici, on fixe arbitrairement le nombre de neurones de cette couche cachée à 5. Il n’y a pas de règle particulière pour déterminer ce nombre ni plus généralement la topologie du réseau de neurones que l’on construit. C’est l’expérience et la connaissance du domaine d’étude qui permettent de déterminer une topologie adaptée. D’autre part, il existe plusieurs méta-paramètres qui peuvent aussi être adaptés. Généralement, on essaie plusieurs configuration et on choisit celle offrant la meilleure performance sur l’échantillon de test.

 
> library(nnet)
> nn_model <- nnet(V11 ~ ., data=breastcancer_train, size=5)
# weights:  56
initial  value 114.785410 
iter  10 value 12.000001
final  value 12.000000 
converged
> pred <- predict(nn_model, newdata=breastcancer_test, supplemental_cols=c("V11"))
>

Le vecteur pred contient la sortie de la fonction d’activation (sigmoide) du neurone de sortie. On binarise le résultat avec un seuil à 0.5:

 
> pred.bin <- ifelse(pred>0.5,1,0)
> table(pred.bin, breastcancer_test$V11)
        
pred.bin   0   1
       0 122   5
       1   5  73
> 

Le taux de réussite des prédictions avec ce modèle est de l’ordre de 95% (122+73)/(122+73+5+5).

C’est excellent mais… pour cet exemple simple, une régression logistique toute simple permet aussi d’atteindre un résultat similaire!!

 
> breastcancer_train$V11 <- as.factor(breastcancer_train$V11)
> breastcancer_test$V11 <- as.factor(breastcancer_test$V11)
> log_model <- glm(V11 ~ ., family=binomial, data=breastcancer_train)
> step(log_model, dir="backward", trace=0)

Call:  glm(formula = V11 ~ V2 + V4 + V5 + V7 + V8 + V9, family = binomial, 
    data = breastcancer_train)

Coefficients:
(Intercept)           V2           V4           V5           V7           V8           V9  
    -1.4256       1.7191       1.5855       0.8481       0.9593       1.1630       0.8326  

Degrees of Freedom: 477 Total (i.e. Null);  471 Residual
Null Deviance:	    610.8 
Residual Deviance: 68.99 	AIC: 82.99
> log_model <- glm(V11 ~ V2 + V4 + V5 + V7 + V8 + V9, family=binomial, data=breastcancer_train)
> pred <- predict(log_model, breastcancer_test)
> levels(breastcancer_test$V11)[1]
[1] "0"
> pred.bin <- ifelse(pred > 0.5,1,0)
> table(pred.bin, breastcancer_test$V11)
        
pred.bin   0   1
       0 124   8
       1   3  70
>

En fait, c’est lorsque le nombre de prédicteurs devient important que les ANN tirent réellement leur épingle du jeu.

To be continued…

Laisser un commentaire

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