简体   繁体   English

如何使用转换条件转换 pandas groupby?

[英]How do I transform a pandas groupby with a condition on the transformation?

I have a dataframe containing session and bid data where there are three columns (of interest): user_id, event and date.我有一个 dataframe 包含 session 和投标数据,其中有三列(感兴趣):用户 ID、事件和日期。

  • user_id is just an ID to identify a user user_id 只是一个标识用户的 ID
  • event is either bid or session事件是出价或 session
  • date is a datetime object日期是日期时间 object

Now what I want to do is add a column to my dataframe that is the date of the first bid.现在我要做的是在我的 dataframe 中添加一列,即第一次投标的日期。 I have tried several ways of getting this to work but the issue is that it is of course very common that the user generated a session before they made a bid.我已经尝试了几种让它工作的方法,但问题是用户在出价之前生成 session 当然很常见。

I have tried in several ways to get a filter to work but it does not seem to work like I think it should.我已经尝试了几种方法来让过滤器工作,但它似乎不像我认为的那样工作。 From the documentation it says "Return a copy of a DataFrame excluding elements from groups that do not satisfy the boolean criterion specified by func."从文档中它说“返回 DataFrame 的副本,不包括不满足 func 指定的 boolean 标准的组中的元素。” which sounds like what I want, ignore the events in the group that are session and not bid.这听起来像我想要的,忽略组中的事件是 session 而不是出价。

df['first bid date'] = df.groupby('user_id').filter(lambda x: x['event'] == 'bid')['date'].transform('min') 

When this did not work I tried to instead have the transform take a custom function, like this:当这不起作用时,我尝试让转换采用自定义 function,如下所示:

def custom_transform(group):
    return group[group['event'] == 'bid']['date'].min()


df['first bid date'] = df.groupby('user_id').['date'].transform(custom_transform)

But this does not work because the transform cannot access both the date and the event at the same time, seemingly no matter what I groupby.但这不起作用,因为转换无法同时访问日期和事件,似乎无论我如何分组。

Finally I tried to group by both the user_id and the event like this最后,我尝试按 user_id 和这样的事件进行分组

df['first bid date'] = df.groupby(['user_id', 'event'])['date'].transform('min')

which kind of works but then I am left with having to change all of the first sessions to the first bid since there is now a first session and a first bid.哪种有效,但是我不得不将所有第一个会话更改为第一个投标,因为现在有第一个 session 和第一个投标。

Any input to make this oneliner work?有什么意见可以让这个 oneliner 工作吗? Seems like a combination of groupby, filter and transform should do the trick but I just can't crack it.似乎 groupby、filter 和 transform 的组合应该可以解决问题,但我就是无法破解它。

Thanks!谢谢!

Idea is replace non matched values to missing values before transform , here by Series.where :想法是在transform不匹配的值替换为缺失值,这里是Series.where

df['first bid date'] = (df.assign(date = df['date'].where(df['event'] == 'bid'))
                          .groupby('user_id')['date']
                          .transform('min'))

Here is some sample code with a dataframe to match the problem.这是一些带有 dataframe 的示例代码来匹配问题。

from io import StringIO

csv = StringIO("""index,uid,event,date
0,1,"bid",'2010-01-01'
1,1,"bid",'2013-01-01'
2,1,"session",'2009-01-01'
3,2,"session",'2010-01-01'
4,2,"bid",'2015-01-01'
5,2,"bid",'2017-01-01'""")

df = pd.read_csv(csv, index_col='index').reset_index(drop=True)

This alternate approach uses the merge function.这种替代方法使用merge function。

df.merge(df[df['event']=='bid'].groupby('uid')['date'].min(),
on='uid', suffixes=('','_first_bid'))

Which prints:哪个打印:

    uid  event    date        date_first_bid
0   1    bid      2010-01-01  2010-01-01
1   1    bid      2013-01-01  2010-01-01
2   1    session  2009-01-01  2010-01-01
3   2    session  2010-01-01  2015-01-01
4   2    bid      2015-01-01  2015-01-01
5   2    bid      2017-01-01  2015-01-01

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM