Pandas GroupBy.apply 方法复制第一组
- 2025-01-10 08:47:00
- admin 原创
- 104
问题描述:
我的第一个 SO 问题:我对 pandas (0.12.0-4) 中 groupby 的 apply 方法的这种行为感到困惑,它似乎将函数 TWICE 应用于数据框的第一行。例如:
>>> from pandas import Series, DataFrame
>>> import pandas as pd
>>> df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]})
>>> print(df)
class count
0 A 1
1 B 0
2 C 2
我首先检查 groupby 函数是否工作正常,并且它看起来没什么问题:
>>> for group in df.groupby('class', group_keys = True):
>>> print(group)
('A', class count
0 A 1)
('B', class count
1 B 0)
('C', class count
2 C 2)
然后我尝试使用 groupby 对象上的 apply 执行类似操作,并两次获得第一行输出:
>>> def checkit(group):
>>> print(group)
>>> df.groupby('class', group_keys = True).apply(checkit)
class count
0 A 1
class count
0 A 1
class count
1 B 0
class count
2 C 2
任何帮助都将不胜感激!谢谢。
编辑:@Jeff 在下面提供了答案。我很笨,没有立即理解,因此这里有一个简单的示例来说明,尽管上例中第一组的打印输出重复,但 apply 方法仅对第一组执行一次,并且不会改变原始数据框:
>>> def addone(group):
>>> group['count'] += 1
>>> return group
>>> df.groupby('class', group_keys = True).apply(addone)
>>> print(df)
class count
0 A 1
1 B 0
2 C 2
但是通过将方法的返回分配给一个新对象,我们看到它按预期工作:
>>> df2 = df.groupby('class', group_keys = True).apply(addone)
>>> print(df2)
class count
0 A 2
1 B 1
2 C 3
解决方案 1:
这是设计使然,如此处和此处所述
该apply
函数需要知道返回数据的形状,以便智能地确定如何组合数据。为此,它会调用该函数(checkit
在您的例子中)两次来实现这一点。
根据实际使用情况,你可以将对的调用替换apply
为aggregate
、transform
或filter
,如此处详细描述的那样。这些函数要求返回值为特定形状,因此不要调用该函数两次。
但是 - 如果您调用的函数没有副作用,那么在第一个值上调用该函数两次很可能并不重要。
解决方案 2:
此“问题”现已修复:升级至 0.25+
从 v0.25 开始,GroupBy.apply()
只会对第一组进行一次评估。请参阅GH24748。
0.25.0(2019 年 7 月 18 日)中的新功能:仅对第一组进行一次Groupby.apply
评估DataFrame
文档中的相关示例:
pd.__version__
# '0.25.0.dev0+590.g44d5498d8'
df = pd.DataFrame({"a": ["x", "y"], "b": [1, 2]})
def func(group):
print(group.name)
return group
新行为(> = v0.25):
df.groupby('a').apply(func)
x
y
a b
0 x 1
1 y 2
旧行为(<=v0.24.x):
df.groupby('a').apply(func)
x
x
y
a b
0 x 1
1 y 2
Pandas 仍然使用第一个组来确定是否apply
可以采取快速路径。但至少它不再需要对第一个组进行两次评估。干得好,开发人员!
解决方案 3:
您可以使用 for 循环来避免 groupby.apply 重复第一行,
日志样本.csv
guestid,keyword
1,null
2,null
2,null
3,null
3,null
3,null
4,null
4,null
4,null
4,null
我的代码片段
df=pd.read_csv("log_sample.csv")
grouped = df.groupby("guestid")
for guestid, df_group in grouped:
print(list(df_group['guestid']))
df.head(100)
输出
[1]
[2, 2]
[3, 3, 3]
[4, 4, 4, 4]