I am trying to use two of my second level indices to calculate a third index. However, I can’t find an idiomatic way to do this.
How can I calculate one second level index from two other second level indices? Each group has the same second level indices.
My Code
JavaScript
x
17
17
1
import numpy as np
2
import pandas as pd
3
4
# Create index
5
tickers = ['A', 'B', 'C']
6
line_items = ['sales', 'ebitda_margin', 'ebitda', 'other_field']
7
index = pd.MultiIndex.from_product([tickers, line_items], names=['ticker', 'line_item'])
8
9
df = pd.DataFrame([100, 0.3, np.nan, 7, 200, 0.2, np.nan, 8, 300, 0.1, np.nan, 9],
10
index=index,
11
columns=[0])
12
13
# Let's assume 10% sales growth for all companies
14
# This is included to show that I am doing this calculation for multiple years (columns)
15
df[1] = df[0]
16
df.loc[pd.IndexSlice[:, 'sales'], 1] *= 1.1
17
This produces the following data frame:
JavaScript
1
15
15
1
0 1
2
ticker line_item
3
A sales 100.0 110.0
4
ebitda_margin 0.3 0.3
5
ebitda NaN NaN
6
other_field 7.0 7.0
7
B sales 200.0 220.0
8
ebitda_margin 0.2 0.2
9
ebitda NaN NaN
10
other_field 8.0 8.0
11
C sales 300.0 330.0
12
ebitda_margin 0.1 0.1
13
ebitda NaN NaN
14
other_field 9.0 9.0
15
What I Have
Note that I know that I will need to do some work with indexes to get the below to work, but would rather find a better way if one exists rather than using this code.
JavaScript
1
2
1
df.apply(lambda x: x.loc[pd.IndexSlice[:, 'sales']] * x.loc[pd.IndexSlice[:, 'ebitda_margin']])
2
Is there a better way to do this?
Advertisement
Answer
Try xs
as an alternative to pd.IndexSlice
where you get to remove one level, then mul
which allows level alignment when multiply:
JavaScript
1
4
1
df.loc[pd.IndexSlice[:, 'sales'],:] = (df.loc[pd.IndexSlice[:, 'sales'],:]
2
.mul(df.xs('ebitda_margin', level='line_item'), level=0)
3
)
4
Output:
JavaScript
1
15
15
1
0
2
ticker line_item
3
A sales 30.0
4
ebitda_margin 0.3
5
ebitda NaN
6
other_field 7.0
7
B sales 40.0
8
ebitda_margin 0.2
9
ebitda NaN
10
other_field 8.0
11
C sales 30.0
12
ebitda_margin 0.1
13
ebitda NaN
14
other_field 9.0
15