Pandas分组和应用 - 在分组变量上获取新的数据框架

3

我正在尝试使用 pandas.DataFrame.groupby['x'] 对分组的 dfx 进行计算。

'x' 重复超过一次时,问题就出现了。apply 函数会根据 'x' 的重复次数执行相应次数的计算,但我只需要“汇总”值(它不是真正的聚合,而更像是处理)。

以下是一个玩具示例:

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc1', 'calc2', 'calc3']

    df['calc1'] = ''.join(df['var1'])
    df['calc2'] = df['var2'].mean()
    df['calc3'] = ''.join(df['var1']) + str(df['var2'].max())

    return df[['id'] + returned_col_names]

df = pd.DataFrame({'id':['id1', 'id1', 'id2', 'id3', 'id3', 'id3'],
                   'var1':['abc', 'cba', 'abc', 'cba', 'abc', 'cba'],
                   'var2':[9, 4, 7, 4, 1, 3]})

print(df)

    id var1  var2
0  id1  abc     9
1  id1  cba     4
2  id2  abc     7
3  id3  cba     4
4  id3  abc     1
5  id3  cba     3

res_df = df.groupby(['id']).apply(simulate_complicated_func).drop_duplicates()
print(res_df)

    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
2  id2        abc  7.000000        abc7
3  id3  cbaabccba  2.666667  cbaabccba4

输出结果正是我想要的,但效率不高。是否有更好的方法使用pandas来做到这一点?
编辑:如何优化?
如果我们在simulate_complicated_func()中添加一个打印语句。
def simulate_complicated_func(df):
    # This function simulates complicate calculations
    print("function called")
    # ...

我们可以看到,该代码将会打印出6次:
function called
function called
function called
function called
function called
function called

事实上,我们只需要访问此函数3次(由groupby创建的组数)。


实际数据的大小是多少?有多少个组? - jezrael
1个回答

2

一个想法是从自定义函数返回 Series,这样就不需要使用 drop_duplicates

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc1', 'calc2', 'calc3']

    a = ''.join(df['var1'])
    b = df['var2'].mean()
    c = ''.join(df['var1']) + str(df['var2'].max())

    return pd.Series([a,b,c], index=returned_col_names)

res_df = df.groupby(['id']).apply(simulate_complicated_func).reset_index()
print(res_df)
    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
1  id2        abc  7.000000        abc7
2  id3  cbaabccba  2.666667  cbaabccba4

另一个想法是使用DataFrameGroupBy.agg,但这只适用于处理所有列的聚合函数,如joinmean。函数agg与每个列单独工作,因此cal3不可能轻松/有效地计数 - 必须再次自定义函数并将输出连接在一起:
def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc3']
    c = ''.join(df['var1']) + str(df['var2'].max())
    return pd.Series([c], index=returned_col_names)

d = {'var1': ''.join, 'var2':'mean'}
cols = {'var1':'calc1','var2':'calc2'}
g = df.groupby(['id'])

df1 = g.agg(d).rename(columns=cols)
print (df1)
         calc1     calc2
id                      
id1     abccba  6.500000
id2        abc  7.000000
id3  cbaabccba  2.666667

df2 = df.groupby(['id']).apply(simulate_complicated_func)
print(df2)
          calc3
id             
id1     abccba9
id2        abc7
id3  cbaabccba4

df = pd.concat([df1, df2], axis=1).reset_index()
print (df)
    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
1  id2        abc  7.000000        abc7
2  id3  cbaabccba  2.666667  cbaabccba4

谢谢Jezrael!但那只是一个玩具示例。实际上,该函数要复杂得多,并且内置聚合函数无法正常工作。在Pandas中没有办法按'id'进行分组,在分组对象上进行1次计算并返回结果,每个'id'? - Eran Moshe
@EranMoshe - 你认为我的第一个解决方案怎么样? - jezrael
它更符合 Python 风格,但仍然每次调用函数(例如,在示例中为 6)而不是 3(因为仅有 3 个唯一的'id')。 - Eran Moshe
@EranMoshe - 你为什么认为会调用 6 次?你如何测试它?在我看来,它会调用 4 次 - 3 + 1,因为警告 - 1. apply 会被调用 2 次。 - jezrael
1
等一下!测试你的Series解决方案,似乎效果更好了!请给我几分钟。 - Eran Moshe
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接