组DataFrame,使用输入应用函数,然后将结果添加回原始

时间:2017-07-05 15:45:03

标签: python pandas dataframe pandas-groupby

无法在任何地方找到这个问题,所以请在此尝试:

我尝试做的基本上是使用groupby功能和自编函数来改变现有的DataFrame对象:

benchmark =

x    y    z    field_1

1    1    3    a
1    2    5    b
9    2    4    a
1    2    5    c
4    6    1    c

我想要做的是分组field_1,使用特定列作为输入应用函数,在这种情况下是列xy,然后将结果添加回原始DataFrame benchmark作为名为new_field的新列。函数本身取决于field_1中的值,即field_1=a将产生与field_1=b等相比的不同结果(因此分组开始)。

伪代码类似于:

1. grouped_data = benchmark.groupby(['field_1'])
2. apply own_function to grouped_data; with inputs ('x', 'y', grouped_data)
3. add back result from function to benchmark as column 'new_field'

谢谢,

蚀变:

benchmark =

x    y    z    field_1

1    1    3    a
1    2    5    b
9    2    4    a
1    2    5    c
4    6    1    c

精化:

我还有一个DataFrame separate_data,其中包含x

的单独值
separate_data =

x    a    b    c

1    1    3    7
2    2    5    6
3    2    4    4
4    2    5    9
5    6    1    10

需要插入现有的benchmark DataFrame。 separate_data中应该用于插值的哪一列取决于field_1中的benchmark(即上面集(a,b,c)中的值)。新列中的插值基于benchmark中的x值。

结果:

benchmark =

x    y    z    field_1  field_new

1    1    3    a        interpolate using separate_data with x=1 and col=a
1    2    5    b        interpolate using separate_data with x=1 and col=b
9    2    4    a        ... etc
1    2    5    c        ...
4    6    1    c        ...

有道理吗?

3 个答案:

答案 0 :(得分:3)

编辑:

我认为您需要先set_index + stack重新设置separate_data,然后按rename_axis设置索引名称,并通过重命名设置Serie的名称。

然后两个级别都可以groupby并使用一些函数。

然后joinapply改为benchmark,默认左连接:

separate_data1 =separate_data.set_index('x').stack().rename_axis(('x','field_1')).rename('d')
print (separate_data1)
x  field_1
1  a           1
   b           3
   c           7
2  a           2
   b           5
   c           6
3  a           2
   b           4
   c           4
4  a           2
   b           5
   c           9
5  a           6
   b           1
   c          10
Name: d, dtype: int64

如果有必要,可以使用一些函数,主要是如果一对xfield_1成对重复,它会返回漂亮的唯一对:

def func(x):
    #sample function   
    return x / 2 + x ** 2


separate_data1 = separate_data1.groupby(level=['x','field_1']).apply(func)
print (separate_data1)
x  field_1
1  a            1.5
   b           10.5
   c           52.5
2  a            5.0
   b           27.5
   c           39.0
3  a            5.0
   b           18.0
   c           18.0
4  a            5.0
   b           27.5
   c           85.5
5  a           39.0
   b            1.5
   c          105.0
Name: d, dtype: float64


benchmark = benchmark.join(separate_data1, on=['x','field_1'])
print (benchmark)

   x  y  z field_1     d
0  1  1  3       a   1.5
1  1  2  5       b  10.5
2  9  2  4       a   NaN
3  1  2  5       c  52.5
4  4  6  1       c  85.5

我认为你不能使用transform,因为多个列是一起阅读的。

因此请使用join

df1 = benchmark.groupby(['field_1']).apply(func)

然后对于新列是多个解决方案,例如使用map(默认left join)或here

两种方法的示例解决方案都是flexible apply

或者可以使用{{3}},它可以使用新列返回新的DataFrame

答案 1 :(得分:1)

尝试这样的事情:

groups = benchmark.groupby(benchmark["field_1"])    
benchmark = benchmark.join(groups.apply(your_function), on="field_1")

在your_function中,您可以使用所需的其他列创建新列,例如:平均他们,总结他们等等。

apply的文档。 join的文档。

答案 2 :(得分:0)

这是一个有效的例子:

# Sample function that sums x and y, then append the field as string.
def func(x, y, z):
    return (x + y).astype(str) + z

benchmark['new_field'] = benchmark.groupby('field_1')\
                                  .apply(lambda x: func(x['x'], x['y'], x['field_1']))\
                                  .reset_index(level = 0, drop = True)

结果:

benchmark
Out[139]: 
   x  y  z field_1 new_field
0  1  1  3       a        2a
1  1  2  5       b        3b
2  9  2  4       a       11a
3  1  2  5       c        3c
4  4  6  1       c       10c