Python Pandas: 使用聚合函数和apply函数定义新列

5
假设我有一个如下的数据框:
n = 20
dim1 = np.random.randint(1, 3, size=n)
dim2 = np.random.randint(3, 5, size=n)
data1 = np.random.randint(10, 20, size=n)
data2 = np.random.randint(1, 10, size=n)
df = pd.DataFrame({'a': dim1, 'b': dim2 ,'val1': data1, 'val2': data2})

如果我定义一个返回分组的函数:
def h(x):
    if x['val2'].sum() == 0:
        return 0
    else:
        return (x['val1'].sum())*1.0/x['val2'].sum()*1.0

按照其中一列进行分组并聚合,得到以下结果:

df.groupby(['a']).aggregate(h)['val1']

虽然它将所有现有的列转换为所需的结果,而不是添加新的列

按两个列进行分组在使用聚合时会导致错误:

df.groupby(['a','b']).aggregate(h)['val1']

KeyError: 'val2'

但是将aggregate更改为apply似乎起作用了。

我有两个问题:

  1. 为什么apply能够工作而aggregate不行?
  2. 如果在按一些键分组一个数据框之后,我想使用一个函数将组值聚合为一个新列,最好的方法是什么?

提前感谢。


好问题。实际上,如果你定义一些测试函数,例如“def test(x):print x;return x.sum()”,并在两种情况下调用“aggregate”,你会发现在第一种情况下,“x”是DataFrame,在第二种情况下,“x”是Series(当你调用“apply”时,它始终是DataFrame)。我暂时没有时间深入研究代码,并且我相信一些pandas开发人员会出现并解释这种行为 :) - Roman Pekar
不确定你在第二个问题中想要什么(也许是cumcount吗?) - Andy Hayden
我一直在努力理解这些groupby操作的确切情况。正如Roman所指出的,传递给agg的第一个参数是Series,因此如果您想基于多个列中的值进行聚合,则必须根据自动传递的Series的索引值调用函数中的第二列。正如他所指出的,apply始终会将DataFrame作为传递的数据帧。如果您想查看一些非常奇怪的行为,请查看transform,它似乎将Series和DataFrame作为函数的第一个参数传递。我认为相当令人困惑。 - Woody Pride
1个回答

0
稍微退后一步,实现此特定"聚合"的更快方法是只需使用sum(它在Cython中进行了优化)几次。
In [11]: %timeit g.apply(h)
1000 loops, best of 3: 1.79 ms per loop

In [12]: %timeit g['val1'].sum() / g['val2'].sum()
1000 loops, best of 3: 600 µs per loop

在我看来,groupby 代码相当复杂,通常会懒惰地“黑盒子”窥视正在发生的事情,通过创建一个值列表来查看它正在看到的内容:

def h1(x):
   a.append(x)
   return h(x)
a = []

警告:有时此列表中的数据类型不一致(在pandas尝试几种不同的方法之后才进行任何计算)... 就像这个例子一样!

第二个聚合在每个列上应用时会卡住,因此该组(引发错误):

0     10
4     16
8     13
9     17
17    17
19    11
Name: val1, dtype: int64

这是 val1 列的子序列,其中(a, b)=(1, 3)。

这可能是一个错误,在此之后,也许可以尝试其他方法(我怀疑这就是为什么第一个版本运行正常的原因,它被特殊处理了)...

对于那些感兴趣的人,我得到的 a 是:

In [21]: a
Out[21]: 
[SNDArray([125755456, 131767536,        13,        17,        17,        11]),
 Series([], name: val1, dtype: int64),
 0     10
4     16
8     13
9     17
17    17
19    11
Name: val1, dtype: int64]

我完全不知道SNDArray是什么意思...


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