我有如下数据:
id movie details value
5 cane1 good 6
5 wind2 ok 30.3
5 wind1 ok 18
5 cane1 good 2
5 cane22 ok 4
5 cane34 good 7
5 wind2 ok 2
我希望输出符合以下条件:
如果电影名称以“ cane”开头-将值相加
如果电影名称以“ wind”开头-计算发生的次数。
所以-最终输出将是:
id movie value
5 cane1 8
5 cane22 4
5 cane34 7
5 wind1 1
5 wind2 2
我尝试使用:
movie_df.groupby(['id']).apply(aggr)
def aggr(x):
if x['movie'].str.startswith('cane'):
y = x.groupby(['value']).sum()
else:
y = x.groupby(['movie']).count()
return y
但是它不起作用。谁能帮忙吗?
答案 0 :(得分:2)
您应该尽可能地进行矢量化操作。
您可以计算2个结果,然后将它们连接起来。
mask = df['movie'].str.startswith('cane')
df1 = df[mask].groupby('movie')['value'].sum()
df2 = df[~mask].groupby('movie').size()
res = pd.concat([df1, df2], ignore_index=0)\
.rename('value').reset_index()
print(res)
movie value
0 cane1 8.0
1 cane22 4.0
2 cane34 7.0
3 wind1 1.0
4 wind2 2.0
答案 1 :(得分:2)
可能有多种方法可以执行此操作。一种方法是先按电影名称的开头进行过滤,然后聚合并合并。
cane = movie_df[movie_df['movie'].str.startswith('cane1')]
wind = movie_df[movie_df['movie'].str.startswith('wind')]
cane_sum = cane.groupby(['id']).agg({'movie':'first', 'value':'sum'}).reset_index()
wind_count = wind.groupby(['id']).agg({'movie':'first', 'value':'count'}).reset_index()
pd.concat([cane_sum, wind_count])
答案 2 :(得分:0)
首先,您需要执行字符串操作。我想在您的情况下,您不需要电影名称中的数字。使用pandas applying regex to replace values中讨论的解决方案。 然后在新系列上调用groupby()。
仅供参考:某些电影名称仅包含数字;在这种情况下,您需要使用更新功能。 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.update.html
答案 3 :(得分:0)
我将从创建定义所需组的列开始。对于当前示例,可以使用
完成 df['group'] = df.movie.transform(lambda x : x[:4])
下一步是按此列分组
df.groupby('group').apply(agg_fun)
使用以下聚合函数
def agg_fun(grp):
if grp.name == "cane":
value=grp.value.sum()
else:
value=grp.value.count()
return value
此代码的输出是
group
cane 19.0
wind 3.0