0
2

More than 1 year has passed since last update.

公平な機械学習モデルの構築(Correlation Remover)

Posted at

はじめに

公平な機械学習モデルを構築する手法を検証します。
Jupyter Notebookは下記にあります。

概要

  • 公平性指標としてEqualized Oddsを使用します。
  • Correlation Removerを用いて、公平な機械学習モデルを構築します。

公平性指標

Equalized Odds

今回考える公平性指標は、性別や人種などの各グループが公平に扱われているか(group fairness)を評価するために用いられます。
Equalized Oddsは、positiveとnegativeの2クラス分類において、positiveと判定される確率に着目した指標です。
具体的には、正しくpositiveと判定される確率(true positive rate)と、誤ってpositiveと判定される確率(false positive rate)がグループによらず等しいかを評価します。

数式で書くと、性別や人種などの属性の集合を$A$、モデルが予測するクラスの集合を$Y={0,1}$、属性が$a \in A$かつ正解クラスが$y \in Y$のデータが、クラス$\hat{Y} =1$と予測される確率を$P(\hat{Y}=1|A=a, Y=y)$とすると、任意の$y, a, a'$で下記が成り立つ場合、モデルはEqualized Oddsを満たします。

$$
P(\hat{Y}=1|A=a, Y=y) = P(\hat{Y}=1|A=a', Y=y)
$$

Correlation Remover

この手法では、モデルの学習に用いるデータから、公平性で考慮する属性との相関を取り除きます。
元のデータを${x_1, ... , x_n}$、それぞれのデータの公平性で考慮する属性を${s_1, ..., s_n}$、属性の平均を$\bar{s}$とし、相関を取り除いたデータ${z_1, ...,z_n}$を最適化します。

具体的には、$z$と$s$との相関が0となる下記条件のもとで
$$
\frac{1}{n} \sum_{i=1}^n z_i (s_i - \bar{s})^T = 0
$$
$z_i$と$x_i$の距離(L2ノルム)を最小化します。
$$
\min_{z_1, ..., z_n} \sum_{i=1}^n ||z_i - x_i||^2
$$

実装

1. ライブラリのインポート

必要なライブラリをインポートします。

import sys
import os
from tqdm import tqdm
import matplotlib.pyplot as plt

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score

import lightgbm as lgb

!pip install fairlearn
from fairlearn.datasets import fetch_adult
from fairlearn.preprocessing import CorrelationRemover
from fairlearn.metrics import equalized_odds_difference, MetricFrame, true_positive_rate, false_positive_rate, count

2. データセットの用意

今回はAdult Data Setを使用します。
年齢や教育歴などの14の属性から、収入が5万ドルを超えるかどうかを予測するタスクのデータセットで、48,842サンプルが含まれます。
UCI Machine Learning Repositoryからダウンロードすることもできますが、Fairlearnのfetch_adultで取得します。

データを7:3にランダムに分割して、それぞれを教師データとテストデータとして使用します。
ラベルは、Fairlearnで用いられるように'>50K'は1、'<=50K'は0となるように変換しておきます。

X, y = fetch_adult(return_X_y=True, as_frame=True)
print(X.head())
print(X.shape)
print(set(y))

X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, random_state=42)
y_train = (y_train == '>50K') * 1
y_test = (y_test == '>50K') * 1
実行結果
    age  workclass    fnlwgt     education  education-num      marital-status  \
0  25.0    Private  226802.0          11th            7.0       Never-married   
1  38.0    Private   89814.0       HS-grad            9.0  Married-civ-spouse   
2  28.0  Local-gov  336951.0    Assoc-acdm           12.0  Married-civ-spouse   
3  44.0    Private  160323.0  Some-college           10.0  Married-civ-spouse   
4  18.0        NaN  103497.0  Some-college           10.0       Never-married   

          occupation relationship   race     sex  capital-gain  capital-loss  \
0  Machine-op-inspct    Own-child  Black    Male           0.0           0.0   
1    Farming-fishing      Husband  White    Male           0.0           0.0   
2    Protective-serv      Husband  White    Male           0.0           0.0   
3  Machine-op-inspct      Husband  Black    Male        7688.0           0.0   
4                NaN    Own-child  White  Female           0.0           0.0   

   hours-per-week native-country  
0            40.0  United-States  
1            50.0  United-States  
2            40.0  United-States  
3            40.0  United-States  
4            30.0  United-States  
(48842, 14)
{'<=50K', '>50K'}

3. 相関の除去

Correlation Removerは、連続値の特徴にしか適用できないため、データセットから連続値だけ抽出した X_train_fl と、そこから相関を除去した X_cr を作成します。
属性も数値に変換する必要があるので、性別を整数値に変換しておきます。

X_train_fl = X_train[['age', 'fnlwgt', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week', 'sex']]
X_test_fl = X_test[['age', 'fnlwgt', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']]
X_train_fl.loc[:,'sex'] = (X_train_fl['sex'] == 'Male').astype(int)

cr = CorrelationRemover(sensitive_feature_ids=["sex"])
X_cr = cr.fit_transform(X_train_fl)
X_cr_df = pd.DataFrame(X_cr, columns=['age', 'fnlwgt', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week'])
X_cr_df['sex'] = X_train_fl['sex']

除去前後の特徴間の相関を可視化します。
除去前は、性別とその他の特徴に相関があるのに対し、除去後には、相関が0になっていることが確認できます。

def draw_heatmap(X, title):
    cols = list(X.columns)
    plt.imshow(round(X.corr(), 2), cmap="coolwarm")
    plt.xticks(np.arange(len(cols)), labels=cols)
    plt.yticks(np.arange(len(cols)), labels=cols)
    plt.xticks(rotation=30)
    for i in range(len(cols)):
        for j in range(len(cols)):
            plt.text(
                j,
                i,
                round(X.corr().to_numpy()[i, j], 2),
                ha="center",
                va="center",
            )
    plt.title(title)

plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
draw_heatmap(X_train_fl, 'Before removal')

plt.subplot(1,2,2)
draw_heatmap(X_cr_df, 'After removal')

plt.tight_layout()
plt.show()

correlation.png

4. 学習

LightGBMでモデルの学習を行います。
全ての特徴を用いたモデル、連続値だけ用いたモデル、相関を取り除いた連続値を用いたモデルの3つを構築します。

lgb_params = {
    'objective' : 'binary',
}
model = lgb.LGBMClassifier(**lgb_params)
model.fit(X_train, y_train)

model_fl = lgb.LGBMClassifier(**lgb_params)
X_tmp = X_train_fl.drop('sex', axis=1)
model_fl.fit(X_tmp, y_train)

model_cr = lgb.LGBMClassifier(**lgb_params)
model_cr.fit(X_cr, y_train)

5. 公平性評価

モデルの有用性は、今回はF1スコアをsklearn.metrics.f1_scoreで計算します。
公平性指標はEqualized OddsをFairlearnのequalized_odds_differenceで計算します。
この関数は、sensitive_featuresに指定した属性のグループ間のtrue positive rateまたはfalse positive rateの差の最大値を出力します。

これらの指標の散布図を描画して、予測性能と公平性のトレードオフを確認します。

# Default
pred = model.predict(X_test)
plt.scatter(equalized_odds_difference(y_test, pred, sensitive_features=X_test['sex']), f1_score(y_test, pred),  label='Default')
plt.legend()

# Float
pred = model_fl.predict(X_test_fl)
plt.scatter(equalized_odds_difference(y_test, pred, sensitive_features=X_test['sex']), f1_score(y_test, pred),  label='Float')
plt.legend()

# Correlation removal
pred = model_cr.predict(X_test_fl)
plt.scatter(equalized_odds_difference(y_test, pred, sensitive_features=X_test['sex']), f1_score(y_test, pred),  label='CR')
plt.legend()

plt.xlabel('Equalized Odds')
plt.ylabel('F1 score')
plt.show()

result_CR.png

おわりに

今回の結果

Correlation Removerによってモデルの公平性を改善できることが確認できました。
しかし、F1スコアの低下が大きく、実用的なモデルとはなりませんでした。

次にやること

学習後に公平性を改善する手法も検証したいと思います。

参考資料

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2