为 tables/data 的多个级别应用函数

Apply function for multiple levels of tables/data

我在工作中遇到了问题。我有 tables:

import pandas as pd
import numpy as np

level1 = pd.DataFrame(list(zip(['a', 'b', 'c'], [3, 'x', 'x'])),
columns=['name', 'value'])
   name value
0   a   3
1   b   x
2   c   x

我想对 value 列求和,但它包含“x”。所以我将不得不使用第二个 table 来计算“x”s :

level2 = pd.DataFrame(list(zip(['b', 'b', 'c', 'c', 'c'], ['b1', 'b2', 'c1', 'c2', 'c3'], [5, 7, 2, 'x', 9])), 
columns=['name', 'sub', 'value'])
  name  sub value
0   b   b1  5
1   b   b2  7
2   c   c1  2
3   c   c2  x
4   c   c3  9

我应该对 b1b2 求和,为 level1 table (x=12) 中的 b 给出“x”。但是对于c,有“x”,所以第三层table:

level3 = pd.DataFrame(list(zip(['c', 'c', 'c'], ['c1', 'c2', 'c3'], [2, 4, 9])), 
columns=['name', 'sub', 'value'])
  name  sub value
0   c   c1  2
1   c   c2  4
2   c   c3  9

现在,我们可以得到 level1 table 中 value 列的总和值。

我的问题是:我们可以使用一个函数来轻松计算吗?如果有更多的层次,我们如何循环直到没有“x”?

level2level3组合即可。

这是使用 combine_firstreplace 的方法:

from functools import reduce
l1 = level1.assign(sub=level1['name']+'1').replace('x', np.nan).set_index(['name', 'sub'])
l2 = level2.replace('x', np.nan).set_index(['name', 'sub'])
l3 = level3.replace('x', np.nan).set_index(['name', 'sub'])

reduce(lambda x, y: x.combine_first(y), [l3,l2,l1]).groupby(level=0).sum()

输出:

      value
name       
a       3.0
b      12.0
c      15.0

完整示例:

import pandas as pd
import numpy as np

level1 = pd.DataFrame(list(zip(['a', 'b', 'c'], [3, 'x', 'x'])),
                      columns=['name', 'value'])

level2 = pd.DataFrame(list(zip(['b', 'b', 'c', 'c', 'c'], 
                               ['b1', 'b2', 'c1', 'c2', 'c3'], 
                               [5, 7, 2, 'x', 9])), 
                      columns=['name', 'sub', 'value'])

level3 = pd.DataFrame(list(zip(['c', 'c', 'c'], 
                               ['c1', 'c2', 'c3'], 
                               [2, 4, 9])),
                      columns=['name', 'sub', 'value'])

from functools import reduce
l1 = level1.assign(sub=level1['name']+'1')\
           .replace('x', np.nan)\
           .set_index(['name', 'sub'])
l2 = level2.replace('x', np.nan)\
           .set_index(['name', 'sub'])
l3 = level3.replace('x', np.nan)\
           .set_index(['name', 'sub'])

out = reduce(lambda x, y: x.combine_first(y), 
             [l3,l2,l1]).groupby(level=0).sum()
print(out)

一个选项是合并(实际上是多个合并)和 groupby 的组合:

(level2
.merge(level3, on = ['name', 'sub'], how = 'left', suffixes = (None, '_y'))
.assign(value = lambda df: np.where(df.value.eq('x'), df.value_y, df.value))
.groupby('name', as_index = False)
.value
.sum()
.merge(level1, on = 'name', how = 'right', suffixes = ('_x',None))
.assign(value = lambda df: np.where(df.value.eq('x'), df.value_x, df.value))
.loc[:, ['name', 'value']]
)

  name value
0    a     3
1    b  12.0
2    c  15.0