Fairlearn 中的 API(二)

前言

Fairlearn 是一个旨在帮助数据科学家提高人工智能系统公平性的开源项目。目前国内并没有相关教程来讲解这个库的使用方式,所以笔者用一系列博客尽可能详细地教学 Fairlearn 库的使用方法。「在官网教程的基础上加入自己的个人见解。」

Fairlearn 官网

本篇博客是此系列的第三篇,主要内容是 Fairlearn 中内置的公平性评估方法。

1. Metrics 模块

功能:Metrics 模块提供了评估模型的公平性相关指标的方法。

1.1 非群体性指标 (ungrouped Metrics)

最简单的情况下,评估指标采取的是标签 Y t r u e Y_{true} Ytrue 和预测集 Y p r e d Y_{pred} Ypred 之间的关系。例如真阳性率 T P = P ( Y p r e d = 1 ∣ Y t r u e = 1 ) TP = P(Y_{pred}=1|Y_{true}=1) TP=P(Ypred=1∣Ytrue=1),即预测为正,实际也为正的概率。假阴性率 F N = P Y p e r d = 0 ∣ Y t r u e = 1 FN = P{Y_{perd}=0|Y_{true}=1} FN=PYperd=0∣Ytrue=1 ,即预测为负,实际为正的概率。召回率 R e c a l l = T P T P + F N Recall = \frac{TP}{TP+FN} Recall=TP+FNTP。召回率在代码中的一个具体实现是 sklearn.metrics.recall_score()

代码展示 「Jupyter NoteBook」

import sklearn.metrics as skm
y_true = [0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1]
y_pred = [0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1]
skm.recall_score(y_true,y_pred)

输出结果如下

1.2 群体性指标 (Metrics with grouping)

当考虑到公平时,我们想看到在不同组之间的指标有什么差异,这就涉及到群体性指标。

1.2.1 将数据分组
import numpy as np
import pandas as pd

group_membership_data = ['d', 'a', 'c', 'b', 'b', 'c', 'c', 'c',
                         'b', 'd', 'c', 'a', 'b', 'd', 'c', 'c']
pd.set_option('display.max_columns',20)
pd.set_option('display.width',80)
pd.DataFrame({'y_true':y_true,'y_pred':y_pred,'group_membership_data':group_membership_data})

我们将前一个例子的 y_truey_preda,b,c,d 划分为四个不同的组。

1.2.2 预测组间召回率
from fairlearn.metrics import MetricFrame
grouped_metrics = MetricFrame(metrics= skm.recall_score,y_pred=y_pred,y_true=y_true,sensitive_features=group_membership_data)
print(grouped_metrics.overall)
print(grouped_metrics.by_group)

1.2.3 输出组间统计信息

除了输出各个组件的评估指标,MetricFrame 还支持输出其他统计信息,例如最大最小精度,比例等等

print("min recall over groups = ", grouped_metrics.group_min()) # 最小召回率
print("max recall over groups = ", grouped_metrics.group_max()) # 最大召回率
print("difference in recall = ", grouped_metrics.difference(method='between_groups')) # 组间召回率的最大差异
print("ratio in recall = ", grouped_metrics.ratio(method='between_groups')) # 最小召回率比最大召回率

结果如下:

1.2.4 评估组间的多个指标

上述的例子只展示了召回率这一个指标,实际上 MetricFrame 可以一次评估多个指标

from fairlearn.metrics import count
multi_metrics = MetricFrame({'precision':skm.precision_score,'recall':skm.recall_score,'count':count},y_true=y_true,y_pred=y_pred,sensitive_features=group_membership_data) # precision_score 是差准率,是 TP/TP + TN
print(multi_metrics.overall)
print(multi_metrics.by_group)

结果如下:

1.2.5 带权重的组间评估指标

通常情况下,不同个体的权重是不同的,得到带权重的组间评估指标只需要在 MetricFrame 中多加一个 sample_params 参数

s_w = [1, 2, 1, 3, 2, 3, 1, 2, 1, 2, 3, 1, 2, 3, 2, 3]
s_p = { 'sample_weight':s_w }
weighted_metrics = MetricFrame(metrics=skm.recall_score,
                       y_true=y_true,
                       y_pred=y_pred,
                       sensitive_features=group_membership_data,
                       sample_params=s_p)
print(weighted_metrics.overall)
print(weighted_metrics.by_group)

结果如下:

1.2.6 使用携带参数的评估指标

前面 MetricFrame 使用到的 metrics 都是不携带参数的,如果我们需要使用携带参数的 metric 该怎么办呢?

直接将携带参数的 metric 传给 metrics 会直接报错,如下

解决方法是,用functools.partial()fbeta_scorebeta 参数封装成一个方法,具体如下

import functools

fbeta_06 = functools.partial(skm.fbeta_score, beta=0.6)
metric_beta = MetricFrame(metrics=fbeta_06, y_true=y_true, y_pred=y_pred, sensitive_features=group_membership_data)
print(metric_beta.overall)
print(metric_beta.by_group)

注意:这里回顾一下 fbeta_score,它是召回率和差准率的加权平均。召回率为 r e c a l l recall recall,查准率是 p r e c i s i o n precision precision ,那么 F − B e t a = ( 1 + β 2 ) ⋅ p r e c i s i o n ⋅ r e c a l l ( β 2 ⋅ p r e c i s i o n ) + r e c a l l F-Beta = (1+\beta^2)\cdot\frac{precision\cdot recall}{(\beta^2\cdot precision)+recall} FBeta=(1+β2)(β2precision)+recallprecisionrecall。当 β < 1 \beta < 1 β<1 时,偏向于召回率, β > 1 \beta > 1 β>1 时偏向于查全率。

输出结果如下:

1.2.7 多敏感属性的评估

前面,我们只使用了单个敏感属性,如果我们需要用多个敏感属性,该如何实现呢?

g_2 = [ 8,6,8,8,8,8,6,6,6,8,6,6,6,6,8,6]
s_f_frame = pd.DataFrame(np.stack([group_membership_data,g_2],axis=1),columns=['SX 0','SX 1'])
metric_2_f = MetricFrame(metrics=skm.recall_score,y_pred=y_pred,y_true=y_true,sensitive_features=s_f_frame)
print(metric_2_f.overall)
print(metric_2_f.by_group)

输出结果如下:

上述代码中,我们唯一需要了解的是 np.stack() 方法,它用于将两个相同维度 array() 在某一维度上合并**「axis = 0 按 x 轴,axis = 1 按 y 轴」。**

a = np.array([1,2,3])
b = np.array([4,5,6])
np.stack([a,b],axis=1)

合并结果如下:

1.3 来自 MetricFrame 的标量结果 (Scalar Results from MetricFrame)

高级的机器学习算法通常使用度量函数来指导它们的优化。这样的算法通常和标量结果一起工作,所以如果我们希望根据公平性指标进行调优,就要在 MetricFrame 上执行聚合。

这一小节,我们用 fairlearn 提供的 make_derived_metric 方法来自定义 metric 。通过 make_derived_metric 基于四种基本 metric 来自定义,它们分别是 group_mingroup_maxdifferenceratio「四选一」

from fairlearn.metrics import make_derived_metric
fbeta_difference = make_derived_metric(metric=skm.fbeta_score,transform='difference') # 选择的 Base Metric 是 differebce,即最大 F_Beta 与最小 F_Beta 的差
fbeta_difference(y_true,y_pred,beta=0.7,sensitive_features = group_membership_data)

输出结果如下:

上述方法可以用以下代码来替代,区别是后者需要使用 functools.partial

fbeta_07 = functools.partial(skm.fbeta_score, beta=0.7)
fbeta_07_metrics = MetricFrame(metrics=fbeta_07, y_true=y_true, y_pred=y_pred, sensitive_features=group_membership_data)
fbeta_07_metrics.difference()

个人感觉下面的方法更好,因为它可以很方便的调用其他方法。

1.4 组间指标的控制属性 ( Control features for grouped metrics)

控制属性也称为条件属性,通过提供将数据分成子组的进一步方法,实现更加详细的公平性洞察。当数据被划分为子组时,控制属性的作用类似于敏感属性。不同的是,度量的 overall 值是在控制属性划分的各个子组上进行的**「其他方法如 group_maxgroup_min也是如此」**。

控制属性对于属性的一些预期变化情况是有用的,所以我们需要在控制属性的同时计算差异。例如,在一个贷款场景中,我们希望不同收入的人以不同的利率获得批准。但是,在每个收入阶层中,我们仍然希望测量不同敏感特征之间的差异。

在 MetricFrame 的一个构造方法中,提供了 control_features 参数。

decision = [
   0,0,0,1,1,0,1,1,0,1,
   0,1,0,1,0,1,0,1,0,1,
   0,1,1,0,1,1,1,1,1,0
]
prediction = [
   1,1,0,1,1,0,1,0,1,0,
   1,0,1,0,1,1,1,0,0,0,
   1,1,1,0,0,1,1,0,0,1
]
control_feature = [
   'H','L','H','L','H','L','L','H','H','L',
   'L','H','H','L','L','H','L','L','H','H',
   'L','H','L','L','H','H','L','L','H','L'
]
sensitive_feature = [
   'A','B','B','C','C','B','A','A','B','A',
   'C','B','C','A','C','C','B','B','C','A',
   'B','B','C','A','B','A','B','B','A','A'
]
metric_c_f = MetricFrame(metrics=skm.accuracy_score,
                         y_true=decision,
                         y_pred=prediction,
                         sensitive_features={'SF' : sensitive_feature},
                         control_features={'CF' : control_feature})
print(metric_c_f.overall)
print(metric_c_f.by_group)

结果如下:

对于控制属性我是这么理解的,当我们需要比较不同组之间的差异时使用敏感属性,如不同地区人民的收入水平。但如果我们想看组内不同小群体,如某地区的男性和女性收入水平时,就可以用到控制属性。

1.5 绘制群体性指标图

1.5.1 基本绘制方法

绘图主要用到 MetricFrame 的 plot 方法,它内部调用了 matplotlib

from fairlearn.metrics import false_positive_rate, true_positive_rate, selection_rate
from sklearn.metrics import accuracy_score, recall_score, precision_score

metrics = {
    'accuracy': accuracy_score,
    'precision': precision_score,
    'recall': recall_score,
    'false positive rate': false_positive_rate,
    'true positive rate': true_positive_rate,
    'selection rate': selection_rate,
    'count': count}
metric_frame = MetricFrame(metrics=metrics,
                           y_true=y_true,
                           y_pred=y_pred,
                           sensitive_features=group_membership_data)
metric_frame.by_group.plot.bar(
    subplots=True,
    layout=[3, 3],
    legend=False,
    figsize=[12, 8],
    title="Show all metrics",
)

1.5.2 修改统一的 ylim

在上一小节的图中,我们可以看出,不同的图 y 轴的范围是不同的,如果我们需要让它们的范围一致(方便比较),可以使用 plot() 方法中规定 ylim 参数来调节。

metric_frame.by_group.plot.bar(
    subplots=True,
    ylim=[0,1],
    layout=[3, 3],
    legend=False,
    figsize=[12, 8],
    title="Show all metrics",
)

结果如下:

1.5.3 修改绘图的色系

到这里,可能有人要吐槽,上面的图选的什么阴间配色!!就不能自己选好看的颜色画吗?

这一点,matplotlib 在设计时就有考虑到,我们可以通过 colormap 参数来调节。更多好康的色系可以参考这里: 好康的色系

这里我们选用 accent 色系

metric_frame.by_group.plot.bar(
    subplots=True,
    ylim=[0,1],
    layout=[3, 3],
    legend=False,
    figsize=[12, 8],
    colormap = 'Accent',
    title="Show all metrics",
)

结果如下:

1.5.4 定义绘制图的样式

到这里,可能小伙伴们又要问了,你这画的都是柱状图啊,只能画柱状图也太垃了吧!!

唉~~,作为一个专业的机器学习公平库,fairlearn 怎么可能没考虑到这点呢?**「其实是 Pandas 考虑到的」**我们可以通过 kind 参数来调节绘图的类型

metric_frame.by_group.plot(
    kind = 'pie',
    subplots=True,
    ylim=[0,1],
    layout=[3, 3],
    legend=False,
    figsize=[12, 8],
    colormap = 'Accent',
    title="Show all metrics",
)

结果如下:

那我们该怎么知道有哪些图形可以画呢?可以参考如下链接: 可绘制的类型

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值