Python 一次计算两个值的GroupBy聚合函数
我有一个类似于以下的datafame:Python 一次计算两个值的GroupBy聚合函数,python,pandas,pandas-groupby,aggregate,Python,Pandas,Pandas Groupby,Aggregate,我有一个类似于以下的datafame: import pandas as pd df = pd.DataFrame({ 'A': [1, 1, 1, 2, 2, 2], 'B': [1, 2, 3, 4, 5, 6], 'C': [4, 5, 6, 7, 8, 9], }) expected = df.groupby('A').agg([min, max]) # B C # min max min max # A
import pandas as pd
df = pd.DataFrame({
'A': [1, 1, 1, 2, 2, 2],
'B': [1, 2, 3, 4, 5, 6],
'C': [4, 5, 6, 7, 8, 9],
})
expected = df.groupby('A').agg([min, max])
# B C
# min max min max
# A
# 1 1 3 4 6
# 2 4 6 7 9
现在我想对每个组生成两个值进行分组和聚合。结果应与以下类似:
import pandas as pd
df = pd.DataFrame({
'A': [1, 1, 1, 2, 2, 2],
'B': [1, 2, 3, 4, 5, 6],
'C': [4, 5, 6, 7, 8, 9],
})
expected = df.groupby('A').agg([min, max])
# B C
# min max min max
# A
# 1 1 3 4 6
# 2 4 6 7 9
但是,在我的例子中,我没有使用两个不同的函数min
和max
,而是使用一个函数同时计算这两个值:
def minmax(x):
"""This function promises to compute the min and max in one go."""
return min(x), max(x)
现在我的问题是,如何使用这个函数为每个组生成两个聚合值
这有点像,但我不知道怎么做。我能想到的最好方法是使用双重嵌套的apply
,但是这不是很优雅,而且它会在行而不是列上生成多索引:
result = df.groupby('A').apply(
lambda g: g.drop(columns='A').apply(
lambda h: pd.Series(dict(zip(['min', 'max'], minmax(h))))
)
)
# B C
# A
# 1 min 1 4
# max 3 6
# 2 min 4 7
# max 6 9
另一个解决方案:
pd.concat({k:d.agg(minmax).set_axis(['min','max'])
for k,d in df.drop('A',axis=1).groupby(df['A'])
})
输出:
B C
1 min 1 4
max 3 6
2 min 4 7
max 6 9
另一个解决方案:
pd.concat({k:d.agg(minmax).set_axis(['min','max'])
for k,d in df.drop('A',axis=1).groupby(df['A'])
})
输出:
B C
1 min 1 4
max 3 6
2 min 4 7
max 6 9
如果您一直使用返回值的
元组的函数。我想:
定义一个新函数,将元组
值包装到dict
中,以便预定义dict.keys()
以与您希望的列名对齐
对
循环使用谨慎的,不要浪费时间和空间
包裹函数
小心进行循环
我的目标是将此字典传递到pd.DataFrame
构造函数中。这意味着,我希望键中的多索引
列元素的元组。我希望值是字典,键是索引元素
dat = {}
for a, d in df.set_index('A').groupby('A'):
for cn, c in d.iteritems():
for k, v in minmax_dict(c).items():
dat.setdefault((cn, k), {})[a] = v
pd.DataFrame(dat).rename_axis('A')
B C
min max min max
A
1 1 3 4 6
2 4 6 7 9
补充细节
看看这本特制的词典
data
{('B', 'min'): {1: 1, 2: 4},
('B', 'max'): {1: 3, 2: 6},
('C', 'min'): {1: 4, 2: 7},
('C', 'max'): {1: 6, 2: 9}}
如果您一直使用返回值的元组的函数。我想:
定义一个新函数,将元组
值包装到dict
中,以便预定义dict.keys()
以与您希望的列名对齐
对
循环使用谨慎的,不要浪费时间和空间
包裹函数
小心进行循环
我的目标是将此字典传递到pd.DataFrame
构造函数中。这意味着,我希望键中的多索引
列元素的元组。我希望值是字典,键是索引元素
dat = {}
for a, d in df.set_index('A').groupby('A'):
for cn, c in d.iteritems():
for k, v in minmax_dict(c).items():
dat.setdefault((cn, k), {})[a] = v
pd.DataFrame(dat).rename_axis('A')
B C
min max min max
A
1 1 3 4 6
2 4 6 7 9
补充细节
看看这本特制的词典
data
{('B', 'min'): {1: 1, 2: 4},
('B', 'max'): {1: 3, 2: 6},
('C', 'min'): {1: 4, 2: 7},
('C', 'max'): {1: 6, 2: 9}}
解决方案应等同于df.groupby('A').agg([min,max])
,即多索引应位于列上。此外,在组上循环与在groupby对象上使用apply
没有太大区别,是吗?使用unstack链接解决方案,您应该获得所需的格式。是的,它等同于应用。最后一个建议和@piRSqaured一样,避免使用minmax函数使用unstack
提供了一个几乎相同的解决方案,唯一的区别是未命名的索引。我的问题中使用的示例可能有点误导,因为它由两个不同的函数组成。在我的用例中,我有一个函数myfunc
,它不能简单地分成两个函数。唯一的方法是df.groupby('A').agg([lambda x:myfunc(x)[0],lambda x:myfunc(x)[1]])
,但是myfunc
的计算成本不低,因此这会浪费大量的计算能力。如果需要名称,请在取消堆栈后将其与rename_axis('A')
链接。好的,这正是我来这里问这个问题的原因,因为堆叠和嵌套这么多函数调用已经不再是真正可读的了。所以我希望有一个更干净的解决方案。无论如何,谢谢你的回答。顺便说一下,您应该更新它以匹配问题的预期结果。解决方案应该相当于df.groupby('A').agg([min,max])
,即多索引应该位于列上。此外,在组上循环与在groupby对象上使用apply
没有太大区别,是吗?使用unstack链接解决方案,您应该获得所需的格式。是的,它等同于应用。最后一个建议和@piRSqaured一样,避免使用minmax函数使用unstack
提供了一个几乎相同的解决方案,唯一的区别是未命名的索引。我的问题中使用的示例可能有点误导,因为它由两个不同的函数组成。在我的用例中,我有一个函数myfunc
,它不能简单地分成两个函数。唯一的方法是df.groupby('A').agg([lambda x:myfunc(x)[0],lambda x:myfunc(x)[1]])
,但是myfunc
的计算成本不低,因此这会浪费大量的计算能力。如果需要名称,请在取消堆栈后将其与rename_axis('A')
链接。好的,这正是我来这里问这个问题的原因,因为堆叠和嵌套这么多函数调用已经不再是真正可读的了。所以我希望有一个更干净的解决方案。无论如何,谢谢你的回答。顺便问一下,你应该更新它以匹配问题的预期结果。通过“不要那样做”,你指的是你的答案还是我的目标?我还应该注意到,解决方案应该比简单的df.groupby('A').agg([lambda x:minmax(x)[0],lambda x:minmax(x)[1]])更有效。
。当然,为了对此进行基准测试,我需要提供一个更复杂的数据帧以及一个更有用的minmax
实现。当您建议我不应该这样做时,可能会有误解,因为我没有太多选择。为了简化示例,我使用了minmax
函数,但实际上我有一个函数不能简单地拆分为多个其他函数。事实上,我的函数将每组的数据拟合到一个模型中,然后返回一组拟合参数及其误差估计值(因此实际上不止两个)。生成的数据框应该包含每个组的参数估计值。啊,那就是mak