Groupby并使用自定义函数执行行方式计算

时间:2017-09-27 15:04:03

标签: python pandas dataframe group-by pandas-groupby

继续这个问题:python - Group by and add new row which is calculation of other rows

我有一个pandas数据帧如下:

col_1   col_2   col_3  col_4
a       X        5      1
a       Y        3      2
a       Z        6      4
b       X        7      8
b       Y        4      3
b       Z        6      5

我希望,对于col_1中的每个值,应用一个函数,其中col_3和col_4(以及更多列)中的值与col_2中的X和Z相对应,并使用这些值创建一个新行。所以输出如下:

col_1   col_2   col_3  col_4 
a       X        5      1
a       Y        3      2
a       Z        6      4
a       NEW      *      *
b       X        7      8
b       Y        4      3
b       Z        6      5
b       NEW      *      *

其中*是函数的输出。

原始问题(只需要简单的添加)回答:

new = df[df.col_2.isin(['X', 'Z'])]\
  .groupby(['col_1'], as_index=False).sum()\
  .assign(col_2='NEW')

df = pd.concat([df, new]).sort_values('col_1')

我现在正在寻找一种使用自定义功能的方法,例如(X/Y)((X+Y)*2),而不是X+Y。如何修改此代码以符合我的新要求?

3 个答案:

答案 0 :(得分:3)

我不确定这是不是你想要的,但是这里有:

def f(x):
    y = x.values
    return y[0] / y[1] # replace with your function

而且,对new的更改是:

new = (
    df[df.col_2.isin(['X', 'Z'])]
      .groupby(['col_1'], as_index=False)[['col_3', 'col_4']]
      .agg(f)
      .assign(col_2='NEW')
)

  col_1     col_3  col_4 col_2
0     a  0.833333   0.25   NEW
1     b  1.166667   1.60   NEW

df = pd.concat([df, new]).sort_values('col_1')

df
  col_1 col_2     col_3  col_4
0     a     X  5.000000   1.00
1     a     Y  3.000000   2.00
2     a     Z  6.000000   4.00
0     a   NEW  0.833333   0.25
3     b     X  7.000000   8.00
4     b     Y  4.000000   3.00
5     b     Z  6.000000   5.00
1     b   NEW  1.166667   1.60

我对f抱有信心,并假设这些列在它们命中之前已经排序。如果不是这种情况,则需要额外sort_values次呼叫:

df = df.sort_values(['col_1, 'col_2'])

应该做的伎俩。

答案 1 :(得分:3)

def foo(df):
    # Expand variables into dictionary.
    d = {v: df.loc[df['col_2'] == v, ['col_3', 'col_4']] for v in df['col_2'].unique()}

    # Example function: (X + Y ) * 2
    result = (d['X'].values + d['Y'].values) * 2

    # Convert result to a new dataframe row.
    result = result.tolist()[0]
    df_new = pd.DataFrame(
        {'col_1': [df['col_1'].iat[0]], 
         'col_2': ['NEW'], 
         'col_3': result[0],
         'col_4': result[1]})
    # Concatenate result with original dataframe for group and return.
    return pd.concat([df, df_new])

>>> df.groupby('col_1').apply(lambda x: foo(x)).reset_index(drop=True)
  col_1 col_2  col_3  col_4
0     a     X      5      1
1     a     Y      3      2
2     a     Z      6      4
3     a   NEW     16      6
4     b     X      7      8
5     b     Y      4      3
6     b     Z      6      5
7     b   NEW     22     22

答案 2 :(得分:0)

一种更新的方法(应该提供性能优势)将使用PyArrow和pandas_udf支持向量化操作,如Spark 2.4中所述:PySpark Usage Guide for Pandas with Apache Arrow