Résumé: L'analyse factorielle multiple des correspondance (AFCM) n'est pas disponible dans la librairie scikit-learn
ni dans tout autre librairie officielle. Elle est obtenue en utilisant celle plus fruste: MCA
. Illustration sommaire de l'AFCM, sur des données "jouet" puis sur celles du naufrage du Titanic.
L'AFCM est une méthode proposée en France par Benzécri en 1982 avant d'être diffusée en langue anglaise de Leeuw (1985) puis par Greenacre à partir de 2005 sans pour autant être très utilisée et donc présente dans la plupart des logiciels (sauf SAS). Elle est très développée dans la librairie R factoMineR
au sein de l'Agrocampus de Rennes mais absente des principales lbrairies en Python plus concernées par des données physiques, signaux ou images.
Il ne serait pas difficile de recontruire cette analyse en suivant le déroulement des calculs matriciels: SVD du tableau disjonctif complet. Néanmoins, ce qui reste le plus compliqué est la gestion des types possibles de données : table de contingence, tableau de Burt, tableau disjontif, en association ou nom à la classe DataFrame
, ainsi que la production de graphiques de qualité. Il est aussi possible d'exploiter un embryon de programme: MCA
en installant la librairie correspondante par la commande pip install --user mca
selon l'installation, ou en chargeant le seul module mca.py
dans le répertoire courant.
Comme pour l'ACP ou l'AFD, il est bienvenu de contrôler les résultats fournis sur un exemple jouet avant d'aborder des données plus complexes.
Il reste du travail pour: traiter directement un objet DataFrame
, accepter des variables siupplémentaires, construire des fonction graphiques de qualité...
In [ ]:
# Librairies
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
# Lire les données avec plusieurs espaces comme séparateur
# oublier la première colonne et utilisaer la première ligne pour le nom des variables
datFic=pd.read_table('Data/afcfic.dat',header=0,sep='\s+',usecols=[1,2])
datFic
In [ ]:
# Changer le type
datFic["csp"]=pd.Categorical(datFic["csp"],ordered=False)
datFic["sport"]=pd.Categorical(datFic["sport"],ordered=False)
datFic
In [ ]:
datFic.describe()
In [ ]:
pd.crosstab(datFic["csp"],datFic["sport"])
In [ ]:
# Indicatrices
dc=pd.DataFrame(pd.get_dummies(datFic))
dc.head()
In [ ]:
from mca import MCA
mcaFic=MCA(dc,benzecri=False)
# Valeurs singulières
print(mcaFic.L)
Q De l'AFC de quel tableau sont ces valeurs propres? (comparer avec R).
Q Que sont les tableaux ci-dessous?
In [ ]:
print(mcaFic.fs_c())
In [ ]:
print(mcaFic.fs_r())
In [ ]:
plt.scatter(mcaFic.fs_c()[:, 0],mcaFic.fs_c()[:, 1])
for i, j, nom in zip(mcaFic.fs_c()[:, 0],mcaFic.fs_c()[:, 1], dc.columns):
plt.text(i, j, nom)
plt.show()
In [ ]:
plt.scatter(mcaFic.fs_r()[:, 0],mcaFic.fs_r()[:, 1])
for i, j, nom in zip(mcaFic.fs_r()[:, 0],mcaFic.fs_r()[:, 1], dc.index):
plt.text(i, j, nom)
plt.show()
In [ ]:
# Lire les données
df=pd.read_csv('Data/titanic.csv',skiprows=1,header=None,usecols=[1,2,4,5,9,11],
names=["Surv","Classe","Genre","Age","Prix","Port"],dtype={"Surv":object,"Classe":object,"Genre":object,"Port":object})
df.head()
In [ ]:
df.shape # dimensions
In [ ]:
# Redéfinir les types
df["Surv"]=pd.Categorical(df["Surv"],ordered=False)
df["Classe"]=pd.Categorical(df["Classe"],ordered=False)
df["Genre"]=pd.Categorical(df["Genre"],ordered=False)
df["Port"]=pd.Categorical(df["Port"],ordered=False)
df.dtypes
In [ ]:
df.count()
In [ ]:
# imputation des valeurs manquantes
df["Age"]=df["Age"].fillna(df["Age"].median())
df.Port=df["Port"].fillna("S")
In [ ]:
# Discrétiser les variables quantitatives
df["AgeQ"]=pd.qcut(df.Age,3,labels=["Ag1","Ag2","Ag3"])
df["PrixQ"]=pd.qcut(df.Prix,3,labels=["Pr1","Pr2","Pr3"])
# redéfinir les noms des modalités
df["Surv"]=df["Surv"].cat.rename_categories(["Vnon","Voui"])
df["Classe"]=df["Classe"].cat.rename_categories(["Cl1","Cl2","Cl3"])
df["Genre"]=df["Genre"].cat.rename_categories(["Gfem","Gmas"])
df["Port"]=df["Port"].cat.rename_categories(["Pc","Pq","Ps"])
df.head()
Les données "Titanic" regroupent des variables qualitatives et quantitatives. Après recodage en classes (discrétisation) des variables quantitatives, la table obtenue se prête à une analyse factorielle multiple des correspondances.
In [ ]:
# Suppression des variables quantitatives
# pour l'AFCM
df_q=df.drop(["Age","Prix"],axis=1)
df_q.head()
# Indicatrices
dc=pd.DataFrame(pd.get_dummies(df_q[["Surv","Classe","Genre","Port","AgeQ","PrixQ"]]))
dc.head()
Calcul de l'AFCM et représentations graphiques.
In [ ]:
mca_df=MCA(dc,benzecri=False)
# Valeurs singulières
print(mca_df.L)
In [ ]:
# Composantes principales des colonnes (modalités)
print(mca_df.fs_c())
In [ ]:
# Premier plan principal
col=[1,1,2,2,2,3,3,5,5,5,6,6,6,7,7,7]
plt.scatter(mca_df.fs_c()[:, 0],mca_df.fs_c()[:, 1],c=col)
for i, j, nom in zip(mca_df.fs_c()[:, 0],mca_df.fs_c()[:, 1], dc.columns):
plt.text(i, j, nom)
plt.show()
Comme pour l'ACP et au contraire de R (cf. FactoMineR
), les librairies Python sont pauvres en fonctions graphiques directement adaptées à l'AFCM. Le graphique est construit à partir des fonctions de MatPlotLib
. Remarquer l'évidente redondance entre la variable Prix
et celle Classe
.
Q Tenter une interprétation des correspondances entre les modalités. Il serait opportun d'en déclarer une supplémentaire; cela semble possible dans la fonction MCA
mais n'est pas documenté.