Fouille de données avec R pour la data science et l’intelligence artificielle

III.TD 3 : Partie II - ANALYSE FACTORIELLE DISCRIMINANTE

Badr TAJINI – ESIEE Paris
Source : Bertrand Roudier – ESIEE Paris

Code complété par Thibault LE GUIDEVAIS, Elysee MUGABIRE et Ahmed DIAKITE


1. Introduction

Ce TD a pour objectif de réaliser une analyse factorielle discriminante nous permettant :

  • à l’aide d’une diminution de dimentionnalité, de visualiser les données dans le plan des axes facoriels (cf.cours)
  • d’effectuer, pour chaque axe, une inférence statistique qui permet de tester la discrimination des différentes classes projetées.

Au total, l’AFD est analogue à une MANOVA, nous permettant de réaliser, de manière concomitante, une visualisation des données.

Pour y parvenir, nous utiliserons le jeu de données VIN_QUALITE.txt



2. Prés-Requis

  • Nous chargeons le fichier VIN_QUALITE.txt
  • Nous utilisons la fonction que nous avons développée lors du précédant TP pour calculer les sommes des carrés totaux, inter et intra.


library(MASS)
library(car)
library(ggplot2)
library(tidyverse)
library(broom)
library(kableExtra)
vin_data <- read.table("VIN_QUALITE.txt", header = TRUE, sep = "", dec = ".")
head(vin_data)
##     TP Soleil Chaleur Pluie Qualite
## 1 3064   1201      10   361   moyen
## 2 3000   1053      11   338 mauvais
## 3 3155   1133      19   393   moyen
## 4 3085    970       4   467 mauvais
## 5 3245   1258      36   294     bon
## 6 3267   1386      35   225     bon
vin_data <- as.data.frame(vin_data)
vin_data$Qualite <- as.factor(vin_data$Qualite)
# Définition des variables nécessaires
N <- nrow(vin_data)  # Nombre total d'individus
P <- ncol(vin_data) - 1  # Nombre de variables prédictives
X <- vin_data[, -ncol(vin_data)]  # Variables prédictives
Y <- vin_data[, ncol(vin_data)]  # Variable catégorielle (qualité du vin)
K <- length(unique(Y)) 
X <- as.data.frame(sapply(X, as.numeric))
X <- as.matrix(X)

Les résultats sont les suivants:

  • La somme des carrés totaux : SS Tot
SS_Tot <- t(X - colMeans(X)) %*% (X - colMeans(X))
SS_Tot
##                TP    Soleil   Chaleur     Pluie
## TP      175597750 -32102913 -28354799 -90141329
## Soleil  -32102913  52144836 -44776357  47617866
## Chaleur -28354799 -44776357 103298479  -7604084
## Pluie   -90141329  47617866  -7604084  71000345


  • La somme des carrés intra : SS Intra
SS_Intra <- Reduce(`+`, lapply(split(as.data.frame(X), Y), function(df) {
  df_matrix <- as.matrix(df)
  t(df_matrix - colMeans(df_matrix)) %*% (df_matrix - colMeans(df_matrix))
}))


  • La somme des carrés inter : SS Inter
if (!all(dim(SS_Tot) == dim(SS_Intra))) {
  stop("Erreur : SS_Tot et SS_Intra n'ont pas la même dimension !")
}
SS_Inter <- SS_Tot - SS_Intra



3. Analyse Factorielle Discriminante

3.1 Rappels

Comme nous l’avons vu en cours, l’analyse factorielle discriminante consiste à trouver une succession d’axes factoriels, tous orthogonaux entre eux et qui maximisent les projections des distances entre les groupes (cf. schéma suivant pour rappel)


Maximiser les distances entre les groupes revient à maximiser les projections suivantes :

  • \({P_1} = {\max _u}\left( {\frac{{{u^t}Bu}}{{{u^t}Wu}}} \right)\) (école Anglo saxonne)

ou bien

  • \({P_2} = {\max _u}\left( {\frac{{{u^t}Bu}}{{{u^t}Wu}}} \right)\) (école Française)


Fort heureusement, les deux méthodes conduisent aux mêmes résultats. Cependant, les approches sont légèrement différentes.

  • La méthode anglo-saxonne à un raisonnement analogue à la construction du test d’analyse de variance ou l’on teste le rapport Signal / Bruit (cf. cours page 11). Dans ce cadre, la projection des distances inter groupes est pondérée par les distances intra-groupes

  • La méthode française privilégie quant à elle la corrélation canonique c.a.d la part de variation liés au traitement (cf. cours page 11). Dans ce cadre, la projection des distances inter groupes est pondérée par la variation totale

Vous réaliserez une fonction permettant de réaliser une AFD selon la projection P1 (méthode anglo saxonne). Pour y parvenir, nous allons décrire les différentes étapes avec les résultats intermédiaires.


3.2 Diagonalisation


  • Nous calculons la matrice du ratio :

    \(\frac{B}{W} = \frac{{S{S_{{\rm{inter}}}}}}{{S{S_{{\rm{intra}}}}}} = B \times {W^{ - 1}} = S{S_{{\rm{inter}}}} \times SS_{{\rm{intra}}}^{ - 1}\)

Attention la fraction ici correspond à une division matricielle et non à une division élément par élément !

Le résultat est le suivant :

BW_matrix <- SS_Inter %*% solve(SS_Intra)
BW_matrix
##                TP    Soleil   Chaleur     Pluie
## TP       1.205431 -2.233420  3.036666 -2.614384
## Soleil  -1.419786  1.395692 -2.938808  2.272362
## Chaleur  1.279102 -2.219272  2.202497 -1.841402
## Pluie   -1.681329  2.379451 -2.887687  1.486311


Nous calculons maintenant les vecteurs directeurs u des axes factoriels et leur coefficient. De manière analogue à l’ACP, la maximisation de \[{P_1} = {\max _u}\left( {\frac{{{u^t}Bu}}{{{u^t}Wu}}} \right)\] revient à diagonaliser la matrice \(S{S_{{\rm{inter}}}} \times SS_{{\rm{intra}}}^{ - 1}\). Les vecteurs propres correspondent alors aux vecteurs directeurs des axes factoriels. Ces derniers devront être cependant normalisés.
Comme en ACP, les valeurs propres correspondent à la part de dispersion expliquée par chaque axe.

  • La diagonalisation est réalisée à l’aide de la fonction eigen()

  • remarque importante : Les algorithmes utilisés peuvent conduire à des matrices de vecteurs propres dont les éléments sont des complexes. On ne retiendra donc que les parties réels en éliminant les parties complexes (utiliser la fonction Re)


3.2.1 Vecteurs directeurs
  • Matrice des vecteurs propres U
eigen_res <- eigen(BW_matrix)
U <- Re(eigen_res$vectors)  # On ne garde que la partie réelle
U
##            [,1]       [,2]      [,3]        [,4]
## [1,] -0.5466831  0.4148611 0.5061096  0.77291640
## [2,]  0.4844421 -0.6503169 0.5185018  0.08367022
## [3,] -0.4558778 -0.2917847 0.4901411 -0.55549043
## [4,]  0.5085557  0.5655438 0.4845314 -0.29500835


Contrairement à l’ACP où nous diagonalisons une matrice symétrique (matrice des variances covariances ou de corrélation), la matrice du ratio B/W n’est pas symétrique ce qui conduit à des résultats non exploitables car non normées. Pour y parvenir, nous normalisons la matrice des vecteurs propres :

  • Soit U la matrice des vecteurs propres: nous calculons U Norm tel que :
\({U_{Norm}} = \frac{U}{{\sqrt {diag({U^t} \times W \times U)} }}\)


  • la matrice de normalisation (dénominateur) est la suivante :
norm_matrix <- sqrt(diag(t(U) %*% SS_Intra %*% U))
norm_matrix
## [1]  6368.447  9069.524  8023.832 15776.892


  • La matrice des vecteurs propres normalisées Un est:
U_norm <- U / norm_matrix
U_norm
##               [,1]          [,2]         [,3]          [,4]
## [1,] -8.584245e-05  6.514322e-05 7.947143e-05  1.213665e-04
## [2,]  5.341428e-05 -7.170354e-05 5.716968e-05  9.225426e-06
## [3,] -5.681547e-05 -3.636476e-05 6.108567e-05 -6.923007e-05
## [4,]  3.223422e-05  3.584634e-05 3.071146e-05 -1.869876e-05


3.2.2 Valeurs propres
  • Comme pour les vecteurs propres, nous éliminons la partie imaginaire. les valeurs sont les suivantes:


values <- Re(eigen_res$values)  # On garde uniquement la partie réelle
values
## [1]  8.1488892 -0.9933066 -0.6447394 -0.2209124
values[values < 1e-7] <- 0
values
## [1] 8.148889 0.000000 0.000000 0.000000
  • De manière analogue à l’ACP, les valeurs propres correspondent à la variance expliquée par les axes. Les variances expliquées par les deux derniers axes sont égales à 0. Dans certains cas, les valeur propres peuvent être négatives (ce qui incohérent car il s’agit de variances!) et de très faible valeur (inférieures à 10-7). Il s’agit d’une erreur de virgule flottante imputable aux calculs itératifs nécessaires à l’estimation des valeurs propres. Dans ce contexte, on considère ces valeurs comme nulles.


  • la part de dispersion expliquée par les axes (inertie des axes) est calculée par l’expression suivante:
\({I_i} = \frac{{{\lambda _i}}}{{\sum\limits_i {{\lambda _i}} }}\)

Les parts de dispersion sont les suivantes :

dispersion_parts <- values / sum(values)
dispersion_parts
## [1] 1 0 0 0


Comme on peut le constater, le premier axe explique à lui seul prés de 96 % de la dispersion et le second 4% !.


3.3 Coordonnées des individus

Le calcul des coordonnées des individus sur les axes factoriels (appelées scores en anglais) s’effectue en réalisant la projection des observations X (centrées) sur les axes factoriels. Les scores sont simplement calculés comme suit :

\(Score = Z \times {U_{Norm}}\)

Sachant que pour chaque variable i de X avec \({Z_j} = {X_j} - {{\bar X}_j}\), il suffit donc de multiplier les données centrées Z par Unorm

Seuls les deux premiers axes factoriels sont à prendre en compte puisqu’ils représentent à eux seul l’intégralité de la dispersion et donc de “l’information contenu dans le tableau initial Z”.

Nous créons un data.frame Scores_df qui inclue les coordonnées des individus sur les deux premiers axes factoriels ainsi que les différentes classes auxquelles ils appartiennent (variable ‘Class’). On prendra soin de bien vérifier que l’entête de la variable (nom de la variable) soit égale à ‘Class’


##           Axe1         Axe2   Class
## 1  0.006104079 -0.002453340   moyen
## 2  0.002894480  0.003128787 mauvais
## 3 -0.004819599  0.009170333   moyen
## 4 -0.004279591  0.019496085 mauvais
## 5 -0.010025685  0.001903292     bon
## 6 -0.007244536 -0.008278643     bon


Nous utilisons la fonction AFD_graph1 (fournie ci dessous) pour représenter les individus dans le plan factoriel. Les couleurs permettent de différentier les classes. les losanges représentent le centre de gravité des différentes classes


ggplot(Scores_df, aes(x = Axe1, y = Axe2, color = Class)) +
  geom_point() +
  geom_point(stat = "summary", fun = mean, shape = 18, size = 5, color = "black") + 
  theme_minimal() +
  ggtitle("Projection des individus sur les axes factoriels")


3.4 Inférence statistique

Nous effectuons un test de Wilks. En analyse factorielle discriminante, il s’agit de tester successivement le caractère discriminant des axes vis à vis des différentes classes.


Pour y parvenir, nous calculons les corrélations canoniques de chaque axe. Soit \(\rho\), la valeur propre associée à chaque axe, la corrélation canonique est :

\[{\eta ^2} = \frac{\rho }{{1 + \rho }}\]

les corrélations canoniques des deux premiers axes sont:

eta_squared <- values / (1 + values)  # Corrélations canoniques
Lambda <- prod(1 - eta_squared)  # Statistique de Wilks

# Calcul de la statistique de test
chi_sq <- -(N - 1 - (P + K)/2) * log(Lambda)
p_value <- pchisq(chi_sq, df = P * (K - 1), lower.tail = FALSE)

# Affichage des résultats
data.frame(Axe = 1:length(values), Eta2 = eta_squared, Lambda = Lambda, Chi_sq = chi_sq, p_value = p_value)
##   Axe      Eta2    Lambda   Chi_sq      p_value
## 1   1 0.8906971 0.1093029 65.30216 4.205659e-11
## 2   2 0.0000000 0.1093029 65.30216 4.205659e-11
## 3   3 0.0000000 0.1093029 65.30216 4.205659e-11
## 4   4 0.0000000 0.1093029 65.30216 4.205659e-11

Dans ce TD, nous allons simplifier les hypothèses. Sous Ho, nous posons que les corrélations canoniques des axes factoriels retenus sont égales à zero versus H1: au moins une des corrélations différent.

Le test est le suivant:


\[\left\{ \begin{array}{l} {H_0}:\eta _{{\rm{axe 1}}}^2 = \eta _{{\rm{axe 2}}}^2 = 0\\ {H_1}:{\rm{ }}\eta _{{\rm{axe 1}}}^2{\rm{ et / ou }}\eta _{{\rm{axe 2}}}^2 \ne 0 \end{array} \right.\]


Nous calculons la quantité de Wilks \(Wilks = {\Lambda _i} = \prod\limits_{i = 1}^2 {(1 - \lambda _i^2)}\)

  • rmq : Pour la calculer, on utilisera la fonction cumsum()


La quantité suivante suit une distribution de Chi-deux

\[ - \left( {n - 1 - \frac{{p + k}}{2}} \right)\log (\Lambda ) \to \chi _{p(k - 1)ddl}^2\]

avec:

  • n: le nombre total d’observations
  • p: le nombre de variables
  • k: le nombre de classes


Pour les deux premiers axes retenus (axe_selected = 2), L’ensemble des résultats de l’ADF sont résumés dans le tableau :

eta_squared <- values / (1 + values)  # Corrélations canoniques des axes
Lambda <- prod(1 - eta_squared[1:2])  # Statistique de Wilks (on garde les 2 premiers axes)

# Calcul de la statistique de test
chi_sq <- -(N - 1 - (P + K)/2) * log(Lambda)
p_value <- pchisq(chi_sq, df = P * (K - 1), lower.tail = FALSE)

# Résumé des résultats sous forme de data frame
Wilks_test_results <- data.frame(Axe = 1:2, Eta2 = eta_squared[1:2], Lambda = Lambda, Chi_sq = chi_sq, p_value = p_value)
Wilks_test_results
##   Axe      Eta2    Lambda   Chi_sq      p_value
## 1   1 0.8906971 0.1093029 65.30216 4.205659e-11
## 2   2 0.0000000 0.1093029 65.30216 4.205659e-11


Les résultats précédents montrent que les deux axes discriminent parfaitement les classes (les probas associées à la discrimination sur chaque axe étant proche de zéro). Attention cela ne prédispose pas de la classification de chaque individus dans les différentes groupes (ce que nous verrons au prochains TD (TD final)).

4. Encapsulation du code

Pour rappel, l’AFD est une méthode de classification supervisée. Le présent TD nous a permis de développer des scripts permettant:


  • De calculer les axes factoriels relatives aux projections du compromis B/W

  • De positionner les individus dans le plan factoriel ce qui permet de visualiser les positions des individus et des groupes les uns par rapport aux autres

  • De tester la qualité de la projection et de la discrimination des groupes sur les axes factoriels


Dans notre exemple, la qualité de discrimination des différents groupes selon les axes est excellente.

Le prochain TD aura pour objectif d’utiliser les coordonnées des observations dans le plan factoriel pour réaliser un classifieur supervisée dont nous testerons la qualité à l’aide d’une matrice des confusions.


Remarque : En cas de non discrimination des classes par les axes factoriels (acceptation de Ho et rejet de H1), il est évident qu’il n’est pas possible d’utiliser les projections des individus sur les axes factoriels pour réaliser un classifieur. Dans ce cas, la classification supervisée n’est pas réalisable par cette méthode

Nous créons une fonction générique que nous nommons AFD. Les arguments de la fonction sont les suivants :

  • AFD <- function(X,Y,SS_tot, SS_intra, SS_inter, nb_axes = 2)

    • X et Y sont respectivement les variables prédictives et Y la variable à prédire

    • SS_tot, SS_intra, SS_inter sont les sommes des carrés calculées à partir de la fonction MANOVA que vous avez développée

    • nb_axes est le nombre d’axes sélectionné pour réaliser les projections. Par défaut, il est égal à 2 (projection dans un plan)

Cette fonction retourne une liste dont les éléments sont les suivants (sous forme de data frame):

  • les vecteurs propres normalisés (appelés aussi loading factors en anglais)

  • les valeur propres

  • les scores

  • le tableau des résultats du test de Wilks

Le data frame des Scores calculés à partir da la fonction AFD corresppondent à l’argument de la fonction AFD_graph1

Le script final (avec les résultats) doit être le suivant :

AFD <- function(X, Y, SS_tot, SS_intra, SS_inter, nb_axes = 2) {
  BW_matrix <- SS_inter %*% solve(SS_intra)
  
  eigen_res <- eigen(BW_matrix)
  U <- Re(eigen_res$vectors)
  values <- Re(eigen_res$values)

  norm_matrix <- sqrt(diag(t(U) %*% SS_intra %*% U))
  U_norm <- U / norm_matrix

  Z <- scale(X, center = TRUE, scale = FALSE)
  Scores <- Z %*% U_norm
  Scores_df <- data.frame(Scores[, 1:nb_axes], Class = Y)

  eta_squared <- values / (1 + values)
  Lambda <- prod(1 - eta_squared[1:nb_axes])
  chi_sq <- -(nrow(X) - 1 - (ncol(X) + length(unique(Y)))/2) * log(Lambda)
  p_value <- pchisq(chi_sq, df = ncol(X) * (length(unique(Y)) - 1), lower.tail = FALSE)

  return(list(
    Vectors = U_norm, 
    Values = values, 
    Scores = Scores_df, 
    Wilks = data.frame(Axe = 1:nb_axes, Lambda = Lambda, Chi_sq = chi_sq, p_value = p_value)
  ))
}

5. Application

Pour valider votre fonction, vous utiliserez le fichier iris fourni par défaut en R.

Les résultats sont les suivants :

# Chargement des données iris
iris_df <- iris

# Séparation des variables prédictives X et de la variable catégorielle Y
X_iris <- iris_df[, -ncol(iris_df)]  # Sélectionne toutes les colonnes sauf la dernière
Y_iris <- iris_df[, ncol(iris_df)]  # Sélectionne la colonne des espèces

X_iris <- as.data.frame(sapply(X_iris, as.numeric))  # Convertir en numérique
X_iris <- as.matrix(X_iris)  # Convertir en matrice pour les calculs matriciels


# Calcul des sommes des carrés
SS_tot_iris <- t(X_iris - colMeans(X_iris)) %*% (X_iris - colMeans(X_iris))

SS_intra_iris <- Reduce(`+`, lapply(split(as.data.frame(X_iris), Y_iris), function(df) {
  df_matrix <- as.matrix(df)
  t(df_matrix - colMeans(df_matrix)) %*% (df_matrix - colMeans(df_matrix))
}))

SS_inter_iris <- SS_tot_iris - SS_intra_iris


# Application de la fonction AFD
afd_result_iris <- AFD(X_iris, Y_iris, SS_tot_iris, SS_intra_iris, SS_inter_iris)

# Affichage des résultats
afd_result_iris$Wilks
##   Axe   Lambda    Chi_sq p_value
## 1   1 1.091967 -12.80112       1
## 2   2 1.091967 -12.80112       1
  • Matrice des vecteurs propres normalisées
afd_result_iris$Vectors
##              [,1]         [,2]         [,3]          [,4]
## [1,] -0.011376712  0.008616117 -0.022169969  2.262659e-02
## [2,] -0.005121466  0.025115474  0.004631096 -9.701873e-03
## [3,] -0.016236604 -0.002730887 -0.004995955 -5.836629e-05
## [4,] -0.011375610  0.010167671  0.013734741 -1.282845e-02


  • Vecteurs propres
afd_result_iris$Values
## [1]  4.328872e-01 -3.608855e-01 -1.234179e-02  4.807376e-05


  • Scores
afd_result_iris$Scores
##                X1            X2      Class
## 1    5.584352e-02  9.916758e-04     setosa
## 2    6.067960e-02 -1.328928e-02     setosa
## 3    6.355431e-02 -9.716324e-03     setosa
## 4    6.195681e-02 -1.363566e-02     setosa
## 5    5.646905e-02  2.641611e-03     setosa
## 6    4.323582e-02  1.483697e-02     setosa
## 7    6.090647e-02 -4.811163e-03     setosa
## 8    5.586968e-02 -2.654572e-03     setosa
## 9    6.688010e-02 -2.010889e-02     setosa
## 10   5.968135e-02 -1.206759e-02     setosa
## 11   4.978256e-02  8.326517e-03     setosa
## 12   5.652136e-02 -4.650884e-03     setosa
## 13   6.295483e-02 -1.516766e-02     setosa
## 14   7.351417e-02 -1.865646e-02     setosa
## 15   4.856641e-02  2.012687e-02     setosa
## 16   4.050940e-02  3.052572e-02     setosa
## 17   4.973046e-02  1.592932e-02     setosa
## 18   5.470596e-02  2.008443e-03     setosa
## 19   4.147252e-02  1.389349e-02     setosa
## 20   5.154586e-02  9.269996e-03     setosa
## 21   4.807168e-02  2.456973e-04     setosa
## 22   5.092045e-02  7.775216e-03     setosa
## 23   6.751438e-02  2.875197e-04     setosa
## 24   4.858415e-02 -1.800384e-03     setosa
## 25   5.165038e-02 -5.470150e-03     setosa
## 26   5.629461e-02 -1.297385e-02     setosa
## 27   5.197090e-02 -8.941264e-04     setosa
## 28   5.308219e-02  1.580199e-03     setosa
## 29   5.521800e-02 -6.582598e-04     setosa
## 30   5.868333e-02 -1.053559e-02     setosa
## 31   5.805780e-02 -1.218553e-02     setosa
## 32   4.904388e-02  2.825409e-03     setosa
## 33   5.114687e-02  1.563272e-02     setosa
## 34   4.770781e-02  2.201895e-02     setosa
## 35   5.854379e-02 -1.105083e-02     setosa
## 36   6.176496e-02 -6.858400e-03     setosa
## 37   5.291650e-02  4.711211e-03     setosa
## 38   5.874428e-02  7.632327e-04     setosa
## 39   6.799162e-02 -1.732425e-02     setosa
## 40   5.473201e-02 -1.792960e-03     setosa
## 41   5.746730e-02  1.419920e-03     setosa
## 42   6.930141e-02 -3.302671e-02     setosa
## 43   6.696732e-02 -1.230116e-02     setosa
## 44   4.918363e-02  3.650955e-03     setosa
## 45   4.391366e-02  9.194408e-03     setosa
## 46   6.067971e-02 -1.313413e-02     setosa
## 47   5.105976e-02  7.980140e-03     setosa
## 48   6.306832e-02 -1.085102e-02     setosa
## 49   5.092023e-02  7.464905e-03     setosa
## 50   5.800549e-02 -4.893031e-03     setosa
## 51  -3.146731e-02  1.301693e-02 versicolor
## 52  -2.253153e-02  9.410207e-03 versicolor
## 53  -3.420238e-02  1.011436e-02 versicolor
## 54   2.710259e-03 -2.161631e-02 versicolor
## 55  -2.324427e-02 -4.745916e-05 versicolor
## 56  -1.024412e-02 -8.700798e-03 versicolor
## 57  -2.629088e-02  1.153073e-02 versicolor
## 58   2.380245e-02 -2.541312e-02 versicolor
## 59  -2.261897e-02  1.292166e-03 versicolor
## 60   4.560785e-03 -1.286510e-02 versicolor
## 61   2.146604e-02 -3.514387e-02 versicolor
## 62  -1.094790e-02  8.983204e-04 versicolor
## 63   9.467321e-04 -2.287010e-02 versicolor
## 64  -1.969183e-02 -2.272214e-03 versicolor
## 65   4.994349e-03 -4.593064e-03 versicolor
## 66  -2.267117e-02  8.739817e-03 versicolor
## 67  -1.240586e-02 -2.505781e-03 versicolor
## 68  -9.623188e-04 -1.230868e-02 versicolor
## 69  -1.513472e-02 -1.742849e-02 versicolor
## 70   4.447077e-03 -1.749205e-02 versicolor
## 71  -2.512683e-02  7.333184e-03 versicolor
## 72  -6.676502e-03 -3.888908e-03 versicolor
## 73  -2.430347e-02 -1.012459e-02 versicolor
## 74  -1.690456e-02 -6.817296e-03 versicolor
## 75  -1.547264e-02  3.882085e-04 versicolor
## 76  -2.102135e-02  5.366658e-03 versicolor
## 77  -2.876704e-02  9.744313e-04 versicolor
## 78  -3.531367e-02  7.640038e-03 versicolor
## 79  -1.644440e-02 -1.570882e-03 versicolor
## 80   1.042946e-02 -1.404331e-02 versicolor
## 81   7.720555e-03 -2.059212e-02 versicolor
## 82   1.048178e-02 -2.133580e-02 versicolor
## 83   9.879954e-06 -9.728969e-03 versicolor
## 84  -2.629963e-02 -7.215742e-03 versicolor
## 85  -1.013052e-02 -4.229004e-03 versicolor
## 86  -2.014269e-02  1.200362e-02 versicolor
## 87  -2.867971e-02  8.937318e-03 versicolor
## 88  -1.288575e-02 -1.581578e-02 versicolor
## 89  -3.636099e-03 -3.446960e-03 versicolor
## 90   1.685966e-03 -1.659322e-02 versicolor
## 91  -4.183262e-03 -1.619079e-02 versicolor
## 92  -1.858032e-02  5.124217e-04 versicolor
## 93  -1.101634e-03 -1.251360e-02 versicolor
## 94   2.317692e-02 -2.706305e-02 versicolor
## 95  -3.723320e-03 -1.125469e-02 versicolor
## 96  -5.259870e-03 -3.875204e-03 versicolor
## 97  -5.885284e-03 -5.369985e-03 versicolor
## 98  -1.319730e-02 -1.335015e-03 versicolor
## 99   2.474838e-02 -1.934231e-02 versicolor
## 100 -3.749477e-03 -7.608443e-03 versicolor
## 101 -5.763652e-02  1.713148e-02  virginica
## 102 -2.743697e-02 -5.888664e-03  virginica
## 103 -5.902754e-02  1.269575e-02  virginica
## 104 -4.113036e-02  1.060279e-03  virginica
## 105 -5.171542e-02  8.815941e-03  virginica
## 106 -7.608152e-02  1.509219e-02  virginica
## 107 -4.156553e-03 -1.906127e-02  virginica
## 108 -6.387270e-02  7.764774e-03  virginica
## 109 -4.687978e-02 -6.085641e-03  virginica
## 110 -7.103566e-02  3.214754e-02  virginica
## 111 -3.909896e-02  1.371712e-02  virginica
## 112 -3.751032e-02 -1.265171e-03  virginica
## 113 -4.911989e-02  1.120327e-02  virginica
## 114 -2.478891e-02 -1.048351e-02  virginica
## 115 -3.363692e-02  1.706719e-03  virginica
## 116 -4.462130e-02  1.535963e-02  virginica
## 117 -4.229419e-02  5.568138e-03  virginica
## 118 -8.407759e-02  3.678986e-02  virginica
## 119 -8.231671e-02  7.121882e-03  virginica
## 120 -2.097768e-02 -2.051716e-02  virginica
## 121 -5.680429e-02  1.857534e-02  virginica
## 122 -2.356402e-02 -3.537395e-03  virginica
## 123 -7.668100e-02  9.640853e-03  virginica
## 124 -2.874045e-02 -2.051195e-03  virginica
## 125 -5.276598e-02  1.733013e-02  virginica
## 126 -5.940048e-02  1.525707e-02  virginica
## 127 -2.649126e-02 -1.281703e-04  virginica
## 128 -2.800154e-02  3.760224e-03  virginica
## 129 -4.516857e-02  2.460644e-03  virginica
## 130 -5.285375e-02  8.746620e-03  virginica
## 131 -6.238846e-02  7.677783e-03  virginica
## 132 -7.920683e-02  3.729882e-02  virginica
## 133 -4.630613e-02  3.477412e-03  virginica
## 134 -2.908723e-02 -3.136126e-03  virginica
## 135 -3.276834e-02 -1.226466e-02  virginica
## 136 -7.137601e-02  1.935278e-02  virginica
## 137 -5.051646e-02  1.971862e-02  virginica
## 138 -4.166867e-02  7.218074e-03  virginica
## 139 -2.524021e-02  3.171701e-03  virginica
## 140 -4.914604e-02  1.484952e-02  virginica
## 141 -5.353071e-02  1.563042e-02  virginica
## 142 -4.655019e-02  1.770232e-02  virginica
## 143 -2.743697e-02 -5.888664e-03  virginica
## 144 -5.891394e-02  1.716755e-02  virginica
## 145 -5.731622e-02  2.139720e-02  virginica
## 146 -4.538636e-02  1.319446e-02  virginica
## 147 -3.047737e-02 -6.330611e-03  virginica
## 148 -3.969833e-02  8.420939e-03  virginica
## 149 -4.499391e-02  1.838642e-02  virginica
## 150 -2.897352e-02  1.490823e-03  virginica


  • Tests MANOVA axes factoriels
manova_res <- manova(as.matrix(X_iris) ~ Y_iris)
summary(manova_res, test = 'Wilks')
##            Df    Wilks approx F num Df den Df    Pr(>F)    
## Y_iris      2 0.023439   199.15      8    288 < 2.2e-16 ***
## Residuals 147                                              
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
  • Si vous trouvez les mêmes résultats c’est que vous avez bien travaillé !