Chargement des données¶

In [ ]:
#changement de dossier
import os
os.chdir("C:/Users/ricco/Desktop/demo")

#chargement des données
import pandas
D = pandas.read_excel("Tennis_Players_AFDM.xlsx",index_col=0)
D
Out[ ]:
Taille Lateralite MainsRevers Titres Finales TitresGC RolandGarros BestClassDouble
Joueur
Agassi 180 droitier deux 60 30 8 vainqueur 123
Becker 191 droitier une 49 28 6 demi 6
Borg 180 droitier deux 64 25 11 vainqueur 890
Connors 178 gaucher deux 109 52 8 demi 370
Courier 185 droitier deux 23 13 4 vainqueur 20
Edberg 187 droitier une 41 36 6 finale 1
Kafelnikov 190 droitier deux 26 20 2 vainqueur 4
Kuerten 190 droitier une 20 9 3 vainqueur 38
Lendl 187 droitier une 94 50 8 vainqueur 20
McEnroe 180 gaucher une 77 31 7 finale 1
Nastase 180 droitier une 58 38 2 vainqueur 59
Rafter 185 droitier une 11 14 2 demi 6
Safin 193 droitier deux 15 12 2 demi 71
Sampras 185 droitier une 64 24 14 demi 27
Vilas 180 gaucher une 62 40 4 vainqueur 175
Wilander 182 droitier deux 33 27 7 vainqueur 3
Djokovic 188 droitier deux 79 34 17 vainqueur 114
Federer 185 droitier une 103 54 20 vainqueur 24
Murray 191 droitier deux 46 22 3 finale 51
Nadal 185 gaucher deux 85 37 19 vainqueur 26
In [ ]:
#individus actifs et variables actives
DActifs = D.iloc[:16,:7]
DActifs
Out[ ]:
Taille Lateralite MainsRevers Titres Finales TitresGC RolandGarros
Joueur
Agassi 180 droitier deux 60 30 8 vainqueur
Becker 191 droitier une 49 28 6 demi
Borg 180 droitier deux 64 25 11 vainqueur
Connors 178 gaucher deux 109 52 8 demi
Courier 185 droitier deux 23 13 4 vainqueur
Edberg 187 droitier une 41 36 6 finale
Kafelnikov 190 droitier deux 26 20 2 vainqueur
Kuerten 190 droitier une 20 9 3 vainqueur
Lendl 187 droitier une 94 50 8 vainqueur
McEnroe 180 gaucher une 77 31 7 finale
Nastase 180 droitier une 58 38 2 vainqueur
Rafter 185 droitier une 11 14 2 demi
Safin 193 droitier deux 15 12 2 demi
Sampras 185 droitier une 64 24 14 demi
Vilas 180 gaucher une 62 40 4 vainqueur
Wilander 182 droitier deux 33 27 7 vainqueur

Préparation des données pour l'AFDM¶

Classe pour "scaling" des variables indicatrices (0/1)¶

In [ ]:
#numpy
import numpy as np

#classe standardscaler de sklearn
from sklearn.preprocessing import StandardScaler

#création d'une classe héritière
#de StandardScaler pour traiter les variables 0/1
# - pas de centrage
# - scaling avec la racine de la fréquence (or fréquence = moyenne pour 0/1)
class MyScaling(StandardScaler):

    #surcharger le constructeur
    def __init__(self, *, copy=True, with_mean=True, with_std=True):
        #appel de l'ancêtre avec modification : pas de centrage
        StandardScaler.__init__(self,copy=True,with_mean=False,with_std=True)

    #surcharger la méthode fit
    def fit(self, X, y=None, sample_weight=None):
        #appel de la méthode ancêtre
        super().fit(X,y,sample_weight)
        #moyenne (fréquence) sera utilisé pour le scale
        self.var_ = self.mean_
        #paramètre scale du coup
        self.scale_ = np.sqrt(self.var_)
        return self

Pipeline pour codage des indicatrices¶

In [ ]:
#imports
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline

#définir un pipeline pour le traitement des qualitatives
# - codage 0/1 d'abord
# - puis le scaling maison ensuite
prepa_quali = Pipeline([
    ('encodage',OneHotEncoder()),
    ('scaling',MyScaling())
])

Préparation différenciée selon le type des variables¶

In [ ]:
#imports
from sklearn.compose import ColumnTransformer, make_column_selector

#préparation complète - d'une part les quanti, de l'autre les quali
#cf. le rôle de ColumnTransformer
#https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html
prepa_full = ColumnTransformer([
    ('quanti',StandardScaler(),make_column_selector(dtype_exclude='object')),
    ('quali',prepa_quali,make_column_selector(dtype_include='object'))
])

ACP sur ces données transformées = AFDM¶

Entraînement de l'algorithme¶

In [ ]:
#imports
from sklearn.decomposition import PCA

#pipeline avec pretraitement + ACP sur variables pré-traitées
# = AFDM (analyse factorielle des données mixtes)
wkf = Pipeline([
    ('preparation',prepa_full),
    ('acp',PCA(n_components=2,svd_solver='full'))
])
In [ ]:
#entraînement
#bien regarder les constituants du Pipeline
wkf.fit(DActifs)
Out[ ]:
Pipeline(steps=[('preparation',
                 ColumnTransformer(transformers=[('quanti', StandardScaler(),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9D4B9550>),
                                                 ('quali',
                                                  Pipeline(steps=[('encodage',
                                                                   OneHotEncoder()),
                                                                  ('scaling',
                                                                   MyScaling(with_mean=False))]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9C0DF650>)])),
                ('acp', PCA(n_components=2, svd_solver='full'))])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Pipeline(steps=[('preparation',
                 ColumnTransformer(transformers=[('quanti', StandardScaler(),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9D4B9550>),
                                                 ('quali',
                                                  Pipeline(steps=[('encodage',
                                                                   OneHotEncoder()),
                                                                  ('scaling',
                                                                   MyScaling(with_mean=False))]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9C0DF650>)])),
                ('acp', PCA(n_components=2, svd_solver='full'))])
ColumnTransformer(transformers=[('quanti', StandardScaler(),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9D4B9550>),
                                ('quali',
                                 Pipeline(steps=[('encodage', OneHotEncoder()),
                                                 ('scaling',
                                                  MyScaling(with_mean=False))]),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9C0DF650>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9D4B9550>
StandardScaler()
<sklearn.compose._column_transformer.make_column_selector object at 0x0000029D9C0DF650>
OneHotEncoder()
MyScaling(with_mean=False)
PCA(n_components=2, svd_solver='full')

Coordonnées des individus dans l'espace factoriel¶

In [ ]:
#coordonnées des individus dans l'espace factoriel
dfFact = wkf.transform(DActifs)
dfFact = pandas.DataFrame(dfFact,index=DActifs.index,columns=['F1','F2'])
dfFact
Out[ ]:
F1 F2
Joueur
Agassi 0.554948 -1.729643
Becker -0.835330 1.241366
Borg 0.715837 -1.875173
Connors 3.520120 -0.681037
Courier -1.660146 -1.165409
Edberg 0.230097 2.088298
Kafelnikov -1.985064 -0.769907
Kuerten -2.269361 0.519756
Lendl 1.497483 -0.037865
McEnroe 2.504098 1.948994
Nastase 0.437266 -0.127113
Rafter -1.919760 1.128111
Safin -2.839067 0.287683
Sampras 0.604335 0.476228
Vilas 1.805785 0.197367
Wilander -0.361243 -1.501657
In [ ]:
#affichage dans le premier plan factoriel
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(7,7))
ax.axis([-3.5,+3.5,-3.5,+3.5])
ax.plot([-3.5,+3.5],[0,0],color='silver',linestyle='--')
ax.plot([0,0],[-3.5,+3.5],color='silver',linestyle='--')
ax.set_xlabel("Dim.1")
ax.set_ylabel("Dim.2")
plt.title("Carte des individus")
for x,y,lbl in zip(dfFact.iloc[:,0],dfFact.iloc[:,1],dfFact.index):
    ax.text(x,y,lbl,horizontalalignment='center',verticalalignment='center',fontsize=7)
 
plt.show()
No description has been provided for this image

Application du Pipeline sur un individu supplémentaire¶

In [ ]:
#le cas Féderer
dfFed = D.loc[['Federer']].iloc[:,:7]
dfFed
Out[ ]:
Taille Lateralite MainsRevers Titres Finales TitresGC RolandGarros
Joueur
Federer 185 droitier une 103 54 20 vainqueur
In [ ]:
#calcul de sa coordonnée factorielle
coord_Fed = wkf.transform(dfFed)
coord_Fed
Out[ ]:
array([[ 3.1306293 , -0.71729545]])
In [ ]:
coord_Fed[0][1]
Out[ ]:
-0.717295454130518
In [ ]:
#position
fig, ax = plt.subplots(figsize=(7,7))
ax.axis([-3.5,+3.5,-3.5,+3.5])
ax.plot([-3.5,+3.5],[0,0],color='silver',linestyle='--')
ax.plot([0,0],[-3.5,+3.5],color='silver',linestyle='--')
ax.set_xlabel("Dim.1")
ax.set_ylabel("Dim.2")
plt.title("Carte des individus")
for x,y,lbl in zip(dfFact.iloc[:,0],dfFact.iloc[:,1],dfFact.index):
    ax.text(x,y,lbl,horizontalalignment='center',verticalalignment='center',fontsize=7)

#position de Federer
ax.text(coord_Fed[0][0],coord_Fed[0][1],'Federer',horizontalalignment='center',verticalalignment='center',fontsize=7,fontweight='bold',c='red')
 
plt.show()
No description has been provided for this image

Sauvegarde du Pipeline dans un fichier binaire¶

In [ ]:
#sauvegarde dans un fichier binaire
#https://pypi.org/project/dill/
import dill

#créer le fichier en écriture binaire
f = open("workflow.sav","wb")

#sérialisation
dill.dump(wkf,f)

#ne pas oublier de fermer
f.close()

Chargement et déploiement avec le Pipeline¶

Chargement et inspection¶

In [ ]:
#chargement dans un nouvel objet
#utilisation de dill : https://pypi.org/project/dill/
import dill

#ouvrir le fichier en lecture binaire
f = open("workflow.sav","rb")

try:
    #chargement
    modele = dill.load(f)
finally:
    #fermeture quoiqu'il en soit
    f.close()

#affichage des étapes
modele.named_steps
Out[ ]:
{'preparation': ColumnTransformer(transformers=[('quanti', StandardScaler(),
                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029DA0A343D0>),
                                 ('quali',
                                  Pipeline(steps=[('encodage', OneHotEncoder()),
                                                  ('scaling',
                                                   MyScaling(with_mean=False))]),
                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000029DA0ABDB10>)]),
 'acp': PCA(n_components=2, svd_solver='full')}

Déploiement sur un individu supplémentaire¶

In [ ]:
#le cas Djokovic
dfDjoko = D.loc[['Djokovic']].iloc[:,:7]
dfDjoko
Out[ ]:
Taille Lateralite MainsRevers Titres Finales TitresGC RolandGarros
Joueur
Djokovic 188 droitier deux 79 34 17 vainqueur
In [ ]:
#coordonnées factorielles de Djoko
coord_Djoko = modele.transform(dfDjoko)
coord_Djoko
Out[ ]:
array([[ 1.16198817, -1.67811469]])
In [ ]:
#position
fig, ax = plt.subplots(figsize=(7,7))
ax.axis([-3.5,+3.5,-3.5,+3.5])
ax.plot([-3.5,+3.5],[0,0],color='silver',linestyle='--')
ax.plot([0,0],[-3.5,+3.5],color='silver',linestyle='--')
ax.set_xlabel("Dim.1")
ax.set_ylabel("Dim.2")
plt.title("Carte des individus")
for x,y,lbl in zip(dfFact.iloc[:,0],dfFact.iloc[:,1],dfFact.index):
    ax.text(x,y,lbl,horizontalalignment='center',verticalalignment='center',fontsize=7)

#position de Federer
ax.text(coord_Fed[0][0],coord_Fed[0][1],'Federer',horizontalalignment='center',verticalalignment='center',fontsize=7,fontweight='bold',c='red')
#et de Djokovic
ax.text(coord_Djoko[0][0],coord_Djoko[0][1],'Djokovic',horizontalalignment='center',verticalalignment='center',fontsize=7,fontweight='bold',c='blue')
 
plt.show()
No description has been provided for this image