分组 DataFrame,将函数与输入一起应用,然后将结果添加回原始数据

Group DataFrame, apply function with inputs then add result back to original

在任何地方都找不到这个问题,所以只需在这里试试:

我想做的基本上是使用 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=afield_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 中的哪一列应该用于插值 取决于 benchmark 中的 field_1(即上面集合 (a,b,c) 中的值).新列中的内插值基于 benchmark.

中的 x 值

结果:

基准=

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        ...

有道理吗?

编辑:

我认为你需要先通过 set_index + stack, set index names by rename_axis 重塑 separate_data 并通过重命名设置 Serie 的名称。

然后可以groupby两个级别并使用一些功能。

然后join它到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 成对重复 return 漂亮独特的对:

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 因为多列是一起阅读的。

所以使用apply:

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

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

两种方法的示例解决方案是 here

或者可以使用 flexible apply 可以 return 新 DataFrame 新列。

这是一个工作示例:

# 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

尝试这样的事情:

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

在 your_function 中,您将使用所需的其他列创建新列,例如对它们进行平均、求和等

apply 的文档。 join.

的文档