Pandas rank与transform('rank')的区别

4
我不确定这是一个错误还是一个特性,但我真的想了解它的工作原理。
我有一个非常简单的数据集。
In [0]: data
Out[0]:
  group  value  data
0     A      1     1
1     A      2     1
2     B      3     1
3     B      4     1

然后我还有一些转换:

In [1]: data.groupby('group').transform('rank')
Out[1]:
   value  data
0    1.0   1.5
1    2.0   1.5
2    1.0   1.5
3    2.0   1.5

In [2]: data.groupby('group').value.transform('rank')
Out[2]:
0    1
1    1
2    2
3    2

In [3]: data.groupby('group').data.transform('rank')
Out[3]:
0    1.5
1    1.5
2    1.5
3    1.5

In [4]: data.groupby('group').transform('rank').value
Out[4]:
0    1.0
1    2.0
2    1.0
3    2.0

In [5]: data.groupby('group').value.rank()
Out[5]:
0    1.0
1    2.0
2    1.0
3    2.0

In [6]: data.groupby('group').cumcount()
Out[6]:
0    0
1    1
2    0
3    1

我发现以下几点很奇怪:
  • 第一点。我似乎理解了value列(类似于第五和第六列)发生了什么,但是我不明白data列中的值1.5从哪里来的?
  • 第二点。它不仅选择了指定的列,并应用了类似于第一点的逻辑,而且完全改变了输出。我可以推测现在是在枚举组而不是组内行,但我仍然不明白为什么要这样做?
  • 第三点。它的表现与预期完全一致,只选择了指定的列,并应用了第一点相同的逻辑(与前一个相比)。但我仍然不知道这个值的来源;
  • 第四点。这不应该与第二点相同吗?
  • 第五和第六点看起来完全相同,但后者从0开始。这正确吗?

如果有人能够解释一下,我将非常感激。

谢谢。

2个回答

2

让我再加一点混乱 - rank() 方法有一个 method 参数...

默认值: method='average'

In [70]: data.groupby('group').transform('rank')
Out[70]:
   value  data
0    1.0   1.5
1    2.0   1.5
2    1.0   1.5
3    2.0   1.5

In [71]: data.groupby('group').transform('rank', method='average')
Out[71]:
   value  data
0    1.0   1.5
1    2.0   1.5
2    1.0   1.5
3    2.0   1.5

method: min

In [72]: data.groupby('group').transform('rank', method='min')
Out[72]:
   value  data
0    1.0   1.0
1    2.0   1.0
2    1.0   1.0
3    2.0   1.0

method: max

In [73]: data.groupby('group').transform('rank', method='max')
Out[73]:
   value  data
0    1.0   2.0
1    2.0   2.0
2    1.0   2.0
3    2.0   2.0

method: first

In [74]: data.groupby('group').transform('rank', method='first')
Out[74]:
   value  data
0    1.0   1.0
1    2.0   2.0
2    1.0   1.0
3    2.0   2.0

方法:dense

In [75]: data.groupby('group').transform('rank', method='dense')
Out[75]:
   value  data
0    1.0   1.0
1    2.0   1.0
2    1.0   1.0
3    2.0   1.0

来自文档

method : {average, min, max, first, dense}

average: 组内排名的平均值

min: 组内最低排名

max: 组内最高排名

first: 排名按照数组中出现的顺序分配

dense: 类似于“min”,但组之间始终增加1个排名

还有另一个参数:

pct : 布尔型, 默认为 False

计算数据的百分比排名


这确实让我更加困惑了。但我仍然不明白两件事:1)如何计算“data”列的“1.5”?如何将1和1的平均值变为1.5?2)为什么似乎对“value”和“data”列应用了不同的逻辑? - Viktor Ershov

0
在较新版本的pandas中(我的版本是0.24.2),data.groupby('group').transform('rank')data.groupby('group').value.transform('rank')的行为如下:
In [1]: data.groupby('group').transform('rank')
Out[1]:
   value  data
0    1.0   1.5
1    1.0   1.5
2    2.0   1.5
3    2.0   1.5

In [2]: data.groupby('group').value.transform('rank')
Out[2]:
0    1
1    1
2    2
3    2

回答你的问题:
  • 第一和第三点: rank() 函数的默认 methodaverage,因此数据列得到排名 1.5(最小值=1,最大值=2,平均值=1.5)。
  • 第二和第四点:在 pandas 的后续版本中,data.groupby('group').transform('rank').value 返回与 data.groupby('group').value.transform('rank') 相同的结果。我建议不要同时使用 transform()rank()data.groupby('group').value.rank() 正是你应该使用的。如果你查看 rank() 函数的 源代码,它已经实现了 transform() 的逻辑:广播到整个列。如果你最终使用 transform('rank')rank 函数仍然会起作用,但是 transform 会出错。以下是源代码的简化版本:

    import pandas as pd
    import pandas.core.algorithms as algorithms
    
    g = data.groupby('group')
    result = getattr(g, 'rank')() #same as g.rank()
    ids = g.grouper.group_info[0] #array([0, 0, 1, 1])
    
    output = []
    for i, _ in enumerate(result.columns):
        res = algorithms.take_1d(result.iloc[:, i].values, ids)
        output.append(res) 
        #[array([1., 1., 2., 2.]), array([1.5, 1.5, 1.5, 1.5])]
    pd.DataFrame._from_arrays(output, columns=result.columns, index=g.obj.index)
    #value|data
    #  1  | 1.5
    #  1  | 1.5
    #  2  | 1.5
    #  2  | 1.5
    
  • 第五和第六点: cumcount() 从 0 开始到该组的长度 - 1,rank() 从 1 开始到 n。

希望这能有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接