Caractéristiques des variables : La cardinalité

Les valeurs d’une variable catégorielle sont sélectionnées à partir d’un groupe de catégories, également appelées labels. Par exemple, dans la variable sexe, les catégories ou labels sont masculins et féminins, alors que dans la variable Ville, les labels peuvent être Montpellier, Le Lude, Grenoble, etc.

Les différentes variables catégorielles contiennent un nombre différent d’étiquettes ou de catégories. La variable “Sexe” ne contient que deux étiquettes, mais une variable comme “ville” ou “code postal” peut contenir un très grand nombre d’étiquettes différentes.

Le nombre d’étiquettes différentes dans une variable catégorielle est connu sous le nom de cardinalité. Un nombre élevé d’étiquettes dans une variable est connu sous le nom de cardinalité élevée.

La présence de plusieurs étiquettes dans une variable catégorielle pose-t-elle un problème ?

Une cardinalité élevée peut poser les problèmes suivants :

  • Les variables ayant trop d’étiquettes ont tendance à dominer celles qui n’en ont que quelques unes, en particulier dans les algorithmes basés sur l’arbre.

  • Un grand nombre d’étiquettes dans une variable peut introduire du bruit avec peu ou pas d’information, ce qui rend les modèles d’apprentissage machine enclins à se surajuster.

  • Certaines étiquettes peuvent n’être présentes que dans l’ensemble des données de formation, mais pas dans l’ensemble de test, ce qui fait que les algorithmes d’apprentissage automatique peuvent être trop adaptés à l’ensemble de formation.

  • Au contraire, certaines étiquettes peuvent n’apparaître que dans l’ensemble de test, laissant ainsi les algorithmes d’apprentissage automatique incapables d’effectuer un calcul sur la nouvelle observation (invisible).

En particulier, les méthodes arborescentes peuvent être biaisées vers des variables avec beaucoup d’étiquettes (variables à haute cardinalité). Ainsi, leurs performances peuvent être affectées par une cardinalité élevée.

Je montrerai ci-dessous l’effet de la haute cardinalité des variables sur les performances de différents algorithmes d’apprentissage machine, et comment une solution rapide pour réduire le nombre d’étiquettes, sans aucune sorte d’aperçu des données, contribue déjà à améliorer les performances.

 

Dans cette démo :

Nous ferons :

  • Apprendre à quantifier la cardinalité
  • Voir des exemples de variables à cardinalité élevée et faible
  • Comprendre l’effet de la cardinalité lors de la préparation des trains et des jeux d’essai
  • Visualiser l’effet de la cardinalité sur les performances du modèle d’apprentissage machine
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

# to build machine learning models
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier

# to evaluate the models
from sklearn.metrics import roc_auc_score

# to separate data into train and test
from sklearn.model_selection import train_test_split

data = pd.read_csv('../exportfeature.csv',parse_dates=['date'],infer_datetime_format=True,dayfirst=True,sep=";",encoding='ANSI')

data.head()
id	place	rapport	date	M1	M2	M3	M4	allocation	Hippodrome	nbPartants	idHippodrome	nDistance	nAllocation	idFerrure	idJockey	nbPartants.1	rPoids	idOeillere	iCote
0	56005	1	1.3	2016-01-01	3a	3m	Da	3a	90000.0	Vincennes	17	Vincennes	2100	95000	0	18	17	0	0	12.0
1	98833	1	2.2	2016-01-01	3a	9Da	5a	4a	70000.0	Vincennes	18	Vincennes	2700	58000	1	30	18	0	0	12.0
2	98834	0	0.0	2016-01-01	1a	Da	Da	1a	44000.0	Vincennes	12	Vincennes	2850	37000	0	53	10	0	0	9.0
3	98835	1	1.5	2016-01-01	Da	7a	4a	2a	40000.0	Vincennes	11	Vincennes	2200	38000	2	143	13	0	0	4.0
4	98836	0	0.0	2016-01-01	1a	7a	10a	11a	40000.0	Vincennes	16	Vincennes	2700	34000	0	50	17	0	0	8.0

Les variables catégorielles de cet ensemble de données sont hippodrome, idHippodrome, idJockey,idFerrure, idOeillere

Notez que M1 à M4 contiennent à la fois des lettres et des chiffres, ils peuvent donc être traités comme des variables mixtes. Pour cette démonstration, je les traiterai comme des variables catégorielles.

# inspectons la cardinalité, voici le nombre
# Nombre d'étiquettes différentes, pour les différentes variables catégorielles

print('Nombre de catégorie de la variable Hippodrome: {}'.format(
    len(data.Hippodrome.unique())))

print('Nombre de catégorie de la variable  idHippodrome: {}'.format(
    len(data.idHippodrome.unique())))

print('Nombre de catégorie de la variable  idJockey: {}'.format(
    len(data.idHippodrome.unique())))

print('Nombre de catégorie de la variable  idFerrure: {}'.format(
    len(data.idFerrure.unique())))

print('Nombre de catégorie de la variable  idOeillere: {}'.format(
    len(data.idOeillere.unique())))
print('Nombre de catégorie de la variable  M1: {}'.format(
    len(data.M1.unique())))

print('Nombre de catégorie de la variable  M2: {}'.format(
    len(data.M2.unique())))

print('Nombre de catégorie de la variable  M3: {}'.format(
    len(data.M3.unique())))

print('Nombre de catégorie de la variable  M4: {}'.format(
    len(data.M4.unique())))


print('Taille de notre dataframe: {}'.format(len(data)))
Nombre de catégorie de la variable Hippodrome: 199
Nombre de catégorie de la variable  idHippodrome: 303
Nombre de catégorie de la variable  idJockey: 303
Nombre de catégorie de la variable  idFerrure: 4
Nombre de catégorie de la variable  idOeillere: 1
Nombre de catégorie de la variable  M1: 67
Nombre de catégorie de la variable  M2: 71
Nombre de catégorie de la variable  M3: 72
Nombre de catégorie de la variable  M4: 70
Taille d enotre dataframe: 20504

Alors que la variable idFerreur ne contient que 4 catégories, toutes les variables, comme prévu, contiennent un grand nombre d’étiquettes différentes (haute cardinalité). On peut remarquer aussi que la variable idOeillere ne comporte qu’une seule cardinalité. Cela indique qu’il y a tjs la même valeur dans la colonne. On pourra donc à l’avenir la supprimer

Pour démontrer l’effet de la haute cardinalité sur les performances de l’entrainement, des tests , je vais travailler avec la variable M1. Je vais créer une nouvelle variable avec une cardinalité réduite.

# explorons les valeurs / catégories de M1

# nous savons, grâce à la cellule précédente, qu'il y  a 67 valeurs
# différentes , donc la variable
# est hautement cardinal

data.M1.unique()
array(['3a', '1a', 'Da', '8a', '2a', '9a', '4a', '5a', '10a', 'Aa', 'Dm',
       '13a', '7a', '6m', '11a', '6a', '2Da', '0a', '1Disqa', '10m', '3m',
       '3Da', '14a', '5m', '4Dista', '1m', '1Dista', '2Dm', '4Da', '15a',
       '1Da', '10Dista', '3Dista', '5Da', '4m', '6Da', '12a', '0m', '2m',
       '7Da', '8m', '2Dista', 'Rpa', '9m', '7m', '4Disqa', 'Dista',
       '7Dista', '4Distm', '2Dpga', '6Dista', '5Dista', '1Dpga', '1Dm',
       'Am', 'Ta', '16a', '17a', '8Dista', '2Disqa', 'Dpga', '12m', '3Dm',
       '11m', '3Dpga', '9Da', '8Dm'], dtype=object)

Réduisons maintenant la cardinalité de la variable. Comment ? Au lieu d’utiliser toute la valeur de la cabine, je vais supprimer la dernière lettre

Justification : la dernière lettre indique la spécialité de la dernière course. Le reste indique la position à l’arrivé

data['M1_reduite'] = data['M1'].astype(str).str[0:-1]

data[['M1', 'M1_reduite']].head()
	M1	M1_reduite
0	3a	3
1	3a	3
2	1a	1
3	Da	D
4	1a	1
print('Nombre de catégorie de la variable  M1: {}'.format(
    len(data.M1.unique())))

print('Nombre de catégorie de la variable  M1 réduite: {}'.format(
    len(data.M1_reduite.unique())))
Nombre de catégorie de la variable  M1: 67
Nombre de catégorie de la variable  M1 réduite: 48

Nous avons réduit les différents label de 67 à 48. C’est pas mal mais on peut encore mieux faire. On peut changer les catégories des chevaux disqualifié ou pour le moins tout ceux qui ne sont pas dans le classement de l’arrivée.

def uniquement_place(M1_reduite):
    position=M1_reduite
    if len(position)>2:
        position="NP"
        
    return position

data['M1_reduite']=data['M1_reduite'].apply(uniquement_place)

pd.set_option('display.max_rows', None)
data[['M1', 'M1_reduite']].head(150)
M1	M1_reduite
0	3a	3
1	3a	3
2	1a	1
3	Da	D
4	1a	1
5	8a	8
6	2a	2
7	9a	9
8	1a	1
9	4a	4
10	Da	D
11	5a	5
12	9a	9
13	2a	2
14	1a	1
15	1a	1
16	4a	4
17	1a	1
18	Da	D
19	Da	D
20	1a	1
21	10a	10
22	2a	2
23	1a	1
24	2a	2
25	Da	D
26	2a	2
27	1a	1
28	3a	3
29	1a	1
30	2a	2
31	Da	D
32	Aa	A
33	1a	1
34	Da	D
35	5a	5
36	3a	3
37	1a	1
38	1a	1
39	2a	2
40	2a	2
41	1a	1
42	Da	D
43	Dm	D
44	8a	8
45	Da	D
46	5a	5
47	1a	1
48	1a	1
49	1a	1
50	2a	2
51	1a	1
52	Da	D
53	13a	13
54	2a	2
55	4a	4
56	1a	1
57	3a	3
58	7a	7
59	2a	2
60	6m	6
61	4a	4
62	1a	1
63	1a	1
64	11a	11
65	1a	1
66	1a	1
67	6a	6
68	3a	3
69	1a	1
70	3a	3
71	2Da	2D
72	2a	2
73	3a	3
74	Da	D
75	2a	2
76	1a	1
77	1a	1
78	1a	1
79	3a	3
80	0a	0
81	4a	4
82	Da	D
83	Da	D
84	1a	1
85	Da	D
86	1a	1
87	6a	6
88	1a	1
89	Da	D
90	2a	2
91	1Disqa	NP
92	3a	3
93	1a	1
94	1a	1
95	1a	1
96	1a	1
97	2a	2
98	10a	10
99	1a	1
100	1a	1
101	4a	4
102	7a	7
103	4a	4
104	Da	D
105	1a	1
106	1a	1
107	1a	1
108	3a	3
109	2a	2
110	3a	3
111	2a	2
112	1a	1
113	Da	D
114	1a	1
115	10a	10
116	1a	1
117	5a	5
118	5a	5
119	2a	2
120	1a	1
121	2a	2
122	1a	1
123	1a	1
124	3a	3
125	1a	1
126	1a	1
127	2a	2
128	2a	2
129	9a	9
130	0a	0
131	1a	1
132	1a	1
133	1a	1
134	2a	2
135	1a	1
136	2a	2
137	2a	2
138	5a	5
139	1a	1
140	2a	2
141	1a	1
142	1a	1
143	3a	3
144	3a	3
145	1a	1
146	1a	1
147	8a	8
148	10m	10
149	Da	D
print('Nombre de catégorie de la variable  M1 réduite: {}'.format(
    len(data.M1_reduite.unique())))
Nombre de catégorie de la variable  M1 réduite: 32
# Séparons-nous en un ensemble de formation et de tests
# afin de construire des modèles d'apprentissage machine

use_cols = ['M1', 'M1_reduite', 'nbPartants']

# this functions comes from scikit-learn
X_train, X_test, y_train, y_test = train_test_split(
    data[use_cols], 
    data['place'],  
    test_size=0.3,
    random_state=0)

X_train.shape, X_test.shape
((14352, 3), (6152, 3))

Une cardinalité élevée entraîne une répartition inégale des catégories dans les ensembles d’entrainement et de test

Lorsqu’une variable est très cardinale, il arrive souvent que certaines catégories ne soient présentes que sur le jeu d’entraînement, ou seulement sur le jeu de test. Si elles ne sont présentes que dans l’ensemble de formation, elles peuvent conduire à un surajustement. Si elles ne sont présentes que sur le banc d’essai, l’algorithme d’apprentissage automatique ne saura pas comment les traiter, car il ne les a pas vues pendant la formation.

# Découvrons les étiquettes présentes uniquement dans l'ensemble d'entrainement

unique_to_train_set = [
    x for x in X_train.M1.unique() if x not in X_test.M1.unique()
]

len(unique_to_train_set)

Il y a 14 categories de M1 présente dans l’ensemble d’entrainement et pas dans celui de test

# Découvrons les étiquettes présentes uniquement dans l'ensemble de test

unique_to_test_set = [
    x for x in X_test.M1.unique() if x not in X_train.M1.unique()
]

len(unique_to_test_set)
4

Les variables à forte cardinalité ont tendance à avoir des valeurs (c’est-à-dire des catégories) présentes dans l’ensemble de formation, qui ne sont pas présentes dans l’ensemble de test, et vice versa. Cela entraîne des problèmes au moment de la formation (en raison d’un surajustement) et de la notation des nouvelles données (comment le modèle doit-il traiter les catégories non vues ?).

Ce problème est presque surmonté par la réduction de la cardinalité de la variable. Voir ci-dessous.

# Découvrons les étiquettes présentes uniquement dans l'ensemble de formation
# pour M1 à cardinalité réduite

unique_to_train_set = [
    x for x in X_train['M1_reduite'].unique()
    if x not in X_test['M1_reduite'].unique()
]

len(unique_to_train_set)

-> 2
# Découvrons les étiquettes présentes uniquement dans l'ensemble de test
# pour M1 à cardinalité réduite

unique_to_test_set = [
    x for x in X_test['M1_reduite'].unique()
    if x not in X_train['M1_reduite'].unique()
]

len(unique_to_test_set)

-> 2

Observez comment, en réduisant la cardinalité, il n’y a plus que deux étiquettes dans l’ensemble d’entrainement qui ne sont pas présente dans l’ensemble de test.

Effet de la cardinalité sur les performances du modèle d’apprentissage machine

Afin d’évaluer l’effet des variables catégorielles dans les modèles d’apprentissage machine, je vais rapidement remplacer les catégories par des nombres. Voir ci-dessous.

# Réorganisons M1 en chiffres afin de pouvoir l'utiliser pour former les modèles ML

# Je remplacerai chaque M1 par un numéro
# pour démontrer rapidement l'effet de
# étiquettes sur les algorithmes d'apprentissage machine

##############
# Note : ce n'est ni le seul ni le meilleur
# comment encoder les variables catégorielles en chiffres
# nous verrons plus loin d'autres techniques
##############

M1_dict = {k: i for i, k in enumerate(X_train.M1.unique(), 0)}
M1_dict
{'5a': 0,
 '1a': 1,
 '7a': 2,
 '2a': 3,
 '6a': 4,
 '4a': 5,
 '10a': 6,
 '3a': 7,
 '0a': 8,
 'Da': 9,
 'Dm': 10,
 '8a': 11,
 '9m': 12,
 '9a': 13,
 '12a': 14,
 '3Dista': 15,
 '3Da': 16,
 '11a': 17,
 '2Da': 18,
 '1m': 19,
 '4Da': 20,
 '3m': 21,
 '11m': 22,
 'Aa': 23,
 '6Dista': 24,
 '1Dista': 25,
 '14a': 26,
 '5m': 27,
 '13a': 28,
 '17a': 29,
 '15a': 30,
 '1Da': 31,
 '6m': 32,
 '4m': 33,
 '2m': 34,
 '0m': 35,
 '2Dpga': 36,
 '5Da': 37,
 '2Dista': 38,
 '8Dista': 39,
 '12m': 40,
 '2Dm': 41,
 '7m': 42,
 'Am': 43,
 '5Dista': 44,
 'Dista': 45,
 '10m': 46,
 '2Disqa': 47,
 '6Da': 48,
 '7Dista': 49,
 '1Dm': 50,
 '1Disqa': 51,
 '3Dpga': 52,
 '4Dista': 53,
 'Ta': 54,
 '3Dm': 55,
 '4Distm': 56,
 '10Dista': 57,
 '8m': 58,
 '1Dpga': 59,
 '7Da': 60,
 '16a': 61,
 'Rpa': 62}
# remplacer les étiquettes, en utilisant le dic créé ci-dessus
X_train.loc[:, 'M1_mapped'] = X_train.loc[:, 'M1'].map(M1_dict)
X_test.loc[:, 'M1_mapped'] = X_test.loc[:, 'M1'].map(M1_dict)

X_train[['M1_mapped', 'M1']].head(10)
	M1_mapped	M1
2540	0	5a
19008	1	1a
7624	2	7a
2575	3	2a
852	4	6a
4855	1	1a
8154	1	1a
18928	1	1a
18286	4	6a
15712	5	4a
# Maintenant, je vais remplacer les lettres dans la variable réduite de M1
# avec la même procédure

# créer un dictionnaire de remplacement
M1_dict = {k: i for i, k in enumerate(X_train['M1_reduite'].unique(), 0)}

# On remplace les étiquettes par le dict
X_train.loc[:, 'M1_reduite'] = X_train.loc[:, 'M1_reduite'].map(
    M1_dict)
X_test.loc[:, 'M1_reduite'] = X_test.loc[:, 'M1_reduite'].map(M1_dict)

X_train[['M1_reduite', 'M1']].head(20)
	M1_reduite	M1
2540	0	5a
19008	1	1a
7624	2	7a
2575	3	2a
852	4	6a
4855	1	1a
8154	1	1a
18928	1	1a
18286	4	6a
15712	5	4a
4842	6	10a
18034	3	2a
1215	1	1a
14732	1	1a
17160	1	1a
6969	3	2a
8964	1	1a
4446	1	1a
3669	3	2a
7129	1	1a
# vérifier s'il y a des valeurs manquantes dans ces variables

X_train[['M1_mapped', 'M1_reduite', 'nbPartants']].isnull().sum()
M1_mapped     4
M1_reduite    2
nbPartants    0
dtype: int64

Dans l’ensemble de test, il y a maintenant 4 valeurs manquantes pour la variable hautement cardinale. Ces valeurs ont été introduites lors de l’encodage des catégories en chiffres.

Comment ?

De nombreuses catégories n’existent que dans la série de tests. Ainsi, lorsque nous avons créé notre dictionnaire d’encodage en utilisant uniquement la série de trains, nous n’avons pas généré de nombre pour remplacer les étiquettes présentes uniquement dans la série de tests. Par conséquent, elles ont été encodées en tant que NaN. Nous verrons dans les prochains cahiers comment résoudre ce problème. Pour l’instant, je vais remplir ces valeurs manquantes avec 0.

# vérifions le nombre de catégories différentes dans les variables codées
len(X_train.M1_mapped.unique()), len(X_train.M1_reduite.unique())
(63, 30)

De ce qui précède, nous constatons immédiatement que sur les 67 cabines originales de l’ensemble de données, seules 63 sont présentes dans l’ensemble de formation.

Allons de l’avant et évaluons l’effet des étiquettes dans les algorithmes d’apprentissage machine.

 

Random Forests

# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
rf = RandomForestClassifier(n_estimators=200, random_state=39)

# Entrainement du modèle
rf.fit(X_train[['M1_mapped', 'nbPartants']], y_train)

# création des prédictions
pred_train = rf.predict_proba(X_train[['M1_mapped', 'nbPartants']])
pred_test = rf.predict_proba(X_test[['M1_mapped', 'nbPartants']].fillna(0))

print('Entrainement')
print('Random Forests roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Random Forests roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Random Forests roc-auc: 0.6126443489995196
Test
Random Forests roc-auc: 0.5703193792960399

Nous observons que les performances des Random Forests sur le banc d’entraînement sont tout à fait supérieures à celles du banc d’essai. Cela indique que le modèle est sur entrainé, ce qui signifie qu’il fait un excellent travail de prédiction du résultat sur l’ensemble de données sur lequel il a été formé, mais qu’il n’a pas la puissance nécessaire pour généraliser la prédiction sur de nouvelles données.

# modèle construit sur des données à faible cardinalité pour M1

# appeler le modèle
rf = RandomForestClassifier(n_estimators=200, random_state=39)

# Entrainement du modèle
rf.fit(X_train[['M1_reduite', 'nbPartants']], y_train)

# création des prédictions
pred_train = rf.predict_proba(X_train[['M1_reduite', 'nbPartants']])
pred_test = rf.predict_proba(X_test[['M1_reduite', 'nbPartants']].fillna(0))


print('Entrainement')
print('Random Forests roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Random Forests roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Random Forests roc-auc: 0.6049508585145702
Test
Random Forests roc-auc: 0.5693662589533326

Nous pouvons maintenant constater que les Random Forests ne sont plus trop adaptées à l’entraînement. En outre, le modèle est bien meilleur pour généraliser les prédictions (comparer le roc-auc de ce modèle sur l’ensemble de test et le roc-auc du modèle ci-dessus également sur l’ensemble de test : 0,57 contre 0,61).

Je voudrais souligner que nous pouvons probablement surmonter l’effet de la cardinalité élevée en ajustant les hyperparamètres des forêts aléatoires. Cela dépasse le cadre de ce cours. Ici, je veux vous montrer qu’avec un même modèle, avec des hyperparamètres identiques, une cardinalité élevée peut entraîner un surajustement du modèle.

 

AdaBoost

# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
ada = AdaBoostClassifier(n_estimators=200, random_state=44)

# Entrainement du modèle
ada.fit(X_train[['M1_mapped', 'nbPartants']], y_train)

# création des prédictions
pred_train = ada.predict_proba(X_train[['M1_mapped', 'nbPartants']])
pred_test = ada.predict_proba(X_test[['M1_mapped', 'nbPartants']].fillna(0))

print('Entrainement')
print('AdaBoost roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('AdaBoost roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
AdaBoost roc-auc: 0.5895832815827019
Test
AdaBoost roc-auc: 0.5842923634665107
# modèle construit sur des données à haute cardinalité pour M1 réduite

# appeler le modèle
ada = AdaBoostClassifier(n_estimators=200, random_state=44)

# Entrainement du modèle
ada.fit(X_train[['M1_reduite', 'nbPartants']], y_train)

# création des prédictions
pred_train = ada.predict_proba(X_train[['M1_reduite', 'nbPartants']])
pred_test = ada.predict_proba(X_test[['M1_reduite', 'nbPartants']].fillna(0))

print('Entrainement')
print('AdaBoost roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('AdaBoost roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
AdaBoost roc-auc: 0.5870471218982631
Test
AdaBoost roc-auc: 0.5819099091989577

Entre les deux modèles on ne voit pas de différences flagrantes

 

Logistic Regression

# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
logit = LogisticRegression(random_state=44, solver='lbfgs')

# Entrainement du modèle
logit.fit(X_train[['M1_mapped', 'nbPartants']], y_train)

# création des prédictions
pred_train = logit.predict_proba(X_train[['M1_mapped', 'nbPartants']])
pred_test = logit.predict_proba(X_test[['M1_mapped', 'nbPartants']].fillna(0))

print('Entrainement')
print('Logistic Regression roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Logistic Regression roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Logistic Regression roc-auc: 0.5743783714148762
Test
Logistic Regression roc-auc: 0.5680422348285903
# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
logit = LogisticRegression(random_state=44, solver='lbfgs')

# Entrainement du modèle
logit.fit(X_train[['M1_reduite', 'nbPartants']], y_train)

# création des prédictions
pred_train = logit.predict_proba(X_train[['M1_reduite', 'nbPartants']])
pred_test = logit.predict_proba(X_test[['M1_reduite', 'nbPartants']].fillna(0))

print('Entrainement')
print('Logistic Regression roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Logistic Regression roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Logistic Regression roc-auc: 0.5755345915325598
Test
Logistic Regression roc-auc: 0.5716232479248637

On peut voir une légère amélioration sur le test

 

Gradient Boosted Classifier

 

# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
gbc = GradientBoostingClassifier(n_estimators=300, random_state=44)

# Entrainement du modèle
gbc.fit(X_train[['M1_mapped', 'nbPartants']], y_train)

# création des prédictions
pred_train = gbc.predict_proba(X_train[['M1_mapped', 'nbPartants']])
pred_test = gbc.predict_proba(X_test[['M1_mapped', 'nbPartants']].fillna(0))

print('Entrainement')
print('Gradient Boosted roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Gradient Boosted roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Gradient Boosted roc-auc: 0.6026729948840729
Test
Gradient Boosted roc-auc: 0.5809900080995234
# modèle construit sur des données à haute cardinalité pour M1

# appeler le modèle
gbc = GradientBoostingClassifier(n_estimators=300, random_state=44)

# Entrainement du modèle
gbc.fit(X_train[['M1_reduite', 'nbPartants']], y_train)

# création des prédictions
pred_train = gbc.predict_proba(X_train[['M1_reduite', 'nbPartants']])
pred_test = gbc.predict_proba(X_test[['M1_reduite', 'nbPartants']].fillna(0))

print('Entrainement')
print('Gradient Boosted roc-auc: {}'.format(roc_auc_score(y_train, pred_train[:,1])))
print('Test')
print('Gradient Boosted roc-auc: {}'.format(roc_auc_score(y_test, pred_test[:,1])))
Entrainement
Gradient Boosted roc-auc: 0.598521098859783
Test
Gradient Boosted roc-auc: 0.5764933062958197

Les arbres Gradient Boosted sont en effet trop adaptés à l’ensemble de formation dans les cas où la variable M1 a beaucoup d’étiquettes. C’était prévisible, car les méthodes d’arborescence ont tendance à être biaisées en faveur de variables comportant de nombreuses catégories.

D’une manière générale, vous vous rendrez compte que travailler sur des vrais données de turf, est toujours assez frustrant par rapport à des données plus usuelles. En effet, on a une part d’incertitude beaucoup plus importante que sur d’autres jeux de données.
Après c’est aussi ce qui fait l’interêt de travailler sur de tels jeux de données.

Si vous voulez découvrir comment fonctionne la librairie pandas ou bien l’environnement Jupyter, n’hésitez pas à consulter les cours ci-dessous.

GCH anime

Je télécharge mon guide gratuit

.

Vous recevrez votre guide par email sans aucun engagement de votre part.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.