我有一个汇总声明如下:
data = data.groupby(['type', 'status', 'name']).agg({
'one' : np.mean,
'two' : lambda value: 100* ((value>32).sum() / reading.mean()),
'test2': lambda value: 100* ((value > 45).sum() / value.mean())
})
我收到 KeyErrors。我已经能够让它适用于一个 lambda 函数,但不能适用于两个。
您需要在
data
中指定要聚合其值的列。
例如,
data = data.groupby(['type', 'status', 'name'])['value'].agg(...)
而不是
data = data.groupby(['type', 'status', 'name']).agg(...)
如果您没有提及列(例如
'value'
),则传递给agg
的字典中的键将被视为列名称。 KeyError
是 Pandas 告诉您它在 DataFrame one
中找不到名为 two
、test2
或 data
的列的方式。
注意:将字典传递给
groupby/agg
已被弃用。相反,接下来您应该传递一个元组列表。每个元组的形式预计为 ('new_column_name', callable)
.
这是可运行的示例:
import numpy as np
import pandas as pd
N = 100
data = pd.DataFrame({
'type': np.random.randint(10, size=N),
'status': np.random.randint(10, size=N),
'name': np.random.randint(10, size=N),
'value': np.random.randint(10, size=N),
})
reading = np.random.random(10,)
data = data.groupby(['type', 'status', 'name'])['value'].agg(
[('one', np.mean),
('two', lambda value: 100* ((value>32).sum() / reading.mean())),
('test2', lambda value: 100* ((value > 45).sum() / value.mean()))])
print(data)
# one two test2
# type status name
# 0 1 3 3.0 0 0.0
# 7 4.0 0 0.0
# 9 8.0 0 0.0
# 3 1 5.0 0 0.0
# 6 3.0 0 0.0
# ...
如果这与您的情况不符,请提供符合您情况的可运行代码。
正如 @unutbu 提到的,问题不在于 lambda 函数的数量,而在于传递给
agg()
的字典中的键不作为列出现在 data
中。 OP似乎尝试使用命名聚合,它将自定义列标题分配给聚合列。一个简单的方法是在聚合后调用 set_axis()
。例如,以下内容产生与 @unutbu 建议的命名聚合相同的输出。
data = (
data.groupby(['type', 'status', 'name'])['value']
.agg(['mean', lambda value: 100* ((value>32).sum() / reading.mean()), lambda value: 100* ((value > 45).sum() / value.mean())])
.set_axis(['one', 'two', 'test2'], axis=1) # <---- rename columns here
)
如果您想为涉及多列的聚合分配自定义名称,这尤其有用,因为
groupby.agg
调用可以正常完成。
N = 100
data = pd.DataFrame({
'type': np.random.randint(2, size=N),
'value1': np.random.randint(50, size=N),
'value2': np.random.randint(50, size=N)
})
reading = np.random.random(10)
x = (
data.groupby('type')
.agg({'value1': [np.mean, lambda value: 100* ((value>32).sum() / reading.mean())],
'value2': lambda value: 100* ((value > 45).sum() / value.mean())})
.set_axis(['one', 'two', 'test2'], axis=1)
)
one two test2
type
0 24.00000 2892.413355 18.627451
1 21.44186 1190.993734 4.589114
要使用命名聚合执行相同操作,需要构建一个复杂的字典,并将其作为 kwargs 传递给
groupby.agg()
。
x = (
data.groupby('type')
.agg(**{'one': ('value1', np.mean),
'two': ('value1', lambda value: 100* ((value>32).sum() / reading.mean())),
'test2': ('value2', lambda value: 100* ((value > 45).sum() / value.mean()))})
)
x.equals(y) # True
我更喜欢接近 R 的 tidyverse 的语法,它提供了很大的灵活性和可读性。您可以通过以下方式应用自定义函数:
# Some input data
df = pd.DataFrame({
'col1': [0, 1, 0, 1, 0],
'col2': [10, 20, 30, 40, 50],
'col3': [100, 200, 300, 400, 500],
})
# Tidyverse-like aggregations
(
df
.groupby('col1')
.agg(
percent_col2_above_30=('col2', lambda x: sum(x>30)/len(x)),
col3_max_divided_by_min=('col3', lambda x: max(x)/min(x))
)
)