首页 > 解决方案 > 如何在 MultiIndex Groupby 中高效地执行乘法

问题描述

我正在尝试使用我的两个二级索引来计算第三个索引。但是,我找不到一种惯用的方法来做到这一点。

如何从其他两个二级指标计算一个二级指标?每个组都有相同的二级指标。

我的代码


import numpy as np
import pandas as pd

# Create index
tickers = ['A', 'B', 'C']
line_items = ['sales', 'ebitda_margin', 'ebitda', 'other_field']
index = pd.MultiIndex.from_product([tickers, line_items], names=['ticker', 'line_item'])

df = pd.DataFrame([100, 0.3, np.nan, 7, 200, 0.2, np.nan, 8, 300, 0.1, np.nan, 9], 
                  index=index, 
                  columns=[0])

# Let's assume 10% sales growth for all companies
# This is included to show that I am doing this calculation for multiple years (columns)
df[1] = df[0]
df.loc[pd.IndexSlice[:, 'sales'], 1] *= 1.1

这将产生以下数据框:

                          0      1
ticker line_item                  
A      sales          100.0  110.0
       ebitda_margin    0.3    0.3
       ebitda           NaN    NaN
       other_field      7.0    7.0
B      sales          200.0  220.0
       ebitda_margin    0.2    0.2
       ebitda           NaN    NaN
       other_field      8.0    8.0
C      sales          300.0  330.0
       ebitda_margin    0.1    0.1
       ebitda           NaN    NaN
       other_field      9.0    9.0

我有的

请注意,我知道我需要对索引进行一些工作才能使以下内容正常工作,但如果存在一种更好的方法而不是使用此代码,我宁愿找到更好的方法。

df.apply(lambda x: x.loc[pd.IndexSlice[:, 'sales']] * x.loc[pd.IndexSlice[:, 'ebitda_margin']])

有一个更好的方法吗?

标签: pythonpandaspandas-groupbymulti-index

解决方案


感谢@piRSquared 帮助我解决这个问题。以下为我做了:


piR 评论:
关键是将行项目放入列中以使数学更容易。如果数据框是面向演示的并且很小,那么 / / 可以更快地stack/ unstack/pivot以便更方便地进行计算,然后stack/ unstack/pivot返回。


df_restack = df.stack().unstack('line_item')
df_restack['ebitda'] = df_restack['sales'] * df_restack['ebitda_margin']
df = df_restack.stack().unstack(1)

这将产生以下数据框:

                          0      1
ticker line_item                  
A      ebitda          30.0   33.0
       ebitda_margin    0.3    0.3
       other_field      7.0    7.0
       sales          100.0  110.0
B      ebitda          40.0   44.0
       ebitda_margin    0.2    0.2
       other_field      8.0    8.0
       sales          200.0  220.0
C      ebitda          30.0   33.0
       ebitda_margin    0.1    0.1
       other_field      9.0    9.0
       sales          300.0  330.0

我会注意到,当数据框较大时,Quang 和 Andrej 的答案要快得多,所以我选择了 Quang 的答案,因为他首先回答。


推荐阅读