熊猫groupby和apply-通过groupby变量获取一个新的DataFrame

时间:2018-11-28 05:57:24

标签: python pandas

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

'x'重复多于一次时出现问题。 apply函数将执行'x'重复的次数,尽管我只需要'aggregated'值(它实际上不是 aggregation ,但更像是- processing )。

这是一个玩具示例:

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

输出正是我想要的,但是效率不高。有没有更好的方法可以使用熊猫呢?

编辑:优化方式?

如果我们要向print添加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创建的组数)。

1 个答案:

答案 0 :(得分: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