I want to multiply two matrices (.dot
not .mul
), one of which may or may not have 2-D mutli-index columns. I have solved this for the 1-D case and the 2-D case, I feel like there should be a generalization between the two, but I can't figure it out.
Sample Data
>>> A = pd.DataFrame({'b': [1, 0], 'c': [1, 0], 'e': [0, 1]}, index=['a','d'])
>>> A
b c e
0 1 1 0
1 0 0 1
>>> columns = pd.MultiIndex.from_product([['b', 'c', 'e'], ['metric1', 'metric2']])
>>> B2D = pd.DataFrame(
[
[22, 24, 20, 31, 29, 20],
[12, 14, 10, 21, 24, 91]
],
columns=columns
)
>>> B2D
b c e
metric1 metric2 metric1 metric2 metric1 metric2
0 22 24 20 31 29 20
1 12 14 10 21 24 91
>>> B1D = B2D.xs('metric1', 1, 1)
Desired Result
>>> func(A, B2D)
a d
metric1 metric2 metric1 metric2
0 42 55 29 20
1 22 35 24 91
>>> func(A, B1D)
a d
0 42 29
1 22 24
My Version
This works for each case but not both. I hope theres a simpler way to combine these into a generalized version...
def func1D(a, b):
return (a @ b.T).T
def func2D(a, b):
return (B.stack(level=1) @ A.T).unstack()
Other Relevant Answers
pandas dot product on each sub frame in multi-index data frame
Pandas multiply dataframes with multiindex and overlapping index levels
CodePudding user response:
You can compute the levels to use in stack
/unstack
:
def func(a, b):
levels = list(range(1, b.columns.nlevels))
return (b.stack(level=levels) @ a.T).unstack(level=levels)
Output:
func(A, B1D)
a d
0 42 29
1 22 24
func(A, B2D)
a d
metric1 metric2 metric1 metric2
0 42 55 29 20
1 22 35 24 91