根据多索引名称将 DataFrame 单元格中的每个值相乘

Multiply each value in DataFrame cell according to multi-index name

鉴于此 pandas 数据框

list_index = pd.Series(['A' for i in range(2)] + ['B' for i in range(4)] + ['C' for i in range(3)] + ['D' for i in range(6)], name='indexes')
list_type = pd.Series(['a', 'c'] + ['a', 'b','c','d'] + ['f','g','i'] + ['a','c','d','e','f','g'], name='types')
df = pd.DataFrame({
    'value' : [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
}, index=[list_index, list_type])

indexes types   value
A       a       1
        c       2
B       a       3
        b       4
        c       5
        d       6
C       f       7
        g       8
        i       9
D       a       10
        c       11
        d       12
        e       13
        f       14
        g       15

我想将每个值乘以另一个 pandas.Dataframe

中包含的一个因子(即比率)
ratio_df = pd.DataFrame({
    'ratio' : [0.1, 0.2, 0.4, 0.5]
}, index=['A', 'B', 'C', 'D'])

    ratio
A   0.1
B   0.2
C   0.4
D   0.5

因此 df 中所有 'indexes' == 'A' 的值都乘以 0.1,'indexes' == 'B' 的值乘以 0.1以 0.2 依此类推。
我确信有一些聪明的方法可以做到这一点,但现在我真的想不出。我知道我可以 'expand' ratio_df 到相同长度的 df (使用 reset_index() 然后为 df 创建一个包含比率的新列)而不是简单地执行 * 操作成对,但我不确定这是最快的方法。

我也看过这个 但它与我的情况略有不同。

这是一种只重置第一级的方法; joining; multiplying 和 set_index 回到原来的:

out = df.reset_index(level=1).join(ratio_df).assign(New=lambda x: x['value']*x['ratio']).set_index('types', append=True)

输出:

         value  ratio  New
  types                   
A a          1    0.1  0.1
  c          2    0.1  0.2
B a          3    0.2  0.6
  b          4    0.2  0.8
  c          5    0.2  1.0
  d          6    0.2  1.2
C f          7    0.4  2.8
  g          8    0.4  3.2
  i          9    0.4  3.6
D a         10    0.5  5.0
  c         11    0.5  5.5
  d         12    0.5  6.0
  e         13    0.5  6.5
  f         14    0.5  7.0
  g         15    0.5  7.5

ratio 列重命名为 value 然后在 level=0 上使用 mul:

df.mul(ratio_df.rename(columns={'ratio': 'value'}), level=0)

结果

               value
indexes types       
A       a        0.1
        c        0.2
B       a        0.6
        b        0.8
        c        1.0
        d        1.2
C       f        2.8
        g        3.2
        i        3.6
D       a        5.0
        c        5.5
        d        6.0
        e        6.5
        f        7.0
        g        7.5

如果只是需要两列的乘积Series.mul可以根据索引级别对齐

仅 select 列和 mul 索引级别:

df['value'].mul(ratio_df['ratio'], level='indexes')

或索引级别编号:

df['value'].mul(ratio_df['ratio'], level=0)

结果是一个未命名的系列:

indexes  types
A        a        0.1
         c        0.2
B        a        0.6
         b        0.8
         c        1.0
         d        1.2
C        f        2.8
         g        3.2
         i        3.6
D        a        5.0
         c        5.5
         d        6.0
         e        6.5
         f        7.0
         g        7.5
dtype: float64

结果系列可以根据需要分配回df

df['new'] = df['value'].mul(ratio_df['ratio'], level='indexes')

df:

               value  new
indexes types            
A       a          1  0.1
        c          2  0.2
B       a          3  0.6
        b          4  0.8
        c          5  1.0
        d          6  1.2
C       f          7  2.8
        g          8  3.2
        i          9  3.6
D       a         10  5.0
        c         11  5.5
        d         12  6.0
        e         13  6.5
        f         14  7.0
        g         15  7.5