在Pandas中,如何分组并应用/转换到每一个整体组(而不是聚合)?

wgxvkvu9  于 2022-12-25  发布在  其他
关注(0)|答案(2)|浏览(187)

在groupby之后,我研究了agg/apply/transform,但似乎没有一个能满足我的需要,下面是一个DF示例:

df_seq = pd.DataFrame({
    'person':['Tom', 'Tom', 'Tom', 'Lucy', 'Lucy', 'Lucy'],
    'day':[1,2,3,1,4,6],
    'food':['beef', 'lamb', 'chicken', 'fish', 'pork', 'venison']
})

person,day,food
Tom,1,beef
Tom,2,lamb
Tom,3,chicken
Lucy,1,fish
Lucy,4,pork
Lucy,6,venison

day列显示,对于每个person,他/她按顺序消费食物。

现在我想按person列分组,并创建一个包含两个相邻日期/时间的食物对的DataFrame(如下所示)
请注意,day列在此仅用于示例目的,因此不应使用其值。* 这仅意味着food列是按顺序排列的。在我的真实的数据中,它是日期时间列。*

person,day,food,food_next
Tom,1,beef,lamb
Tom,2,lamb,chicken
Lucy,1,fish,pork
Lucy,4,pork,venison

目前,我只能使用for循环来遍历所有用户,速度非常慢。
是否可以使用groupby和apply/transform来实现此操作或任何矢量化操作?

jvlzgdj9

jvlzgdj91#

DataFrameGroupBy.shift创建新列,然后按DataFrame.dropna删除food_next中缺少值的行:

df = (df_seq.assign(food_next = df_seq.groupby('person')['food'].shift(-1))
            .dropna(subset=['food_next']))
print (df)
  person  day  food food_next
0    Tom    1  beef      lamb
1    Tom    2  lamb   chicken
3   Lucy    1  fish      pork
4   Lucy    4  pork   venison
mccptt67

mccptt672#

这可能是一个稍微不完整的答案,并且它不执行标准意义上的聚合。
首先,一个小的查询函数,给定名称和日期,将返回第一个与参数匹配的结果(假设数据是预先排序的),如果失败,则返回某个默认值:

def get_next_food(df, person, day):
    results = df.query(f"`person`=='{person}' and `day`>{day}")
    if len(results)>0:
        return results.iloc[0]['food']
    else:
        return "Mystery"

您可以按如下方式使用此选项:

get_food(df_seq,"Tom", 1)

> 'lamb'

现在,我们可以在一个apply语句中使用这个函数,用这个函数按行应用的结果填充一个新列:

df_seq['next_food']=df_seq.apply(lambda x : get_food(df_seq, x['person'], x['day']), axis=1)

>
  person  day     food next_food
0    Tom    1     beef      lamb
1    Tom    2     lamb   chicken
2    Tom    3  chicken   Mystery
3   Lucy    1     fish      pork
4   Lucy    4     pork   venison
5   Lucy    6  venison   Mystery

给予一下吧,我不相信你会看到巨大的性能改进,但它会很有趣的发现。

相关问题