
Cet article a été rédigé par Sarah Khatry et Haniyeh Mahmoudian, data scientists chez DataRobot.
La question des biais dans les modèles d'apprentissage automatique a fait l'objet d'une forte attention ces dernières années. Les défaillances de modèles font la une, et juristes spécialisés en droits humains, responsables politiques et journalistes participent désormais au débat sur l'éthique et les valeurs que nous voulons voir reflétées dans les modèles que nous concevons.
Si le biais humain est une notion complexe et difficile à définir, le biais en apprentissage automatique est, au bout du compte, mathématique. Il existe de nombreux tests pour identifier différents types de biais dans les prédictions d'un modèle. Le choix du test dépend surtout de ce qui vous importe et du contexte d'usage du modèle.
Parmi les tests les plus universels figure la parité statistique, que ce tutoriel pratique va détailler. Le biais s'évalue toujours par rapport à des groupes de personnes distingués par un attribut protégé présent dans vos données, par exemple la race, le genre, l'âge, l'orientation sexuelle, la nationalité, etc.
Avec la parité statistique, l'objectif est de mesurer si les différents groupes ont la même probabilité d'obtenir une issue favorable. Un exemple classique est un modèle de recrutement, pour lequel vous souhaitez garantir que les candidats et les candidates aient une probabilité équivalente d'être embauchés. Dans un modèle biaisé, on observe plutôt qu'un groupe est privilégié avec une probabilité plus élevée d'embauche, tandis que l'autre est défavorisé.
Pour illustrer cela en pratique, nous allons d'abord générer des données synthétiques avec un biais prédéfini, puis vérifier par l'analyse que les données correspondent bien au scénario souhaité, avant d'appliquer le test de parité statistique.
Générer des données synthétiques
Dans ce tutoriel, nous utiliserons le package pandas en Python, mais chaque étape peut également être reproduite en R.
import pandas as pd
Pour générer des données synthétiques comportant un attribut protégé et des prédictions de modèle, nous devons d'abord préciser quelques paramètres : le nombre total d'enregistrements, l'attribut protégé (ici deux valeurs génériques, A et B), et la prédiction du modèle associée à l'issue favorable, soit la valeur 1 dans cet exemple.
num_row = 1000 # number of rows in the data
prot_att = 'prot_att' # column name for protected attribute
model_pred_bin = 'prediction' # column name for predictions
pos_label = 1 # prediction value associated to positive/favorable outcome
prot_group = ['A','B'] # two groups in our protected attribute
Comme dans la réalité, les groupes A et B peuvent ne pas être répartis uniformément dans nos données. Dans le code ci-dessous, nous décidons que 60 % de la population appartient au groupe B, privilégié, qui a 30 % de chances d'obtenir l'issue favorable. Le groupe A, défavorisé, représente les 40 % restants et n'a que 15 % de probabilité d'obtenir l'issue favorable.
priv_g = 'B' # privileged group
priv_g_rate = 60 # 60% of the population is from group B
priv_p_rate = 30 # 30% of the predictions for group B was for favorable outcome 1
unpriv_p_rate = 15 # 15% of the predictions for group A was for favorable outcome 1
biased_list_priv = [prot_group[0]] * (100 - priv_g_rate) + [prot_group[1]] * priv_g_rate
biased_list_pos_priv = [0] * (100 - priv_p_rate) + [1] * priv_p_rate
biased_list_pos_unpriv = [0] * (100 - unpriv_p_rate) + [1] * unpriv_p_rate
Pour chaque enregistrement, nous attribuons aléatoirement un groupe protégé et une prédiction, en utilisant comme poids le biais spécifié, puis nous créons un dataframe à partir de la liste d'enregistrements.
list_df = [] # empty list to store the synthetic records
for i in range(0, num_row):
# generating random value representing protected groups with bias towards B
prot_rand = random.choices(biased_list_priv)[0]
if prot_rand == priv_g:
prot_g = priv_g
# generating random binary value representing prediction with bias towards 0
pred = random.choices(biased_list_pos_priv)[0]
# adding the new record to the list
list_df.append([prot_g,pred])
else:
prot_g = prot_group[0]
pred = random.choices(biased_list_pos_unpriv)[0]
list_df.append([prot_g,pred])
# create a dataframe from the list
df = pd.DataFrame(list_df,columns=['prot_att','prediction'])
Interpréter les données
Maintenant que nous avons nos données synthétiques, analysons ce que nous avons construit. Pour chaque groupe, A versus B, quelle est la probabilité d'obtenir l'issue favorable ou défavorable ?
df_group = (df.groupby([prot_att])[model_pred_bin].value_counts() / df.groupby([prot_att])[
model_pred_bin].count()).reset_index(name='probability')
print(df_group)
prot_att prediction probability
0 A 0 0.849490
1 A 1 0.150510
2 B 0 0.713816
3 B 1 0.286184
À l'examen du tableau, on voit clairement que le groupe B a une probabilité presque doublée d'obtenir l'issue favorable, avec 28,6 %. Nos données synthétiques ont été conçues pour une probabilité de 30 %, nous sommes donc proches de l'objectif. Nous enregistrons ensuite ces probabilités dans un dictionnaire.
Comme la génération est aléatoire, votre code pourra donner un résultat légèrement différent.
prot_att_dic = {}
for att in prot_group:
temp = df_group[(df_group[prot_att] == att) & (df_group[model_pred_bin] == pos_label)]
prob = float(temp['probability'])
prot_att_dic[att] = prob
Le test de parité statistique
Pour chaque groupe, la parité statistique renvoie le ratio entre sa probabilité d'obtenir l'issue favorable et celle du groupe privilégié. Nous itérons sur le dictionnaire des groupes protégés et de leur probabilité d'issue favorable pour construire ces ratios.
prot_test_res = {}
for k in prot_att_dic.keys():
res = float(prot_att_dic[k] / prot_att_dic[priv_g])
prot_test_res[k] = res
for key in prot_test_res.keys():
value = prot_test_res[key]
print(key, ' : ', value)
A : 0.5259207131128314
B : 1.0
Pour le groupe privilégié B, le score de parité statistique est de 1, comme attendu. Pour l'autre groupe, A, le score est de 0,526, ce qui indique qu'il a environ deux fois moins de chances d'obtenir l'issue favorable que le groupe B.
Le test de biais statistique offre une évaluation simple des écarts potentiels entre les résultats prédits pour certains groupes de vos données. Mesurer le biais poursuit deux objectifs. D'une part, ce test produit un indicateur transparent, plus facile à communiquer de manière concrète. D'autre part, l'idéal est de faire de l'identification des biais la première étape de leur atténuation dans votre modèle. C'est un champ de recherche actif en apprentissage automatique, avec de nombreuses techniques développées pour traiter différents types de biais et d'approches de modélisation.
Avec la bonne combinaison de tests et de techniques d'atténuation, vous pouvez améliorer votre modèle de manière itérative, réduire les biais et préserver la précision. Vous pouvez concevoir des systèmes d'apprentissage automatique qui n'apprennent pas seulement des résultats passés, mais reflètent aussi vos valeurs dans les décisions futures.
Découvrez comment concevoir une IA de confiance avec DataRobot.