Le caretpackage (abréviation de C lassification A nd RE gression T raining) est un ensemble de fonctions qui tentent de rationaliser le processus de création de modèles prédictifs. Le package contient des outils pour : -fractionnement des données -pré-traitement -sélection de fonctionnalité -réglage du modèle à l’aide du rééchantillonnage -estimation de l’importance des variables - ainsi que d’autres fonctionnalités.

Il existe de nombreuses fonctions de modélisation différentes dans R. Certaines ont une syntaxe différente pour la formation et/ou la prédiction du modèle. Le package a commencé comme un moyen de fournir une interface uniforme aux fonctions elles-mêmes, ainsi qu’un moyen de standardiser les tâches courantes (telles que le réglage des paramètres et l’importance variable).

Visuatlisation des données

Nous allons utiliser le jeux de données irris qui se trouve dans Rstudio. Le jeux de données commprend 5 variables et 150 observations.

# importation de la base de données 
data("iris")
str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

Nous allons tracer La matrice des points

La featurePlotfonction est un wrapper pour différentes latticeparcelles pour visualiser les données. Par exemple, les figures suivantes montrent le tracé par défaut des résultats continus générés à l’aide de la featurePlotfonction. Nous allons installer le package AppliedPredictiveModeling

#install.packages("AppliedPredictiveModeling")
library(AppliedPredictiveModeling)
transparentTheme(trans = .4)
library(caret)
## Loading required package: ggplot2
## Loading required package: lattice
featurePlot(x = iris[, 1:4], 
            y = iris$Species, 
            plot = "pairs",
            ## Ajouter une clé en haut
            auto.key = list(columns = 3))

Nous allons tracer Matrice de nuages de points avec ellipses

featurePlot(x = iris[, 1:4], 
            y = iris$Species, 
            plot = "ellipse",
            ## Ajouter une clé en haut
            auto.key = list(columns = 3))

Nous allons tracer de densité superposés avec notre jeux de données

transparentTheme(trans = .9)
featurePlot(x = iris[, 1:4], 
            y = iris$Species,
            plot = "density", 
            ## Pass in options to xyplot() to 
            ## make it prettier
            scales = list(x = list(relation="free"), 
                          y = list(relation="free")), 
            adjust = 1.5, 
            pch = "|", 
            layout = c(4, 1), 
            auto.key = list(columns = 3))

Nous allons tracer les Boîtes à moustaches.

featurePlot(x = iris[, 1:4], 
            y = iris$Species, 
            plot = "box", 
            ## Pass in options to bwplot() 
            scales = list(y = list(relation="free"),
                          x = list(rot = 90)),  
            layout = c(4,1 ), 
            auto.key = list(columns = 2))

Nous allons tracer les Nuages de points. Pour la régression, les données de Boston Housing sont utilisées. Nous allons installer le package mlbench.

#install.packages("mlbench")
library(mlbench)
data(BostonHousing)
regVar <- c("age", "lstat", "tax")
str(BostonHousing[, regVar])
## 'data.frame':    506 obs. of  3 variables:
##  $ age  : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
##  $ lstat: num  4.98 9.14 4.03 2.94 5.33 ...
##  $ tax  : num  296 242 242 222 222 222 311 311 311 311 ...

Lorsque les prédicteurs sont continus, featurePlot peut être utilisé pour créer des diagrammes de dispersion de chacun des prédicteurs avec le résultat. Nous allons présenter un exemples

theme1 <- trellis.par.get()
theme1$plot.symbol$col = rgb(.2, .2, .2, .4)
theme1$plot.symbol$pch = 16
theme1$plot.line$col = rgb(1, 0, 0, .7)
theme1$plot.line$lwd <- 2
trellis.par.set(theme1)
featurePlot(x = BostonHousing[, regVar], 
            y = BostonHousing$medv, 
            plot = "scatter", 
            layout = c(3, 1))

Pré-traitement

Création de variables factices Prédicteurs de variance nulle et proche de zéro Identification des prédicteurs corrélés Dépendances linéaires La preProcessfonction Centrage et mise à l’échelle Imputation Transformer les prédicteurs Mettre tous ensemble Calculs de distance de classe caretinclut plusieurs fonctions pour pré-traiter les données du prédicteur. Il suppose que toutes les données sont numériques (c’est-à-dire que les facteurs ont été convertis en variables fictives via model.matrix, dummyVarsou d’autres moyens)

1 Création de variables factices

La fonction dummyVarspeut être utilisée pour générer un ensemble complet (moins que paramétré sur le rang complet) de variables fictives à partir d’un ou de plusieurs facteurs. La fonction prend une formule et un ensemble de données et génère un objet qui peut être utilisé pour créer les variables fictives à l’aide de la méthode de prédiction.

Par exemple, l’ etitanicensemble de données dans le earthpackage comprend deux facteurs : pclass(classe de passagers, avec les niveaux 1er, 2e, 3e) et sex(avec les niveaux femme, homme). La fonction R de base model.matrixgénérerait les variables suivantes :

# install.packages("earth")
library(earth)
## Loading required package: Formula
## Loading required package: plotmo
## Loading required package: plotrix
## Loading required package: TeachingDemos
data(etitanic)
head(model.matrix(survived ~ ., data = etitanic))
##   (Intercept) pclass2nd pclass3rd sexmale     age sibsp parch
## 1           1         0         0       0 29.0000     0     0
## 2           1         0         0       1  0.9167     1     2
## 3           1         0         0       0  2.0000     1     2
## 4           1         0         0       1 30.0000     1     2
## 5           1         0         0       0 25.0000     1     2
## 6           1         0         0       1 48.0000     0     0

Utilisation dummyVars:

dummies <- dummyVars(survived ~ ., data = etitanic)
head(predict(dummies, newdata = etitanic))
##   pclass.1st pclass.2nd pclass.3rd sex.female sex.male     age sibsp parch
## 1          1          0          0          1        0 29.0000     0     0
## 2          1          0          0          0        1  0.9167     1     2
## 3          1          0          0          1        0  2.0000     1     2
## 4          1          0          0          0        1 30.0000     1     2
## 5          1          0          0          1        0 25.0000     1     2
## 6          1          0          0          0        1 48.0000     0     0

Notons qu’il n’y a pas d’ordonnée à l’origine et que chaque facteur a une variable fictive pour chaque niveau, donc ce paramétrage peut ne pas être utile pour certaines fonctions de modèle, telles que lm.

2 Prédicteurs de variance nulle et proche de zéro

Dans certaines situations, le mécanisme de génération de données peut créer des prédicteurs qui n’ont qu’une seule valeur unique (c’est-à-dire un « prédicteur à variance nulle »). Pour de nombreux modèles (à l’exception des modèles basés sur des arbres), cela peut entraîner le blocage du modèle ou l’instabilité de l’ajustement.

De même, les prédicteurs peuvent n’avoir qu’une poignée de valeurs uniques qui se produisent avec des fréquences très basses. Par exemple, dans les données sur la pharmacorésistance, nR11les données du descripteur (nombre d’anneaux à 11 membres) ont quelques valeurs numériques uniques très déséquilibrées :

data(mdrr)
data.frame(table(mdrrDescr$nR11))
##   Var1 Freq
## 1    0  501
## 2    1    4
## 3    2   23

La préoccupation ici est que ces prédicteurs peuvent devenir des prédicteurs à variance nulle lorsque les données sont divisées en sous-échantillons de validation croisée/bootstrap ou que quelques échantillons peuvent avoir une influence indue sur le modèle. Ces prédicteurs de « variance proche de zéro » peuvent devoir être identifiés et éliminés avant la modélisation.

Pour identifier ces types de prédicteurs, les deux métriques suivantes peuvent être calculées :

la fréquence de la valeur la plus répandue par rapport à la deuxième valeur la plus fréquente (appelée «rapport de fréquence»), qui serait proche de un pour les prédicteurs bien comportés et très élevée pour les données très déséquilibrées et le “pourcentage de valeurs uniques” est le nombre de valeurs uniques divisé par le nombre total d’échantillons (fois 100) qui se rapproche de zéro à mesure que la granularité des données augmente. Si le rapport de fréquence est supérieur à un seuil prédéfini et que le pourcentage de valeur unique est inférieur à un seuil, nous pouvons considérer qu’un prédicteur est proche de la variance nulle.

Nous ne voudrions pas identifier à tort des données qui ont une faible granularité mais qui sont uniformément distribuées, telles que des données provenant d’une distribution uniforme discrète. L’utilisation des deux critères ne devrait pas détecter à tort de tels prédicteurs.

En regardant les données MDRR, la nearZeroVarfonction peut être utilisée pour identifier des variables à variance proche de zéro (l’ saveMetricsargument peut être utilisé pour afficher les détails et prend généralement la valeur par défaut FALSE):

nzv <- nearZeroVar(mdrrDescr, saveMetrics= TRUE)
nzv[nzv$nzv,][1:10,]
##        freqRatio percentUnique zeroVar  nzv
## nTB     23.00000     0.3787879   FALSE TRUE
## nBR    131.00000     0.3787879   FALSE TRUE
## nI     527.00000     0.3787879   FALSE TRUE
## nR03   527.00000     0.3787879   FALSE TRUE
## nR08   527.00000     0.3787879   FALSE TRUE
## nR11    21.78261     0.5681818   FALSE TRUE
## nR12    57.66667     0.3787879   FALSE TRUE
## D.Dr03 527.00000     0.3787879   FALSE TRUE
## D.Dr07 123.50000     5.8712121   FALSE TRUE
## D.Dr08 527.00000     0.3787879   FALSE TRUE
dim(mdrrDescr)
## [1] 528 342
nzv <- nearZeroVar(mdrrDescr)
filteredDescr <- mdrrDescr[, -nzv]
dim(filteredDescr)
## [1] 528 297

Par défaut, nearZeroVarrenverra les positions des variables signalées comme problématiques.

3 Identification des prédicteurs corrélés

Bien que certains modèles fonctionnent avec des prédicteurs corrélés (tels que pls), d’autres modèles peuvent bénéficier d’une réduction du niveau de corrélation entre les prédicteurs.

Étant donné une matrice de corrélation, la findCorrelationfonction utilise l’algorithme suivant pour signaler les prédicteurs à supprimer :

descrCor <-  cor(filteredDescr)
highCorr <- sum(abs(descrCor[upper.tri(descrCor)]) > .999)
highlyCorDescr <- findCorrelation(descrCor, cutoff = .75)
filteredDescr <- filteredDescr[,-highlyCorDescr]
descrCor2 <- cor(filteredDescr)
summary(descrCor2[upper.tri(descrCor2)])
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## -0.70728 -0.05378  0.04418  0.06692  0.18858  0.74458

4 Dépendances linéaires

La fonction findLinearCombosutilise la décomposition QR d’une matrice pour énumérer des ensembles de combinaisons linéaires (s’ils existent). Par exemple, considérez la matrice suivante qui aurait pu être produite par une paramétrisation de rang inférieur à un agencement expérimental bidirectionnel :

ltfrDesign <- matrix(0, nrow=6, ncol=6)
ltfrDesign[,1] <- c(1, 1, 1, 1, 1, 1)
ltfrDesign[,2] <- c(1, 1, 1, 0, 0, 0)
ltfrDesign[,3] <- c(0, 0, 0, 1, 1, 1)
ltfrDesign[,4] <- c(1, 0, 0, 1, 0, 0)
ltfrDesign[,5] <- c(0, 1, 0, 0, 1, 0)
ltfrDesign[,6] <- c(0, 0, 1, 0, 0, 1)

Notez que les colonnes deux et trois s’additionnent à la première colonne. De même, les colonnes quatre, cinq et six ajoutent la première colonne. findLinearCombosrenverra une liste qui énumère ces dépendances. Pour chaque combinaison linéaire, il supprimera progressivement les colonnes de la matrice et testera pour voir si les dépendances ont été résolues. findLinearCombosrenverra également un vecteur de positions de colonne pouvant être supprimé pour éliminer les dépendances linéaires :

comboInfo <- findLinearCombos(ltfrDesign)
comboInfo
## $linearCombos
## $linearCombos[[1]]
## [1] 3 1 2
## 
## $linearCombos[[2]]
## [1] 6 1 4 5
## 
## 
## $remove
## [1] 3 6
ltfrDesign[, -comboInfo$remove]
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    0
## [2,]    1    1    0    1
## [3,]    1    1    0    0
## [4,]    1    0    1    0
## [5,]    1    0    0    1
## [6,]    1    0    0    0

Ces types de dépendances peuvent survenir lorsqu’un grand nombre d’empreintes chimiques binaires sont utilisées pour décrire la structure d’une molécule.

5 La preProcessfonction

La preProcessclasse peut être utilisée pour de nombreuses opérations sur les prédicteurs, y compris le centrage et la mise à l’échelle. La fonction preProcessestime les paramètres requis pour chaque opération et predict.preProcessest utilisée pour les appliquer à des ensembles de données spécifiques. Cette fonction peut également être des interfaces lors de l’appel de la trainfonction.

Plusieurs types de techniques sont décrits dans les sections suivantes, puis un autre exemple est utilisé pour démontrer comment plusieurs méthodes peuvent être utilisées. Notez que, dans tous les cas, la preProcessfonction estime tout ce dont elle a besoin à partir d’un ensemble de données spécifique (par exemple, l’ensemble d’apprentissage), puis applique ces transformations à n’importe quel ensemble de données sans recalculer les valeurs.

6 Centrage et mise à l’échelle

Dans l’exemple ci-dessous, la moitié des données MDRR sont utilisées pour estimer l’emplacement et l’échelle des prédicteurs. La fonction preProcessne prétraite pas réellement les données. predict.preProcessest utilisé pour pré-traiter cet ensemble de données et d’autres.

set.seed(96)
inTrain <- sample(seq(along = mdrrClass), length(mdrrClass)/2)

training <- filteredDescr[inTrain,]
test <- filteredDescr[-inTrain,]
trainMDRR <- mdrrClass[inTrain]
testMDRR <- mdrrClass[-inTrain]

preProcValues <- preProcess(training, method = c("center", "scale"))
#summary(preProcValues)

trainTransformed <- predict(preProcValues, training)
#summary(trainTransformed)
testTransformed <- predict(preProcValues, test)
#♠summary(testTransformed)

L’ preProcessoption “range”met les données à l’échelle dans l’intervalle entre zéro et un.

7 Imputation

preProcesspeut être utilisé pour imputer des ensembles de données basés uniquement sur les informations contenues dans l’ensemble d’apprentissage. Une méthode consiste à utiliser les K voisins les plus proches. Pour un échantillon arbitraire, les K voisins les plus proches sont trouvés dans l’ensemble d’apprentissage et la valeur du prédicteur est imputée à l’aide de ces valeurs (par exemple, à l’aide de la moyenne). L’utilisation de cette approche déclenchera automatiquement preProcessle centrage et la mise à l’échelle des données, quel que soit le contenu de l’ methodargument. Alternativement, les arbres ensachés peuvent également être utilisés pour imputer. Pour chaque prédicteur dans les données, un arbre empaqueté est créé à l’aide de tous les autres prédicteurs de l’ensemble d’apprentissage. Lorsqu’un nouvel échantillon a une valeur de prédicteur manquante, le modèle bagué est utilisé pour prédire la valeur. Bien qu’en théorie, il s’agisse d’une méthode d’imputation plus puissante, les coûts de calcul sont beaucoup plus élevés que la technique du plus proche voisin.

8 Transformer les prédicteurs

Dans certains cas, il est nécessaire d’utiliser l’analyse en composantes principales (ACP) pour transformer les données en un sous–espace plus petit où les nouvelles variables ne sont pas corrélées entre elles. La preProcessclasse peut appliquer cette transformation en l’incluant “pca”dans l’ methodargument. Cela forcera également la mise à l’échelle des prédicteurs. Notez que lorsque PCA est demandé, predict.preProcesschange les noms de colonne en PC1, PC2et ainsi de suite.

De même, l’analyse en composantes indépendantes (ICA) peut également être utilisée pour trouver de nouvelles variables qui sont des combinaisons linéaires de l’ensemble d’origine de sorte que les composantes soient indépendantes (par opposition à non corrélées dans l’ACP). Les nouvelles variables seront étiquetées comme IC1, IC2et ainsi de suite.

La transformation « signe spatial » ( Serneels et al, 2006 ) projette les données d’un prédicteur sur le cercle unitaire en p dimensions, où p est le nombre de prédicteurs. Essentiellement, un vecteur de données est divisé par sa norme. Les deux figures ci-dessous montrent deux descripteurs centrés et mis à l’échelle des données MDRR avant et après la transformation du signe spatial. Les prédicteurs doivent être centrés et mis à l’échelle avant d’appliquer cette transformation.

library(AppliedPredictiveModeling)
transparentTheme(trans = .4)
plotSubset <- data.frame(scale(mdrrDescr[, c("nC", "X4v")])) 
xyplot(nC ~ X4v,
       data = plotSubset,
       groups = mdrrClass, 
       auto.key = list(columns = 2))

Après le signe spatial :

transformed <- spatialSign(plotSubset)
transformed <- as.data.frame(transformed)
xyplot(nC ~ X4v, 
       data = transformed, 
       groups = mdrrClass, 
       auto.key = list(columns = 2))

Une autre option “BoxCox”estimera une transformation de Box-Cox sur les prédicteurs si les données sont supérieures à zéro.

preProcValues2 <- preProcess(training, method = "BoxCox")
trainBC <- predict(preProcValues2, training)
testBC <- predict(preProcValues2, test)
preProcValues2
## Created from 264 samples and 31 variables
## 
## Pre-processing:
##   - Box-Cox transformation (31)
##   - ignored (0)
## 
## Lambda estimates for Box-Cox transformation:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -2.0000 -0.2500  0.5000  0.4387  2.0000  2.0000

Les NAvaleurs correspondent aux prédicteurs qui n’ont pas pu être transformés. Cette transformation nécessite que les données soient supérieures à zéro. Deux transformations similaires, la transformation de Yeo-Johnson et la transformation exponentielle de Manly (1976) peuvent également être utilisées dans preProcess.

9 Tout mettre ensemble

Dans Applied Predictive Modeling, il existe une étude de cas où les temps d’exécution des travaux dans un environnement informatique haute performance sont prédits. Les données sont :

library(AppliedPredictiveModeling)
data(schedulingData)
str(schedulingData)
## 'data.frame':    4331 obs. of  8 variables:
##  $ Protocol   : Factor w/ 14 levels "A","C","D","E",..: 4 4 4 4 4 4 4 4 4 4 ...
##  $ Compounds  : num  997 97 101 93 100 100 105 98 101 95 ...
##  $ InputFields: num  137 103 75 76 82 82 88 95 91 92 ...
##  $ Iterations : num  20 20 10 20 20 20 20 20 20 20 ...
##  $ NumPending : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ Hour       : num  14 13.8 13.8 10.1 10.4 ...
##  $ Day        : Factor w/ 7 levels "Mon","Tue","Wed",..: 2 2 4 5 5 3 5 5 5 3 ...
##  $ Class      : Factor w/ 4 levels "VF","F","M","L": 2 1 1 1 1 1 1 1 1 1 ...

Les données sont un mélange de prédicteurs catégoriques et numériques. Supposons que nous voulions utiliser la transformation Yeo-Johnson sur les prédicteurs continus, puis les centrer et les mettre à l’échelle. Supposons également que nous exécutons un modèle basé sur un arbre, nous voudrons donc peut-être conserver les facteurs en tant que facteurs (par opposition à la création de variables fictives). Nous exécutons la fonction sur toutes les colonnes sauf la dernière, qui est le résultat.

pp_hpc <- preProcess(schedulingData[, -8], 
                     method = c("center", "scale", "YeoJohnson"))
pp_hpc
## Created from 4331 samples and 7 variables
## 
## Pre-processing:
##   - centered (5)
##   - ignored (2)
##   - scaled (5)
##   - Yeo-Johnson transformation (5)
## 
## Lambda estimates for Yeo-Johnson transformation:
## -0.08, -0.03, -1.05, -1.1, 1.44
transformed <- predict(pp_hpc, newdata = schedulingData[, -8])
head(transformed)
##   Protocol  Compounds InputFields Iterations NumPending         Hour Day
## 1        E  1.2289592  -0.6324580 -0.0615593  -0.554123  0.004586516 Tue
## 2        E -0.6065826  -0.8120473 -0.0615593  -0.554123 -0.043733201 Tue
## 3        E -0.5719534  -1.0131504 -2.7894869  -0.554123 -0.034967177 Thu
## 4        E -0.6427737  -1.0047277 -0.0615593  -0.554123 -0.964170752 Fri
## 5        E -0.5804713  -0.9564504 -0.0615593  -0.554123 -0.902085020 Fri
## 6        E -0.5804713  -0.9564504 -0.0615593  -0.554123  0.698108782 Wed

Les deux prédicteurs étiquetés comme « ignorés » dans la sortie sont les deux prédicteurs factoriels. Ceux-ci ne sont pas modifiés mais les prédicteurs numériques sont transformés. Cependant, le prédicteur du nombre d’emplois en attente a une distribution très clairsemée et déséquilibrée :

mean(schedulingData$NumPending == 0)
## [1] 0.7561764

Pour certains autres modèles, cela peut poser problème (surtout si nous rééchantillonnons ou sous-échantillonnons les données). Nous pouvons ajouter un filtre pour vérifier les prédicteurs de variance nulle ou proche de zéro avant d’exécuter les calculs de prétraitement :

pp_no_nzv <- preProcess(schedulingData[, -8], 
                        method = c("center", "scale", "YeoJohnson", "nzv"))
pp_no_nzv
## Created from 4331 samples and 7 variables
## 
## Pre-processing:
##   - centered (4)
##   - ignored (2)
##   - removed (1)
##   - scaled (4)
##   - Yeo-Johnson transformation (4)
## 
## Lambda estimates for Yeo-Johnson transformation:
## -0.08, -0.03, -1.05, 1.44
predict(pp_no_nzv, newdata = schedulingData[1:6, -8])
##   Protocol  Compounds InputFields Iterations         Hour Day
## 1        E  1.2289592  -0.6324580 -0.0615593  0.004586516 Tue
## 2        E -0.6065826  -0.8120473 -0.0615593 -0.043733201 Tue
## 3        E -0.5719534  -1.0131504 -2.7894869 -0.034967177 Thu
## 4        E -0.6427737  -1.0047277 -0.0615593 -0.964170752 Fri
## 5        E -0.5804713  -0.9564504 -0.0615593 -0.902085020 Fri
## 6        E -0.5804713  -0.9564504 -0.0615593  0.698108782 Wed

Notez qu’un prédicteur est étiqueté comme “supprimé” et que les données traitées n’ont pas le prédicteur clairsemé.

10 Calculs de distance de classe

caretcontient des fonctions pour générer de nouvelles variables prédictives basées sur les distances aux centroïdes de classe (similaire au fonctionnement de l’analyse discriminante linéaire). Pour chaque niveau d’une variable factorielle, le centroïde de classe et la matrice de covariance sont calculés. Pour les nouveaux échantillons, la distance de Mahalanobis à chacun des centroïdes de classe est calculée et peut être utilisée comme prédicteur supplémentaire. Cela peut être utile pour les modèles non linéaires lorsque la véritable limite de décision est en fait linéaire.

Dans les cas où il y a plus de prédicteurs dans une classe que d’échantillons, la classDistfonction a des arguments appelés pcaet keepdes arguments qui permettent d’utiliser l’analyse des composants principaux dans chaque classe pour éviter les problèmes avec les matrices de covariance singulières.

predict.classDistest ensuite utilisé pour générer les distances de classe. Par défaut, les distances sont enregistrées, mais cela peut être modifié via l’ transargument de predict.classDist.

A titre d’exemple, nous pouvons utiliser les données MDRR.

centroids <- classDist(trainBC, trainMDRR)
distances <- predict(centroids, testBC)
distances <- as.data.frame(distances)
head(distances)
##                dist.Active dist.Inactive
## ACEPROMAZINE      3.787139      3.941234
## ACEPROMETAZINE    4.306137      3.992772
## MESORIDAZINE      3.707296      4.324115
## PERIMETAZINE      4.079938      4.117170
## PROPERICIAZINE    4.174101      4.430957
## DUOPERONE         4.355328      6.000025

Cette image montre une matrice de nuage de points des distances de classe pour les échantillons retenus :

xyplot(dist.Active ~ dist.Inactive,
       data = distances, 
       groups = testMDRR, 
       auto.key = list(columns = 2))