熊猫按功能汇总

时间:2018-08-24 14:16:32

标签: python pandas dataframe

我有如下数据:

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

但是它不起作用。谁能帮忙吗?

4 个答案:

答案 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