Python “我该怎么做?”;“重新分组”;在SeriesGroupBy上执行apply()后我的系列?

Python “我该怎么做?”;“重新分组”;在SeriesGroupBy上执行apply()后我的系列?,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我需要修改一个现有函数,它基本上执行一个Series.str.contains并返回结果Series,以便能够将SeriesGroupBy作为输入处理 如错误消息所示 无法访问“SeriesGroupBy”对象的属性“str”,请尝试使用“apply”方法 我曾尝试在SeriesGroupBy对象上使用apply(),它在某种程度上起作用,但会产生一个Series对象。现在,我想对这个系列应用与以前相同的分组 原函数 def包含(系列、表达式): return series.str.contai

我需要修改一个现有函数,它基本上执行一个
Series.str.contains
并返回结果
Series
,以便能够将
SeriesGroupBy
作为输入处理

如错误消息所示

无法访问“SeriesGroupBy”对象的属性“str”,请尝试使用“apply”方法

我曾尝试在
SeriesGroupBy
对象上使用
apply()
,它在某种程度上起作用,但会产生一个
Series
对象。现在,我想对这个
系列
应用与以前相同的分组

原函数

def包含(系列、表达式):
return series.str.contains(表达式)
我迄今为止的努力

>>将熊猫作为pd导入
... 从functools导入部分
...
... 定义f(系列、表达式):
...     return series.str.contains(表达式)
...
... def包含(分组_系列,表达式):
...     结果=分组的_系列。应用(部分(_f,表达式=表达式))
...     返回结果
>>>df=pd.DataFrame(zip([1,1,2,2],'abc','def','abq','bcq']),columns=['group','text'])
>>>gdf=df.groupby('group')
>>>gs=gdf['text']
>>>类型(gs)
>>>r=包含(gdf['text'],'b')
>>>r
0对
1错误
2正确
3正确
名称:text,数据类型:bool
>>>类型(r)
所需的结果将由一个布尔序列组成,该序列按与原始
分组的\u序列相同的索引进行分组

实际结果是一个没有任何分组的
系列
对象

编辑/澄清:

最初的答案让我觉得我没有充分强调问题的核心。为了回答这个问题,假设我不能更改
包含(分组的_系列,表达式)
函数之外的任何内容。 我想如果我从另一个角度看待问题,我知道如何解决问题,如果我不这样做,那将成为另一个问题。现实世界的环境使得在一个函数之外更改代码变得非常复杂。因此,我非常感谢在这一限制范围内有效的建议

因此,让我将问题重新表述如下:

我正在寻找一个函数
包含(分组的_系列,表达式)
,这样下面的代码就可以工作了:

df=pd.DataFrame(zip([1,1,2,2],'abc','def','abq','bcq']),columns=['group','text']) >>>grouped_series=contains(df.groupby('group')['text'],'b')) >>>分组_系列.sum() 组 1 1.0 2 2.0 名称:text,数据类型:float64
您可以这样做。不需要分组

df['eval']= df['text'].str.contains('b')
eval
是要添加的列的名称。你可以说出你想要的名字

df.groupby('group')['eval'].sum()
在第一行之后运行这个。结果是

group
1    1.0
2    2.0

按照错误消息的建议,您可以使用
apply

df.groupby('group').apply(lambda x : x.text.str.contains('b'))
Out[10]: 
group   
1      0     True
       1    False
2      2     True
       3     True
Name: text, dtype: bool
如果要将这些索引放入数据集中并返回数据帧,请使用
reset\u index

df.groupby('group').apply(lambda x : x.text.str.contains('b')).reset_index()
Out[11]: 
   group  level_1   text
0      1        0   True
1      1        1  False
2      2        2   True
3      2        3   True

groupby
是不需要的,除非您想对“组”执行某些操作,例如计算其总和或检查组中的所有行是否都包含字母
b
。在
GroupBy
对象上调用
apply
时,可以通过关键字将附加参数传递给要应用的函数:

def contains(frame, expression):
    return frame['text'].str.contains(expression).all()

df.groupby('group').apply(contains, expression='b')
结果:

group
1    False
2    True
dtype: bool
我喜欢认为所应用函数的第一个参数(
frame
)是原始数据帧的较小视图,由
groupby
子句分割


也就是说,
apply
与专门的聚合函数
min
max
sum
相比速度非常慢。尽可能多地使用这些方法,并保存
对复杂情况应用
\u f
与组绝对没有关系。处理这个问题的方法是在分组之前定义一列(不是单独的函数),然后分组。现在,该列(称为“to_sum”
)是您的
系列.GroupBy
对象的一部分

df.assign(to_sum = _f(df['text'], 'b')).groupby('group').to_sum.sum()
#group
#1    1.0
#2    2.0
#Name: to_sum, dtype: float64
如果后续操作不需要整个数据帧,则可以使用
df
\u f
返回的序列相加到组中(因为它们将共享相同的索引)


例如,索引应该是
[0,1,0,1]
?我不太明白。如果您的
GroupBy
聚合为每个组返回一个值,则输出是一个以组键为索引的系列(想想
GroupBy.sum
)。但是,如果返回值是组内每行一个值,则在组内进行计算,但返回一个带有原始索引的序列(想想
GroupBy.cumsum
)。您当前的公式与后一个公式类似,其中实际上没有特定于计算的组。@ALollz问题是,
包含的
函数不知道聚合。它只需返回一个
SeriesGroupBy
,然后稍后的函数将“决定”(可能在运行时)如何聚合结果(例如,计算
包含的每个组的所有行()
返回的
True
)。如果可能的话,我想在不改变流程的情况下实现它。@Josmoor98问得好,我实际上不知道SeriesGroupBy对象上的索引是什么样子的。(这可能是我挣扎的部分原因。)@MatthiasManhertz据我所知,唯一能返回
系列的东西是
.GroupBy
。此时,您唯一的选择是
应用
agg
转换
或迭代组。因为您的函数不知道分组,所以绝对没有理由让它成为groupby的一部分。您应该在分组之前定义此列,然后创建
Series.GroupBy
对象。似乎我在最初的问题中没有明确指出,我不能(不想)更改
_f(df['text'], 'b').groupby(df['group']).sum()