考虑一个多索引数据框:
import numpy as np
import pandas as pd
df1 = pd.DataFrame(np.random.rand(3, 3), index=['a', 'b', 'c'], columns=['col1', 'col2', 'col3'])
df2 = pd.DataFrame(np.random.rand(3, 3), index=['a', 'b', 'c'], columns=['col1', 'col2', 'col3'])
df3 = pd.DataFrame(np.random.rand(3, 3), index=['a', 'b', 'c'], columns=['col1', 'col2', 'col3'])
df = pd.concat([df1, df2, df3], axis=0, keys=['A', 'B', 'C'])
这给出了df
:
col1 col2 col3
A a 0.893752 0.554021 0.492867
b 0.319270 0.263366 0.542281
c 0.082265 0.635637 0.796405
B a 0.954748 0.684624 0.488293
b 0.485414 0.966693 0.211348
c 0.411648 0.989666 0.028412
C a 0.701327 0.025172 0.320882
b 0.073527 0.060885 0.111406
c 0.169269 0.627686 0.438393
(您的数字会有所不同)
我该怎么办:
- 将行 (A, b) 和 (A, c) 除以 (A, a)
- 将行 (B, b) 和 (B, c) 除以 (B, a)
- 将行 (C, b) 和 (C, c) 除以 (C, a)
...一次调用?
我的尝试:
idx = pd.IndexSlice
ratio_list = [df.loc[idx[x,:], :].div(df.loc[idx[x,'a'], :]) for x in ['A', 'B', 'C']]
ratio = pd.concat(ratio_list, axis=0)
这给出了比率
:
col1 col2 col3
A a 1.000000 1.000000 1.000000
b 0.357225 0.475371 1.100259
c 0.092044 1.147315 1.615864
B a 1.000000 1.000000 1.000000
b 0.508422 1.412005 0.432830
c 0.431159 1.445560 0.058186
C a 1.000000 1.000000 1.000000
b 0.104840 2.418784 0.347188
c 0.241355 24.936324 1.366214
请参阅以下来自 @Smordy 和 @ouoboros1 的回答。两者都很棒。 groupby-transform
更简洁,但是当数据帧很大时,np.repeat
的性能肯定更高。
nrow = 100 # iterate through this
df = df = pd.DataFrame(np.random.rand(nrow*3, 3),
columns=['col1', 'col2', 'col3'],
index=pd.MultiIndex.from_product([[*'ABC'], ['row' + str(ii) for ii in range(0, nrow)]]))
# pandas `groupby-transform` from @Smordy
%timeit df.div(df.groupby(level=0).transform('first'))
# `numpy.repeat` from @ouroboros1
%timeit df.div(np.repeat(df.loc[(slice(None), ['row0']), :].to_numpy(), nrow, axis=0))
结果:
这里时间因子似乎稳定在 3 倍左右。如果我们增加列数,时间因子将再次上升。
最佳答案
您可以通过使用 groupby
和 transform
来更有效地尝试
result = df.div(df.groupby(level=0).transform('first'))
关于python - 多索引 Pandas Dataframe 划分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76722678/