「fairness」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「fairness」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「fairness の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
公平性は、AIが差別をしないための基準です。
正しい判断ができているか測るために使います。
部活のメンバー選びで不公平がないか考えるときと同じです。
ここでは、公平性を測る方法や対策について読みます。
AIシステムが差別的でないことの基準
🍰 まずはやさしく
公平性は、社会のルールに関わる大切な考え方です。
AIによる差別を防ぎ、法律を守るために使います。
スマホの顔認証などで不当な差が出ないようにします。
ここでは、公平性を学ぶための全体の流れを読みます。
AI採用、 ローン審査、 顔認識 — 差別的判断が社会問題化。 EU AI Act では高リスクAIに公平性監査が義務化される方向。 倫理を超えて法令対応事項に。
本ページでは「fairness」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「fairness」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
公平性には、いくつかの考え方があります。
どの基準が正しいかを判断するために使います。
テストの点数と合格率の関係を考えるときのような話です。
ここでは、公平性の種類と難しい点について読みます。
採用 AI を例にすると、 公平性には少なくとも 3 つの異なる定義があります:
Chouldechova (2017) と Kleinberg et al. (2016) は、 基底率 (各群の真の正例率) が群間で違うとき これら全てを同時に満たすことは数学的に不可能 と証明しました (Impossibility Theorem)。 例えば SSDSE-B-2026 で「大都市 vs 地方」を保護属性として推定した場合、 大都市の方が機会が多ければ Demographic Parity と Calibration は両立しません。
つまり「何を公平とするか」自体が技術ではなく 価値判断・社会合意の問題で、 COMPAS 再犯予測ツール (ProPublica 2016) の論争はまさにこの選択を巡るものでした。 米国 EEOC の 4/5 ルール (採用率比 ≥ 0.8) と EU AI Act (2026 施行) の高リスク区分では、 適用する公平性定義が異なります。
大学奨学金を「成績」だけで選ぶ場合、 もし家庭環境で塾通いができる学生が有利なら、 結果として高所得家庭の合格率が高くなる。 これは Demographic Parity に違反する可能性がある。 一方、 「同じ成績の学生は出身家庭によらず同じ確率で合格」していれば Equal Opportunity は満たされる。 どちらを優先するか? もし君が奨学金委員会のメンバーなら、 「結果の平等」と「機会の平等」のどちらを重視するだろうか? この問いに技術だけでは答えられないことが、 公平性問題の核心だ。
| 属性群 | 大学進学率 (真値) | AI推薦合格率 | True Positive Rate (機会均等) |
|---|---|---|---|
| 東京都市部 | 72% | 78% | 0.91 |
| 地方中核市 | 58% | 61% | 0.88 |
| 山間部・離島 | 41% | 32% | 0.71 |
この AI 推薦システムは TPR が地域で 0.71〜0.91 とばらつき、 Equal Opportunity 不成立。 さらに合格率も地域で 32〜78% で Demographic Parity 不成立。 どちらの不成立をどこまで許容するかは「教育政策の価値判断」であり、 純粋な数学的最適化では決められない。
🍰 まずはやさしく
公平性とは、数式で表した差別のなさと定義します。
AIの計算結果が平等かを確かめるために使います。
買い物での割引率が誰でも同じか調べるようなものです。
ここでは、公平性を表す数式やグラフについて読みます。
公平性(Fairness):AIシステムが差別的でないことの基準
同義・関連語:AI公平性
制約 eps を変えながら学習すると、 「公平性」「精度」「校正」が同時に最適化できない曲面が見えます。 これを Pareto frontier (パレートフロンティア) と呼びます。 組織は この曲面上のどの点を選ぶかを倫理判断として行います。
| eps (DP 上限) | DP 差 | 精度 | TPR (大都市/地方) |
|---|---|---|---|
| 制約なし | 0.561 | 0.851 | 1.000 / 0.561 |
| 0.20 | 0.196 | 0.787 | 0.833 / 0.683 |
| 0.10 | 0.099 | 0.766 | 0.667 / 0.683 |
| 0.05 | 0.048 | 0.745 | 0.500 / 0.683 |
| 0.01 | 0.008 | 0.681 | 0.333 / 0.341 |
💬 eps を厳しくすると DP 差は小さくなるが、 精度が低下し、 大都市群の TPR が下がる。 これは「大都市の優秀者にも漏れが出る」ことを意味し、 単純な「公平 = 正義」ではない複雑性が現れる。
| 記号 | 意味 |
|---|---|
| $A$ | 保護属性(性別、 人種、 年齢など) |
| $\hat{Y}$ | AIの予測ラベル |
| $Y$ | 真のラベル |
| プロキシ | 保護属性と相関する変数(郵便番号と人種等) |
公平性(Fairness)は、 単に用語の定義を覚えるだけでは本当には理解できません。 なぜこの概念が生まれたのか、 どんな問題を解決するために導入されたのか、 類似の手法とどう違うのか — これらを意識することで、 初めて「使える知識」になります。
数式や Python コードはあくまで 道具。 道具の使い方を覚える前に、 その道具で何をしたいか(目的) を明確にすることが、 データサイエンス学習の鉄則です。
公平性は単独の指標ではなく、 統計的差別禁止 (disparate impact)、 アルゴリズムバイアス、 個別公平性 vs 集団公平性、 因果推論との接続といった概念ネットワークの中心に位置します。 関連用語を辿ると以下の構造が見えます:
理論を学ぶことと、 実務で使えることは別物です。 公的統計(SSDSE、 e-Stat 等)の実データで実装・実験することで、 教科書だけでは見えない罠 に気付けます。 たとえば:
これらは 公平性 に限った話ではなく、 データサイエンス全般に共通する作法です。 「落とし穴」セクションの内容と合わせて、 自分なりのチェックリストを作るとよいでしょう。
公平性 を使った分析の 正しさを担保する ためには、 以下の観点で検証するのが定番です。
| 確認する点 | 公平性 で何を見るか |
|---|---|
| 属性を消せば公平、 ではない | プロキシ(郵便番号等)から保護属性が推測できる。 |
| 複数定義の取り違え | DP と EO は両立しない(不可能性定理)。 |
| 精度との両立 | 公平性制約で精度が落ちる場合あり。 トレードオフを開示。 |
| 「無バイアス」は不可能 | 公平性は完全達成ではなく、 継続的監視が現実解。 |
| 再現性 | 同じデータ・同じコードで同じ結果が出るか。このページの ▶ 実行ボタンで確かめられます |
公平性 は分野横断で活躍する概念です。 業界別に見ると以下のような使われ方があります。
公平性 を実際のデータで学ぶときは、 SSDSE(教育用標準データセット、 総務省統計局)が便利です。
これらは 統計センターの SSDSE ページ から CSV で直接ダウンロードできます。 上の Python コード例で data/raw/SSDSE-B-2026.csv としているのが、 まさにこれです。
実データで動かすことで、 教科書の例題では見えない 実務的な気づき(欠損のパターン、 単位の混在、 都道府県名の表記揺れ等)が得られます。
pip install pandas numpy scikit-learn matplotlib で揃います。utf-8 ではなく shift_jis や cp932 の場合がある(古い日本の公的統計に多い)。 encoding='cp932' を試してください。%matplotlib inline、 スクリプト実行なら plt.show() を忘れずに。 日本語フォントは matplotlib 用に別途設定(japanize-matplotlib 等)が必要。公平性の代表指標 Demographic Parity(人口統計的均等) を 4 要素で精密に読み解きます。
$\hat Y$ は モデル予測(融資承認= 1、 不承認= 0 など)。 $A$ は 保護属性(性別・人種・年齢・国籍)。 $P(\hat Y = 1 \mid A = a)$ はサブグループ $a$ の中で陽性予測が出る確率。 「女性の中で融資承認率は何%か」を測る量。 実務では性別・人種・年齢区分などをサブグループとして設定し、 サブグループ間で陽性率が等しくなることを要求する。
$b$ は別のサブグループ(男性、 白人、 若年層)。 右辺は同じ陽性予測の条件付き確率を $b$ 側で測ったもの。 「男性の中で融資承認率は何%か」。 左辺=右辺 は 「サブグループに関わらず承認率が同じ」を意味する。 つまり結果(output)の均等性を要求する指標。 米 EEOC の Disparate Impact ルール(4/5 ルール)は緩い形の Demographic Parity と等価で、 「マイノリティの承認率/マジョリティの承認率 ≥ 0.8」を法的閾値とする。
$\forall a, b \in \mathcal{A}$ は 「任意の 2 つのサブグループの組み合わせ」で等式が成立することを要求。 $\mathcal{A}$ が 2 値(男女)なら 1 つの等式、 $|\mathcal{A}| = 5$(年齢層 5 区分)なら $\binom{5}{2} = 10$ 個の等式すべて成立を求める。 実務では完全な等式は不可能なので、 Demographic Parity Difference (DPD) $= \max_{a,b} |P(\hat Y=1|A=a) - P(\hat Y=1|A=b)|$ を 0.05〜 0.10 以下に抑えるという緩和を採る。
この指標には致命的な限界がある。 Chouldechova(2017)と Kleinberg ら(2017)が独立に示した 「Fairness Impossibility Theorem」 によれば、 Demographic Parity、 Equalized Odds、 Calibration の 3 つは、 base rate(クラス事前確率)がサブグループ間で異なるとき、 同時に満たすことは数学的に不可能。 たとえば男女で犯罪再犯率の base rate が異なれば、 Demographic Parity を満たすと Equalized Odds が破れる。 したがって 「どの公平性を優先するか」は技術的選択ではなく、 社会的・倫理的選択 となる。 ML エンジニアは「すべて満たします」と約束できない。 これがアルゴリズム公平性の本質的難しさ。
10 種類の公平性メトリクスを「定義式 → 直感 → 採用場面」で並列に並べます。 これは fairlearn / AIF360 の機能対応表でもあります。
| 名称 | 数式 | 数式を言葉で読み解く |
|---|---|---|
| Statistical / Demographic Parity | $P(\hat Y=1 | A=a) = P(\hat Y=1 | A=b)$ | 予測の「1 が出る確率」が群で等しい |
| Disparate Impact | $P(\hat Y=1|A=u)/P(\hat Y=1|A=p) \geq 0.8$ | 不利群比率 / 有利群比率 が 0.8 以上 |
| Equal Opportunity | $P(\hat Y=1 | Y=1, A=a) = P(\hat Y=1 | Y=1, A=b)$ | 本来 1 の人を 1 と予測する率が群で等しい (= TPR 等価) |
| Equalized Odds | $P(\hat Y=1 | Y=y, A=a) = P(\hat Y=1 | Y=y, A=b),\ y \in \{0,1\}$ | TPR も FPR も両群で等しい (より厳しい条件) |
| Predictive Parity | $P(Y=1 | \hat Y=1, A=a) = P(Y=1 | \hat Y=1, A=b)$ | 1 と予測した中での真陽性率 (Precision) が群で等しい |
| Calibration | $P(Y=1 | \hat p = p, A=a) = p$ | 「予測確率 p」と「実際の真陽率」が一致 (群で) |
| Treatment Equality | $\mathrm{FN}/\mathrm{FP}$ が群で等しい | 偽陰性 / 偽陽性 の比率が群で等しい |
| Counterfactual Fairness | $P(\hat Y_{A \leftarrow a} = 1 | X, A) = P(\hat Y_{A \leftarrow b} = 1 | X, A)$ | 保護属性だけ書き換えた仮想世界での予測が変わらない |
| Individual Fairness (Lipschitz) | $d_Y(M(x_1), M(x_2)) \leq L \cdot d_X(x_1, x_2)$ | 似た個人には似た予測 (距離が L 倍以下) |
| Theil Index (不平等) | $T = \frac{1}{N}\sum_i \frac{b_i}{\mu} \ln\frac{b_i}{\mu}$ | 利得 $b_i$ の不平等度合いをエントロピー風に測る |
💬 運用上の選び方: ① 採用・融資 → Equal Opportunity (本来資格のある人を漏らさない) ② 刑事司法 → Equalized Odds (両エラーを均等に) ③ 医療診断 → Calibration (予測確率の信頼性) ④ 推薦・広告 → Demographic Parity (露出の平等) ⑤ 価格・保険 → Individual Fairness (個別の合理性)。 不可能定理により 全部は満たせないため、 領域固有の優先順位を文書化することが重要。
公平性は抽象概念ですが、 サブグループ別の予測陽性率を実値で並べると一目瞭然です。 ここでは仮想的な「市区町村への補助金審査スコア」を想定し、 都市規模別の Demographic Parity を計算する数値例を示します(SSDSE-B-2026 は 47 都道府県×複数年のデータのため、 以下は市区町村統計を想定した仮想例です)。
| サブグループ | 陽性率 | 95% CI |
|---|---|---|
| 大都市 | 0.142 | [0.10, 0.18] |
| 中規模 | 0.387 | [0.35, 0.42] |
| 小規模 | 0.612 | [0.58, 0.64] |
なお、 これは 意図的なバイアスではなく、 高齢化率を特徴量に入れた結果。 「Demographic Parity の達成」と「予測精度の維持」はトレードオフ関係にあり、 どちらを優先するかは政策判断。
公平性 は学術概念に留まらず、 産業界で多種多様に運用されています。 6 業界の代表事例を示します。
公平性 は単独でなく類似概念群の中で位置付けると理解が深まります。
| 概念 | 定義の要点 | 代表例 | 分類軸 |
|---|---|---|---|
| Demographic Parity | 陽性率がグループ間で等しい | 融資承認率= | 結果均等 |
| Equalized Odds | TPR・FPR が等しい | 正解者の見逃し率= | 誤り均等 |
| Calibration | 予測確率が実頻度と一致 | リスク 0.3 のうち実際 30% | 確率整合 |
| Individual Fairness | 似た個人は似た処遇 | Lipschitz 連続 | 個別 |
| Counterfactual Fairness | 属性を変えても結果不変 | 性別を変えても与信不変 | 反実 |
| Procedural Fairness | プロセスの公正性 | Due process(手続的) | 手続 |
理解度を確認する 5 問。 解答例は折りたたみで隠してあります。 まず自力で考えてから開いてください。
2019 年 11 月、 Apple Card(Goldman Sachs 提供)に対し 夫婦間で同等の収入・信用スコアにも関わらず、 妻側の与信限度が夫の 1/20 だった事例が Twitter で告発(DHH @dhh、 Steve Wozniak も同様報告)。 ニューヨーク金融サービス局が調査開始、 Apple/Goldman Sachs は「アルゴリズムは性別を明示的に使っていない」と弁明したが、 NYDFS は 「proxy variable(代理変数)経由で性別バイアスが学習データから漏れた可能性」を指摘。 教訓:性別・人種を入力から除外しても、 居住地・職業・学歴などの相関変数(proxy)から間接的にバイアスが学習される。 これは「fairness through unawareness」の限界。 対策:counterfactual fairness テスト、 サブグループ別精度の継続監視、 第三者監査。
公平性 を学ぶ際に頻出する 10 語の最小限定義集です。 詳しくは各専用ページを参照。
公平性 (Fairness) は AI 倫理の中で最も多用される語ですが、 「測れない不公平」は対処もできません。 ここでは SSDSE-B-2026 の 2023 年データから、 47 都道府県を 大都市群 (東京・神奈川・埼玉・千葉・大阪・愛知 計 6 都府県) と 地方群 (残り 41 県) に分け、 高等学校卒業者の大学進学率という「機会の指標」で 3 つの公平性メトリクスを計算します。 これは「もし AI が高校生に進学先を推薦するモデル」を構築する場合、 学習データに含まれる 地域バイアス を可視化する手順そのものです。
$$\text{Demographic Parity (DP)}:\ P(\hat{Y}=1 \mid A=a) = P(\hat{Y}=1 \mid A=b)$$
$$\text{Disparate Impact (DI)}:\ \frac{P(\hat{Y}=1 \mid A=\text{unprivileged})}{P(\hat{Y}=1 \mid A=\text{privileged})} \geq 0.8$$
$$\text{Equal Opportunity (EOp)}:\ P(\hat{Y}=1 \mid Y=1, A=a) = P(\hat{Y}=1 \mid Y=1, A=b)$$
$\hat{Y}$: モデルの予測 (例: 進学する=1)、 $Y$: 真のラベル、 $A$: 保護属性 (今回は地域)🎯 このコードでやること: SSDSE-B-2026 の 47 都道府県を大都市/地方の 2 群に分け、 高校卒業→大学進学率について Demographic Parity 差・Disparate Impact 比・絶対格差を計算する。
📥 入力データ (SSDSE-B-2026 2023 年 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() big_list = ['東京都','神奈川県','埼玉県','千葉県','大阪府','愛知県'] d['Group'] = d['Prefecture'].apply(lambda p: 'big' if p in big_list else 'small') big = d[d['Group']=='big'] small = d[d['Group']=='small'] # 進学率 = 大学進学者 / 高校卒業者 rate_big = big['E4602'].sum() / big['E4601'].sum() rate_small = small['E4602'].sum() / small['E4601'].sum() # 1. Demographic Parity 差 DP_diff = rate_big - rate_small # 2. Disparate Impact 比 (unprivileged=小, privileged=大) DI = rate_small / rate_big # 3. 絶対人数の格差 (Equal Opportunity の単純版) N_big_advantage = big['E4602'].sum() / d['E4602'].sum() N_big_pop = big['E4601'].sum() / d['E4601'].sum() print(f'大都市群 進学率: {rate_big:.4f}') print(f'地方群 進学率: {rate_small:.4f}') print(f'DP 差: {DP_diff:.4f}') print(f'DI 比: {DI:.3f} (4/5 ルール基準: 0.8)') print(f'大都市の全国進学者シェア: {N_big_advantage:.3f}') print(f'大都市の全国高校卒業者シェア: {N_big_pop:.3f}') |
📤 実行結果:
💬 結果の読み方: 大都市の高校生は 68.6% が大学に進学するのに対し、 地方は 57.3%。 11.3 ポイントの開きがあります。 DI 比は 0.835 で 4/5 ルール (0.8) はギリギリ通過しますが、 米国 EEOC の解釈では「グレーゾーン」。 さらに、 全国の高校卒業者の 39.9% を占める大都市が、 大学進学者の 44.3% を占めるという「機会の集中」も観察されます。 もしこのデータで「AI 進路推薦モデル」を学習させると、 地方の生徒に対しても保守的な推薦 (大学を勧めない) が出やすくなる可能性があります。
公平性の議論は「平均値の差」だけでは不十分。 47 県を上位/下位で並べると、 連続的な格差構造が見えます。 以下は SSDSE-B-2026 (2023) で計算した全 47 県の高校→大学進学率です。
| 順位 | 県名 | 高卒 | 進学 | 進学率 | 大都市? |
|---|---|---|---|---|---|
| 1 | 東京都 | 93,495 | 69,302 | 74.1% | ○ |
| 2 | 京都府 | 20,757 | 15,350 | 74.0% | × |
| 3 | 神奈川県 | 60,088 | 41,686 | 69.4% | ○ |
| 4 | 大阪府 | 62,697 | 43,208 | 68.9% | ○ |
| 5 | 兵庫県 | 39,100 | 26,802 | 68.5% | × |
| 6 | 埼玉県 | 50,543 | 33,264 | 65.8% | ○ |
| 7 | 広島県 | 20,902 | 13,733 | 65.7% | × |
| … | … | … | … | … | … |
| 43 | 山口県 | 9,331 | 4,528 | 48.5% | × |
| 44 | 佐賀県 | 6,843 | 3,310 | 48.4% | × |
| 45 | 鹿児島県 | 12,998 | 6,257 | 48.1% | × |
| 46 | 宮崎県 | 8,786 | 4,216 | 48.0% | × |
| 47 | 沖縄県 | 13,022 | 6,080 | 46.7% | × |
💬 解釈: 進学率は 46.7% (沖縄) ~ 74.1% (東京) の幅で連続的に分布。 2 位の京都府 (74.0%) は大都市群ではないが大学集積地として東京とほぼ並び、 単純な「大都市 vs 地方」分類は粗い。 大都市群の平均 68.6% は中庸より上だが、 京都府を上回るわけではない。 公平性指標を計算する際は「群定義の妥当性」も同時に問うべき。
合成データで群別の予測陽性率の差を計算する。
| 群 | n | 陽性予測 | P(ŷ=1|G) |
|---|---|---|---|
| 男性 | 500 | 250 | 0.500 |
| 女性 | 500 | 200 | 0.400 |
1 2 3 4 5 6 7 8 | p_m = 250/500 p_f = 200/500 dp = p_m - p_f di = p_f / p_m print(f"P(ŷ=1|男): {p_m}") print(f"P(ŷ=1|女): {p_f}") print(f"DP差: {dp}") print(f"DI比: {di}") |
💬 手計算 (Step 2) と Python 出力が完全一致。 DI=0.80 は 4/5 ルール境界。
SSDSE-B-2026 などの実データを使った最小コード(11行):
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd import numpy as np # 公平性指標の簡易計算 rng = np.random.default_rng(0) df = pd.DataFrame({ 'group': rng.choice(['A','B'], 1000), 'pred': rng.binomial(1, 0.5, 1000), }) rates = df.groupby('group')['pred'].mean() print('グループ別予測率:'); print(rates) print('DP差:', abs(rates['A'] - rates['B']).round(3)) |
※ data/raw/SSDSE-B-2026.csv は e-Stat SSDSE から取得した実データを想定。
公平性メトリクスで「問題あり」と判明したら、 次は 緩和です。 代表的な 3 アプローチ — Pre-processing (前処理: 重み調整)、 In-processing (学習中: 制約付き最適化)、 Post-processing (後処理: 閾値別調整) — を SSDSE-B のデータで試します。
🎯 このコードでやること: 「大都市の進学例」を軽く、 「地方の進学例」を重く、 という訓練データの重みを調整して DP 差を縮める。
📥 入力: 47 県 × 2 (進学/非進学) = 94 行に展開した教育データ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() big_list = ['東京都','神奈川県','埼玉県','千葉県','大阪府','愛知県'] d['Group'] = d['Prefecture'].apply(lambda p: 'big' if p in big_list else 'small') # 4 セルの観測度数 (大/小 × 進学/非進学) N = {} for g, sub in d.groupby('Group'): N[(g, 1)] = sub['E4602'].sum() # 進学 N[(g, 0)] = sub['E4601'].sum() - sub['E4602'].sum() # 非進学 total = sum(N.values()) # Reweighting 重み = (P(A) * P(Y)) / P(A, Y) weights = {} for (g, y), n in N.items(): PA = sum(N[(g, y2)] for y2 in [0, 1]) / total PY = sum(N[(g2, y)] for g2 in ['big', 'small']) / total PAY = n / total weights[(g, y)] = (PA * PY) / PAY for k, w in weights.items(): print(f'{k}: 観測 {N[k]:>7}, 重み {w:.3f}') |
📤 実行結果:
💬 結果の読み方: 大都市の進学例 (有利な観測) の重みは 0.901 と「軽く」、 地方の進学例 (不利な観測) は 1.079 と「重く」なります。 この重みで再学習すれば、 モデルは地方の進学者をより重視するようになり、 結果として DP 差が縮小します。 これが Kamiran & Calders (2012) の Reweighting 原理。
🎯 このコードでやること: モデル予測スコアに対し、 大都市と地方で 異なる判定閾値を設定し、 DP 差を 0 にする。
📥 入力: 仮想的なスコア (進学率を 0.05 ノイズで揺らしたもの)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() big_list = ['東京都','神奈川県','埼玉県','千葉県','大阪府','愛知県'] d['Group'] = d['Prefecture'].apply(lambda p: 'big' if p in big_list else 'small') d['Score'] = d['E4602'] / d['E4601'] # 進学率を仮想スコアとして使う # 同一閾値 0.6 で判定した場合 mask = d['Score'] >= 0.6 big_rate0 = mask[d['Group']=='big'].mean() small_rate0 = mask[d['Group']=='small'].mean() print(f'共通閾値 0.6 → 大都市予測率: {big_rate0:.3f}, 地方予測率: {small_rate0:.3f}') print(f' DP 差: {big_rate0 - small_rate0:.3f}') # 群別閾値: 大都市=0.68, 地方=0.56 thresh = {'big': 0.68, 'small': 0.56} d['Pred'] = d.apply(lambda r: r['Score'] >= thresh[r['Group']], axis=1) big_rate1 = d.loc[d['Group']=='big','Pred'].mean() small_rate1 = d.loc[d['Group']=='small','Pred'].mean() print(f'群別閾値 → 大都市予測率: {big_rate1:.3f}, 地方予測率: {small_rate1:.3f}') print(f' DP 差: {big_rate1 - small_rate1:.3f}') |
📤 実行結果:
💬 結果の読み方: 共通閾値 0.6 では大都市の 100%、 地方の 22% しか「進学を勧める」予測にならず、 DP 差は 0.78 と巨大。 群別閾値 (大=0.68, 小=0.56) を使うと両群で約 50% に揃い、 DP 差はほぼゼロに。 ただし、 これは 群別の判定基準を持つことを意味し、 「個人公平性」(同じスコアなら同じ扱い) とは正面衝突します。 ここに fairness の根本的トレードオフがあります。
🎯 このコードでやること: Microsoft Fairlearn の MetricFrame を用いて、 群別の精度・偽陽性率を一括で算出する。
📥 入力: 47 県の予測 (Score≥0.6 → 1) と真のラベル (Score≥0.65 → 1; 教師データを進学率 0.65 を境とした 2 値で生成)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd from fairlearn.metrics import MetricFrame, demographic_parity_difference, equalized_odds_difference, true_positive_rate, false_positive_rate from sklearn.metrics import accuracy_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() big_list = ['東京都','神奈川県','埼玉県','千葉県','大阪府','愛知県'] d['Group'] = d['Prefecture'].apply(lambda p: 'big' if p in big_list else 'small') d['Score'] = d['E4602'] / d['E4601'] d['Pred'] = (d['Score'] >= 0.60).astype(int) d['True'] = (d['Score'] >= 0.65).astype(int) mf = MetricFrame( metrics={'acc': accuracy_score, 'TPR': true_positive_rate, 'FPR': false_positive_rate}, y_true=d['True'], y_pred=d['Pred'], sensitive_features=d['Group'] ) print(mf.by_group) print('DP diff:', demographic_parity_difference(d['True'], d['Pred'], sensitive_features=d['Group'])) print('EO diff:', equalized_odds_difference(d['True'], d['Pred'], sensitive_features=d['Group'])) |
📤 実行結果:
💬 結果の読み方: 両群とも TPR は 1.0 だが、 大都市群は FPR 100% (真のラベルが 0 の 2 県も陽性判定) で精度 66.7%、 地方群は FPR 13.5% で精度 87.8%。 DP 差 0.780 / Equalized Odds 差 0.865 ともに大きく、 fairlearn のルールでは「強い不公平」と判定される水準。 fairlearn の Reduction Algorithm (ExponentiatedGradient) を使えば、 制約付き最適化で DP 差をしきい値内に抑えた予測器を学習できます。
Pre-processing と Post-processing は予測モデル本体を変更しません。 In-processing は 損失関数 + 公平性制約のラグランジュ最適化を行い、 「最初から公平な分類器」を作ります。 Agarwal et al. (2018) の Reduction Approach が標準。
🎯 このコードでやること: SSDSE-B-2026 を 4 特徴量に展開し、 LogisticRegression を「DP 差 ≤ 0.05」の制約下で学習する。
📥 入力特徴量 (説明変数): 人口・大学数・幼稚園数・着工建築物床面積を標準化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import pandas as pd import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from fairlearn.reductions import ExponentiatedGradient, DemographicParity df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() big_list = ['東京都','神奈川県','埼玉県','千葉県','大阪府','愛知県'] d['Group'] = d['Prefecture'].apply(lambda p: 'big' if p in big_list else 'small') X_raw = d[['A1101', 'E6102', 'E4101', 'C3302']].values y = (d['E4602'] / d['E4601'] >= 0.60).astype(int).values A = d['Group'].values X = StandardScaler().fit_transform(X_raw) # 制約なし clf0 = LogisticRegression().fit(X, y) pred0 = clf0.predict(X) dp0 = abs(pred0[A=='big'].mean() - pred0[A=='small'].mean()) # 制約付き学習 (DP) mitigator = ExponentiatedGradient(LogisticRegression(), constraints=DemographicParity(), eps=0.05) mitigator.fit(X, y, sensitive_features=A) pred1 = mitigator.predict(X, random_state=0) dp1 = abs(pred1[A=='big'].mean() - pred1[A=='small'].mean()) print(f'制約なし DP 差: {dp0:.3f}, 精度: {(pred0==y).mean():.3f}') print(f'制約あり DP 差: {dp1:.3f}, 精度: {(pred1==y).mean():.3f}') |
📤 実行結果:
💬 結果の読み方: 制約なしの分類器は DP 差 0.951 と巨大、 精度は 80.9%。 制約付き (eps=0.05) は DP 差を 0.000 に抑えるが、 精度は 68.1% に低下。 12.8 ポイントの精度トレードオフを組織は「公平性が値打ちか」を社会的議論で決める必要があります。 Agarwal et al. の論文では複数の eps を試して Pareto frontier を描く方法を推奨。
Kusner et al. (2017) の Counterfactual Fairness は因果モデルを利用します。 「ある個人の保護属性 (例: 地域) を入れ替えても予測が変わらないなら公平」とする立場で、 group fairness と individual fairness の橋渡しになります。
🎯 このコードでやること: 沖縄県の特徴量を「もし東京都の人口規模だったら」と入れ替え、 進学率モデルの予測がどう変わるか計算する。
📥 入力: 47 県 LogisticRegression + 沖縄県の特徴量を東京の値に書き換え
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() X_raw = d[['A1101', 'E6102', 'E4101', 'C3302']].values y = (d['E4602'] / d['E4601'] >= 0.60).astype(int).values scaler = StandardScaler().fit(X_raw) X = scaler.transform(X_raw) clf = LogisticRegression().fit(X, y) # 沖縄県のオリジナル okinawa = d[d['Prefecture']=='沖縄県'].copy() tokyo = d[d['Prefecture']=='東京都'].iloc[0] X_okinawa = scaler.transform(okinawa[['A1101', 'E6102', 'E4101', 'C3302']].values) p_orig = clf.predict_proba(X_okinawa)[0, 1] # Counterfactual: 沖縄県の人口・大学数だけ東京都に置き換え okinawa_cf = okinawa.copy() okinawa_cf[['A1101', 'E6102']] = [tokyo['A1101'], tokyo['E6102']] X_cf = scaler.transform(okinawa_cf[['A1101', 'E6102', 'E4101', 'C3302']].values) p_cf = clf.predict_proba(X_cf)[0, 1] print(f'沖縄県 (オリジナル) 進学率予測確率: {p_orig:.3f}') print(f'沖縄県 (人口・大学数を東京に置換) 進学率予測確率: {p_cf:.3f}') print(f'差: {p_cf - p_orig:.3f}') |
📤 実行結果:
💬 結果の読み方: 沖縄県の予測は 0.206 (進学率 60% 以上の確率は低い) だったのが、 人口と大学数を東京都の値に置き換えると 1.000 に跳ね上がります。 差 0.794 — Counterfactual Fairness の観点からは、 このモデルは沖縄県を「人口」だけで強く差別している。 因果モデル (DAG) を組み立て、 「人口」が「進学率」の因果原因か単なる代理変数かを問うことが Pearl 流の解析です。
🎯 このコードでやること: SSDSE-B-2026 の「男性人口 (A110101)」と「女性人口 (A110102)」を使い、 47 都道府県で「男女の人口バランス」がどれだけ偏っているかを Theil 指数で計算する。
📥 入力: 47 県 × {男性人口, 女性人口}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() d['MaleRatio'] = d['A110101'] / d['A1101'] # Theil index: T = (1/N) * sum( (b_i/mu) * ln(b_i/mu) ) b = d['MaleRatio'].values mu = b.mean() T = np.mean((b / mu) * np.log(b / mu)) print(f'平均男性比率: {mu:.4f}') print(f'男性比率の Theil 指数: {T:.6f}') print(f'男性比率の標準偏差: {b.std():.4f}') # 上位/下位 5 県 sorted_d = d.sort_values('MaleRatio', ascending=False) print('男性比率 上位 5:') print(sorted_d[['Prefecture', 'MaleRatio']].head(5).to_string(index=False)) print('男性比率 下位 5:') print(sorted_d[['Prefecture', 'MaleRatio']].tail(5).to_string(index=False)) |
📤 実行結果:
💬 結果の読み方: 男性比率は 47.0% (奈良) ~ 50.0% (茨城) の幅で、 Theil 指数 0.000175 は 極めて低い不平等。 つまり性別比は地域差より個人内の文化要因の方が大きい。 ただし「製造業県は男性比率が高い」(茨城・栃木・愛知) という傾向は読み取れます。 これは「採用 AI の地域要因」を考える際の出発点。
| 領域 | 事例 | 問題 | 教訓 |
|---|---|---|---|
| 刑事司法 | COMPAS (2016) | FPR が黒人で 2 倍 | 複数公平性の選択を公開 |
| 金融 | Apple Card (2019) | 夫婦間で与信額に 20 倍差 | 変数の解釈責任は提供者 |
| 医療 | Optum リスクスコア (2019) | 「医療費」を健康代理に → 黒人軽視 | 代理変数の選択を吟味 |
| 採用 | Amazon (2018) | 女性応募を低く評価 | 過去ラベル使用を慎重に |
| 画像認識 | Gender Shades (2018) | 黒人女性の誤認 35% | 交差性 (intersectionality) 評価 |
| 広告 | Facebook 住宅広告 (2019) | 人種で広告露出が偏向 | 配信先の DP 監査 |
| 教育 | 英国 A-level アルゴリズム (2020) | 地域名で評定降格 | アルゴリズム説明の公開 |
公平性 (fairness) を中心に、 上 (Calibration: 較正/予測確率と実頻度の整合)・右上 (Balance for positive: 陽性予測値の集団間均衡)・右下 (Balance for negative: 陰性予測値の集団間均衡)・下 (不可能性定理: 基準率が異なる集団間で 3 指標を同時に満たせない: Chouldechova 2017, Kleinberg et al. 2017)・左下 (EEOC 4/5 ルール: demographic parity ratio ≥ 0.8)・左上 (EU AI Act 2024: 高リスク AI 第三者監査義務) の 6 方向に概念群を配置した。 Demographic Parity / Equal Opportunity / Equalized Odds (Hardt et al. 2016) のどれを採るかは政策判断であり、 SSDSE-B-2026 のような公的統計で都道府県別予測モデルを構築する場面でも、 地域属性間の公平性指標選択が現実的論点となる。
図中央の「公平性 (fairness)」は Demographic Parity / Equal Opportunity / Equalized Odds (Hardt et al. 2016) / Calibration の 4 系列の指標群を内包する。 これら指標は Chouldechova (2017) と Kleinberg et al. (2017) が示した不可能性定理 (基準率が異なる集団間で 3 指標を同時に満たすことは不可能) により、 「どの指標を採るか」が政策判断になる。 米国 EEOC の 4/5 ルール (1978) は demographic parity ratio ≥ 0.8 を採用、 EU AI Act (2024) は高リスク AI に第三者監査を要求している。
公平性指標のうち最も基本的な demographic parity (人口統計学的同等性) は、 保護属性 (例: 性別、地域) によって「肯定的判定 (融資承認・採用合格など) を受ける確率」が変わらないことを要求する。 SSDSE-B-2026 の都道府県データに対し、 「人口 200 万人以上の都府県 = A 群」「200 万人未満 = B 群」と分け、 「仮想の審査スコア (人口規模に相関する設計) が全国平均以上」を「肯定判定」と見なすトイ問題で確認する。
このコードでやること:SSDSE-B-2026 から人口区分ごとの「肯定判定率」を計算し、 demographic parity difference (DPD) と disparate impact ratio (DI) を出力する。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import numpy as np import pandas as pd # トイ例: 47 都道府県を人口規模(実列 A1101)で 2 群に分ける df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') d = df[df['SSDSE-B-2026'] == 2023].copy() # 保護属性: 総人口 200 万人以上=A_large, 未満=B_small d['group'] = (d['A1101'] >= 2_000_000).map({True: 'A_large', False: 'B_small'}) # 仮想の審査スコア(人口規模に相関する設計)が全国平均以上を肯定判定 rng = np.random.default_rng(0) d['score'] = np.log10(d['A1101']) + rng.normal(0, 0.15, len(d)) d['positive'] = (d['score'] >= d['score'].mean()).astype(int) rates = d.groupby('group')['positive'].mean() DPD = rates['A_large'] - rates['B_small'] DI = rates['B_small'] / rates['A_large'] print(rates) print(f'DPD = {DPD:.3f}, DI = {DI:.3f}') |
📤 実行結果:
💬 DPD = 0.744 は人口大規模県の肯定率が 74 ポイントも高いことを示し、 demographic parity は完全に崩れている。 DI = 0.206 は米国 EEOC の 4/5 ルール (0.8) を大きく下回り、 もしこの判定モデルを採用判定に使うなら差別的とみなされる水準。 現実には「人口」は保護属性ではないので問題ではないが、 同じロジックで「性別」「地域」に置き換えれば直ちに違法リスクとなる。 また DPD が大きくても equalized odds や calibration は満たすケースもあり、 公平性指標は 同時には満たせない (impossibility theorem, Chouldechova 2017) ことが知られている。
実務では fairlearn.metrics.MetricFrame を使うと一括で群別の精度・再現率・FPR を比較でき、
fairlearn.reductions.ExponentiatedGradient で制約付き再学習も可能。
ただし「どの公平性定義を採用するか」は技術ではなく 倫理・法務・当事者対話 の領域であり、 データサイエンティストは選択肢を提示する役回りに徹するのが望ましい。
公平性は単一の数式で測れない。 同じデータ・同じモデルに対して指標を変えると「公平」と「不公平」が真逆になることが珍しくなく、 これが impossibility theorem (Chouldechova 2017, Kleinberg 2016) として知られている。 ここでは SSDSE-B-2026 の都道府県データを使って、 demographic parity (DP)、 equalized odds (EO)、 predictive parity (PP) の 3 つを同じケースで計算し、 何が両立しないのかを実数値で見る。 題材は「出生率の高い県 (=合計特殊出生率 A4103 が中央値以上の 24 県を仮想的に positive とする) を、 県の消費支出 (L3221: 二人以上の世帯) だけで予測するモデル」とする。 これは保護属性として「人口規模 (大 / 小)」を取り、 規模で扱いに差が出ないかを点検する設定である。
| 指標 | 数式 | 何を等しくしたいか | 想定する公平観 |
|---|---|---|---|
| Demographic Parity | P(Ŷ=1|A=a) = P(Ŷ=1|A=b) | 肯定率 (採用率) を群間で揃える | 機会の平等 / 4/5 ルール |
| Equalized Odds | TPR・FPR を群間で揃える | 真陽性率と偽陽性率を等しく | 結果ベースの誤り均等 |
| Predictive Parity | PPV (precision) を群間で揃える | 「陽性」と判定した内の的中率を揃える | 予測の意味的キャリブレーション |
DP は「採用率 (yes 率) を揃える」のに対し、 EO は「真に positive な人の中で正答率を揃える」点が決定的に違う。 PP は逆に「yes と判定された人の中で本当に positive である割合を揃える」。 元の base rate (群ごとの正答比) が違うとき、 この 3 つは数学的に同時に満たせないことが証明されている (Chouldechova, 2017)。 SSDSE-B-2026 の人口規模 (大: 人口 200 万人以上 / 小: 200 万人未満) で base rate が異なれば、 この impossibility に実数値で出会える。
このコードでやること: SSDSE-B-2026 から「消費支出 (L3221)」だけを特徴量に取り、 人口規模 (大/小) を保護属性として、 DP / EO / PP の差分を一括出力する。
📥 入力例 (SSDSE-B-2026 の 2023 年抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import pandas as pd from fairlearn.metrics import MetricFrame, demographic_parity_difference, equalized_odds_difference from sklearn.linear_model import LogisticRegression from sklearn.metrics import precision_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') d = df[df['SSDSE-B-2026'] == 2023].copy() d['large'] = (d['A1101'] >= 2_000_000).astype(int) d['y'] = (d['A4103'] >= d['A4103'].median()).astype(int) X = d[['L3221']].values y = d['y'].values A = d['large'].values # 保護属性: 1=大規模 0=小規模 model = LogisticRegression().fit(X, y) yhat = model.predict(X) mf = MetricFrame(metrics={'precision': precision_score}, y_true=y, y_pred=yhat, sensitive_features=A) print('PPV by group:', mf.by_group.to_dict()) print('DP diff:', round(demographic_parity_difference(y, yhat, sensitive_features=A), 3)) print('EO diff:', round(equalized_odds_difference(y, yhat, sensitive_features=A), 3)) |
📤 実行例 (実際の出力):
💬 PPV (precision) は小規模県 0.833 / 大規模県 0.0 と極端に差があり、 predictive parity は崩れている (大規模県で陽性と予測した 3 県はすべて外れ)。 一方で DP 差分は 0.393、 EO 差分は 0.682 と、 いずれも 0.1 を大幅に超えており、 3 指標すべてが不公平の側に倒れている。 ここで興味深いのは、 DP を「均等」 (差分 0) に近づける後処理 (例: ExponentiatedGradient) を入れると、 PPV の差分はむしろ拡大することが多い、 という impossibility の現れである。 つまり どの公平性を満たすかは設計判断であり、 全部は取れない。
| 業務シナリオ | 優先する指標 | 理由 |
|---|---|---|
| 採用・入学選考 | Demographic Parity (4/5 ルール) | EEOC 等の法令が「結果の偏り」を直接規制するため |
| 再犯予測・与信 | Equalized Odds | 「無辜の人を陽性にしない」FPR 均等が社会的に重要 |
| 医療診断・スクリーニング | Predictive Parity + Calibration | スコアの臨床的意味を群間で共通化する必要 |
| 広告配信・推薦 | DP + 機会均等 (exposure parity) | 情報アクセス機会の不均衡防止 |
| 教育推薦・個別指導 | Calibration (個別キャリブレーション) | 個別差を尊重し集団差を強制しない |
どの指標も「正解」ではなく、 業務文脈と法規制と被影響者の声から選ぶしかない。 データサイエンティストは impossibility を説明し、 採用する公平性定義を意思決定者に明示させる役割を持つ。 「全部均等にしました」というモデル提案は数学的に成立しないので、 そう主張するベンダーは指標の定義を曖昧にしている可能性が高い。 必ず「どの公平性か」を聞くこと。
参考: Chouldechova A. (2017) Fair prediction with disparate impact, Big Data 5(2). / Kleinberg J. et al. (2016) Inherent trade-offs in the fair determination of risk scores, ITCS 2017. / Hardt M. et al. (2016) Equality of opportunity in supervised learning, NeurIPS.
公平性指標を測れたら、 次は「どう直すか」である。 ミティゲーションは介入点で 3 段階に分類される: 前処理 (preprocessing)・処理中 (in-processing)・後処理 (postprocessing)。 どの段階で介入するかでアクセス可能なものが変わる: モデル内部を触れるかどうか、 訓練データを書き換えてよいか、 既に出力されたスコアだけ調整するか、 で選択肢が決まる。 SSDSE-B-2026 の都道府県データを「人口規模 (大/小)」を保護属性として、 3 段階それぞれで「消費支出 (L3221) だけから合計特殊出生率上位を当てる」モデルを直してみる。
| 段階 | 代表手法 | 介入対象 | 向いている状況 | トレードオフ |
|---|---|---|---|---|
| 前処理 | Reweighing / DI-Remover | 訓練データの重み・特徴 | モデルがブラックボックス / 再学習可能 | 情報損失で全体精度↓ |
| 処理中 | Adversarial Debiasing / ExponentiatedGradient | 損失関数・制約条件 | モデルを自分で訓練できる | 学習が不安定・収束遅 |
| 後処理 | Threshold Optimization / Calibration | 予測スコアの閾値 | 既存モデルを触れない | 個人レベルで不当な反転 |
このコードでやること: 既に学習済みの LogisticRegression に対し、 群ごとの判定閾値を変えて demographic parity の差分を最小化する。 モデルを触らず公平性だけ後付けで改善する典型手法。
📥 入力データ (前セクションと同じ SSDSE-B-2026):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd from sklearn.linear_model import LogisticRegression from fairlearn.postprocessing import ThresholdOptimizer from fairlearn.metrics import demographic_parity_difference df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') d = df[df['SSDSE-B-2026'] == 2023].copy() d['large'] = (d['A1101'] >= 2_000_000).astype(int) d['y'] = (d['A4103'] >= d['A4103'].median()).astype(int) X = d[['L3221']].values y = d['y'].values A = d['large'].values base = LogisticRegression().fit(X, y) fix = ThresholdOptimizer(estimator=base, constraints='demographic_parity', prefit=True) fix.fit(X, y, sensitive_features=A) yhat = fix.predict(X, sensitive_features=A, random_state=0) print('DP diff after fix:', round(demographic_parity_difference(y, yhat, sensitive_features=A), 3)) print('Accuracy after fix:', round((yhat == y).mean(), 3)) |
📤 実行例:
💬 DP 差分は 0.393 → 0.038 と大幅に縮小し、 規模間の肯定判定率はほぼ揃った。 ただし全体精度は 0.681 → 0.638 と約 4 ポイント低下している。 この 精度と公平性のトレードオフは典型的な「fairness tax」と呼ばれ、 公平性介入には常に代償がある。 重要なのは「どこまでの精度低下なら受容可能か」を意思決定者・被影響者と合意して上限を定めることである。
このコードでやること: モデル訓練時に Equalized Odds 制約を満たすように、 重み付き分類問題のラグランジュ双対を反復的に解く。 fairlearn の最も理論的に整備された手法。
1 2 3 4 5 6 7 8 9 | from fairlearn.reductions import ExponentiatedGradient, EqualizedOdds from sklearn.linear_model import LogisticRegression from fairlearn.metrics import equalized_odds_difference eg = ExponentiatedGradient(LogisticRegression(), constraints=EqualizedOdds(), eps=0.05) eg.fit(X, y, sensitive_features=A) yhat_eg = eg.predict(X, random_state=0) print('EO diff (in-proc):', round(equalized_odds_difference(y, yhat_eg, sensitive_features=A), 3)) print('Accuracy (in-proc):', round((yhat_eg == y).mean(), 3)) |
📤 実行例:
💬 EO 差分は 0.682 → 0.136 まで大きく縮小した。 精度は 0.596 で、 この例では後処理 (0.638) よりやや低いが、 47 件という小標本では制約の効き方が group 構成に強く依存する点に注意。 一般には学習時から制約を組み込む方が、 後処理の閾値強制よりも自然なモデルに収束しやすい。 ただし学習時間は数倍に伸びる (反復回数 50 程度) ので、 大規模データでは現実的でないこともある。
「公平性」は単独で完結せず、 隣接する手法と接続することで分析パイプラインの一部として機能する。 以下に具体的な接続関係を示す。
公平性は (1) 保護属性の特定 (法的要件 + 倫理的考慮) → (2) 指標選択 (Demographic Parity / Equal Opportunity / Calibration はトレードオフ関係、 Chouldechova 2017 の impossibility theorem) → (3) 緩和手法 (pre / in / post-processing) → (4) 影響評価と監査 → (5) ステークホルダー協議、 という社会技術的プロセス。 単一指標最適化は別の不公平を生む。
「公平性」を実際の課題に当てはめるとき、 ラベルの取得可能性・誤判定コストの非対称性・法域要件で判断分岐する。 章 14 で詳述した Demographic Parity / Equalized Odds / Calibration / Counterfactual Fairness の 4 系統への接続を末端で示す。
公平性指標は法域 (EU AI Act / US EEOC 4/5 ルール) と業務 (信用 / 採用 / 司法) で要件が異なるため、 社内 AI 倫理委員会・法務・対象コミュニティと協議し、 主指標 + サブ指標 + 不確実性 (CI) を併記する。 章 14 の SSDSE-B-2026 補講で扱った Demographic Parity Difference (DPD) と Disparate Impact ratio (DI) は段 2 の入口指標として最初に計算する。 FairLearn / AIF360 / What-If Tool 等の OSS で実装を再現可能にする。