多评估者数据的评估者间可靠性计算

Inter-rater reliability calculation for multi-raters data

我有以下列表:

[[1, 1, 1, 1, 3, 0, 0, 1],
 [1, 1, 1, 1, 3, 0, 0, 1],
 [1, 1, 1, 1, 2, 0, 0, 1],
 [1, 1, 0, 2, 3, 1, 0, 1]]

在我想计算 inter-rater 可靠性分数的地方,有多个评分者(行)。我不能使用 Fleiss 的 kappa,因为行的总和不等于相同的数字。在这种情况下,什么是好的方法?

这里的基本问题是您没有正确应用所提供的数据。有关正确的组织,请参阅 here。您有四个类别(评分 0-3)和八个科目。因此,无论审稿人的数量有多少,您的 table 必须有八行和四列。例如,第一行是对第一项的评分统计:

[0, 4, 0, 0]   ... since everyone rated it a `1`.

您的 -inf 值来自倒数第二列的 P[j] 分数除以 0。


我之前的回答,标准化分数,是基于 对 Fleiss 的误解;我有不同的可靠性。 有很多方法可以计算这样的指标;一个是相对评分的一致性(可以通过归一化获得);另一种是将每个评分者的行转换为相对排名的图表,并计算这些图表之间的相似度。

请注意,Fleiss 完全适用于具有相对指标的 rating 情况:它假定这是分类任务,而不是排名。 Fleiss 对收视率的差距并不敏感。它只知道评级不同:(0,1) 配对与 (0,3) 配对一样具有破坏性。

这个问题的一个答案是使用 krippendorff alpha 分数:

Wikipedia Description

Python Library

import krippendorff

arr = [[1, 1, 1, 1, 3, 0, 0, 1],
       [1, 1, 1, 1, 3, 0, 0, 1],
       [1, 1, 1, 1, 2, 0, 0, 1],
       [1, 1, 0, 2, 3, 1, 0, 1]]    
res = krippendorff.alpha(arr)

是的,数据准备是这里的关键。让我们一起走过它。

虽然 Krippendorff 的 alpha 可能出于多种原因而更优越,但 numpy 和 statsmodels 提供了从上述 table 中获取 Fleiss kappa 所需的一切。 Fleiss 的 kappa 在医学研究中更为普遍,尽管 Krippendorff alpha 提供的结果基本相同如果使用得当。如果它们提供的结果大不相同,这可能是由于许多用户错误造成的,最重要的是 输入数据的格式和测量级别(例如,序数与标称) – 跳过解决方案(转置和聚合):Fleiss kappa 0.845

密切注意哪个轴代表 主题、评分者或类别!

弗莱斯河童

statsmodels.stats import inter_rater as irr

原始数据的行是评分者,列是受试者,整数代表分配的类别(如果我没记错的话)。

我删除了一行,因为有 4 行和 4 个类别,这可能会混淆情况 – 所以现在我们有 4 [0,1,2,3] 个类别和 3 行。

orig = [[1, 1, 1, 1, 3, 0, 0, 1],
        [1, 1, 1, 1, 3, 0, 0, 1],
        [1, 1, 1, 1, 2, 0, 0, 1]] 

来自 aggregate_raters() 函数的文档

"将形状为 (subject, rater) 的原始数据转换为 (subject, cat_counts)"

irr.aggregate_raters(orig)

这个returns:

(array([[2, 5, 0, 1],
        [2, 5, 0, 1],
        [2, 5, 1, 0]]),
array([0, 1, 2, 3]))

现在……orig 数组中的行数等于第一个返回数组 (3) 中的行数。列数现在等于类别数 ([0,1,2,3] -> 4)。每行的内容加起来为 8,等于 orig 输入数据中的列数 - 假设每个评分者都对每个主题进行评分。此聚合显示评分者如何分布在每个主题(行)的类别(列)中。 (如果在类别 2 上达成一致,我们将看到 [0,0,8,0];或类别 0 [8,0,0,0]。

该函数需要行作为主题。查看受试者数量如何没有变化(3 行)。对于每个主题,它计算每个类别被分配的次数 'looking' 在行中找到类别(数字)的次数。对于第一行或类别,0 被分配了两次,1 分配了五次,2 none,3 分配了一次

[1, 1, 1, 1, 3, 0, 0, 1] -> [2, 5, 0, 1]

第二个数组returns类别值。如果我们将输入数组中的两个 3 都替换为 9,则分布看起来相同,但最后一个类别已更改。

ori9 = [[1, 1, 1, 1, 9, 0, 0, 1],
        [1, 1, 1, 1, 9, 0, 0, 1],
        [1, 1, 1, 1, 2, 0, 0, 1]] 
(array([[2, 5, 0, 1],
        [2, 5, 0, 1],
        [2, 5, 1, 0]]),
array([1, 2, ,3, 9]))      <- categories

aggregate_raters() returns ([data], [categories])

的元组

在 [data] 中,行保持主题。 aggregate_raters() 将评分者的列转换为类别。 Fleiss 期望 'table' 数据采用这种(主题、类别)格式:https://en.wikipedia.org/wiki/Fleiss'_kappa#Data

现在开始解决问题:

如果我们将原始数据插入 Fleiss kappa 会发生什么: (我们只使用数据 'dats' 而不是类别列表 'cats')

dats, cats = irr.aggregate_raters(orig)
irr.fleiss_kappa(dats, method='fleiss')

-0.12811059907834096

但是……为什么?好吧,看看 orig 数据 – aggregate_raters() 假设 raters 作为列 !这意味着我们 完全不一致 例如在第一列和倒数第二列之间——Fleiss 认为:“第一个评分者总是评分为“1”,倒数第二个评分者总是评分为“0”-> 在所有三个主题上完全不一致。

所以我们需要做的是(抱歉我是菜鸟——可能不是最优雅的):

giro = np.array(orig).transpose()
giro
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1],
       [1, 1, 1],
       [3, 3, 2],
       [0, 0, 0],
       [0, 0, 0],
       [1, 1, 1]]) 

现在我们将主题作为行,将评估者作为列(三个评估者分配 4 个类别)。如果我们将其插入 aggregate_raters() 函数并将结果数据输入 fleiss 会发生什么? (使用索引 0 获取返回元组的第一部分)

irr.fleiss_kappa(irr.aggregate_raters(giro)[0], method='fleiss')

0.8451612903225807

最后......这更有意义,如果除了主题 5 [3, 3, 2] 之外,所有三位评分者都完全同意。

Krippendorff 的阿尔法

当前的 krippendorff 实现需要 orig 格式的数据,其中评估者作为行,列作为主题——准备数据不需要聚合函数。所以我可以看到这是一个更简单的解决方案。 Fleiss 在医学研究中仍然非常普遍,所以让我们看看它的比较:

import krippendorff as kd
kd.alpha(orig)

0.9359

哇……比 Fleiss 的 kappa 高很多……好吧,我们需要告诉 Krippendorff ”史蒂文对变量的测量水平。它必须是 'nominal' 之一, 'ordinal', 'interval', 'ratio' 或可调用的。 – 这是 Krippendorff 阿尔法的 'difference function'。 https://repository.upenn.edu/cgi/viewcontent.cgi?article=1043&context=asc_papers

kd.alpha(orig, level_of_measurement='nominal')

0.8516

希望这对您有所帮助,我在写这篇文章时学到了很多东西。