Python 熊猫使用多索引和重叠索引级别来繁殖数据帧
我正在努力完成一项应该很简单的任务,但它并不像我想象的那样有效。我有两个数字数据帧A和B,具有多索引和以下列:Python 熊猫使用多索引和重叠索引级别来繁殖数据帧,python,pandas,Python,Pandas,我正在努力完成一项应该很简单的任务,但它并不像我想象的那样有效。我有两个数字数据帧A和B,具有多索引和以下列: A = A B C D X 1 AX1 BX1 CX1 DX1 2 AX2 BX2 CX2 DX2 3 AX3 BX3 CX3 DX3 Y 1 AY1 BY1 CY1 DY1 2 AY2 BY2 CY2 DY2 3 AY3 BY3 CY3 DY3 B =
A = A B C D
X 1 AX1 BX1 CX1 DX1
2 AX2 BX2 CX2 DX2
3 AX3 BX3 CX3 DX3
Y 1 AY1 BY1 CY1 DY1
2 AY2 BY2 CY2 DY2
3 AY3 BY3 CY3 DY3
B = A B C D
X 1 a AX1a BX1a CX1a DX1a
b AX1b BX1b CX1b DX1b
c AX1c BX1c CX1c DX1c
2 a AX2a BX2a CX2a DX2a
b AX2b BX2b CX2b DX2b
c AX2c BX2c CX2c DX2c
3 a AX3a BX3a CX3a DX3a
b AX3b BX3b CX3b DX3b
c AX3c BX3c CX3c DX3c
Y 1 a AY1a BY1a CY1a DY1a
b AY1b BY1b CY1b DY1b
c AY1c BY1c CY1c DY1c
2 a AY2a BY2a CY2a DY2a
b AY2b BY2b CY2b DY2b
c AY2c BY2c CY2c DY2c
3 a AY3a BY3a CY3a DY3a
b AY3b BY3b CY3b DY3b
c AY3c BY3c CY3c DY3c ## Heading ##
我想将A*B广播乘以B的最内层,我想要得到的数据帧R,如下所示:
R= A B C D
X 1 a (AX1a * AX1) (BX1a * BX1) (CX1a * CX1) (DX1a * DX1)
b (AX1b * AX1) (BX1b * BX1) (CX1b * CX1) (DX1b * DX1)
c (AX1c * AX1) (BX1c * BX1) (CX1c * CX1) (DX1c * DX1)
2 a (AX2a * AX2) (BX2a * BX2) (CX2a * CX2) (DX2a * DX2)
b (AX2b * AX2) (BX2b * BX2) (CX2b * CX2) (DX2b * DX2)
c (AX2c * AX2) (BX2c * BX2) (CX2c * CX2) (DX2c * DX2)
3 a (AX3a * AX3) (BX3a * BX3) (CX3a * CX3) (DX3a * DX3)
b (AX3b * AX3) (BX3b * BX3) (CX3b * CX3) (DX3b * DX3)
c (AX3c * AX3) (BX3c * BX3) (CX3c * CX3) (DX3c * DX3)
Y 1 a (AY1a * AY1) (BY1a * BY1) (CY1a * CY1) (DY1a * DY1)
b (AY1b * AY1) (BY1b * BY1) (CY1b * CY1) (DY1b * DY1)
c (AY1c * AY1) (BY1c * BY1) (CY1c * CY1) (DY1c * DY1)
2 a (AY2a * AY2) (BY2a * BY2) (CY2a * CY2) (DY2a * DY2)
b (AY2b * AY2) (BY2b * BY2) (CY2b * CY2) (DY2b * DY2)
c (AY2c * AY2) (BY2c * BY2) (CY2c * CY2) (DY2c * DY2)
3 a (AY3a * AY3) (BY3a * BY3) (CY3a * CY3) (DY3a * DY3)
b (AY3b * AY3) (BY3b * BY3) (CY3b * CY3) (DY3b * DY3)
c (AY3c * AY3) (BY3c * BY3) (CY3c * CY3) (DY3c * DY3)
我尝试通过执行以下操作,将pandas multiply函数与level关键字一起使用:
b.multiply(a, level=[0,1])
但它抛出了一个错误:“TypeError:两个多索引对象之间在级别上的连接是不明确的”
做这个手术的正确方法是什么?请注意,我并不是说这是做这个手术的正确方法,只是说这是做这个手术的一种方法。过去,我自己也曾在正确的广播模式上遇到过问题-/
简短的版本是,我最终手动进行广播,并创建一个适当对齐的中间对象:
In [145]: R = B * A.loc[B.index.droplevel(2)].set_index(B.index)
In [146]: A.loc[("X", 2), "C"]
Out[146]: 0.5294149302910357
In [147]: A.loc[("X", 2), "C"] * B.loc[("X", 2, "c"), "C"]
Out[147]: 0.054262618238601339
In [148]: R.loc[("X", 2, "c"), "C"]
Out[148]: 0.054262618238601339
其工作原理是使用B的匹配部分索引到A,然后将索引设置为匹配。如果我更聪明的话,我会想出一个本地的方法来让它工作,但我还没有-(建议的方法
我们谈论的是广播
,因此我想在这里介绍一下
解决方案代码如下所示-
def numpy_broadcasting(df0, df1):
m,n,r = map(len,df1.index.levels)
a0 = df0.values.reshape(m,n,-1)
a1 = df1.values.reshape(m,n,r,-1)
out = (a1*a0[...,None,:]).reshape(-1,a1.shape[-1])
df_out = pd.DataFrame(out, index=df1.index, columns=df1.columns)
return df_out
基本理念:
1] 将视图作为多维数组放入数据框。多维性根据multindex数据框的级别结构进行维护。因此,第一个数据框将有三个级别(包括列)第二个有四个级别,因此,我们有与输入数据帧df0
和df1
相对应的a0
和a1
,导致a0
和a1
分别具有3和4
维度
2) 现在是广播部分。通过在第三个位置引入一个新的轴,我们简单地将a0
扩展为4维。这个新轴将与df1
中的第三个轴匹配。这允许我们执行元素级乘法
B.multiply(A.reindex(B.index, method='ffill')) # Or method='pad'
3) 最后,为了得到输出的multindex数据帧,我们只需对产品进行重塑
样本运行:
1) 输入数据帧-
In [369]: df0
Out[369]:
A B C D
0 0 3 2 2 3
1 6 8 1 0
2 3 5 1 5
1 0 7 0 3 1
1 7 0 4 6
2 2 0 5 0
In [370]: df1
Out[370]:
A B C D
0 0 0 4 6 1 2
1 3 3 4 5
2 8 1 7 4
1 0 7 2 5 4
1 8 6 7 5
2 0 4 7 1
2 0 1 4 2 2
1 2 3 8 1
2 0 0 5 7
1 0 0 8 6 1 7
1 0 6 1 4
2 5 4 7 4
1 0 4 7 0 1
1 4 2 6 8
2 3 1 0 6
2 0 8 4 7 4
1 0 6 2 0
2 7 8 6 1
2) 输出数据帧-
In [371]: df_out
Out[371]:
A B C D
0 0 0 12 12 2 6
1 9 6 8 15
2 24 2 14 12
1 0 42 16 5 0
1 48 48 7 0
2 0 32 7 0
2 0 3 20 2 10
1 6 15 8 5
2 0 0 5 35
1 0 0 56 0 3 7
1 0 0 3 4
2 35 0 21 4
1 0 28 0 0 6
1 28 0 24 48
2 21 0 0 36
2 0 16 0 35 0
1 0 0 10 0
2 14 0 30 0
标杆管理
我只需在较小的DF
形状上使用,以匹配较大DF
形状的索引,并向前填充其中的值。然后做乘法运算
B.multiply(A.reindex(B.index, method='ffill')) # Or method='pad'
演示:
准备一些数据:
np.random.seed(42)
midx1 = pd.MultiIndex.from_product([['X', 'Y'], [1,2,3]])
midx2 = pd.MultiIndex.from_product([['X', 'Y'], [1,2,3], ['a','b','c']])
A = pd.DataFrame(np.random.randint(0,2,(6,4)), midx1, list('ABCD'))
B = pd.DataFrame(np.random.randint(2,4,(18,4)), midx2, list('ABCD'))
小型DF
:
BigDF
:
确保两者在所有级别上共享一个共同的索引轴后相乘:
>>> B.multiply(A.reindex(B.index, method='ffill'))
A B C D
X 1 a 0 3 0 0
b 0 3 0 0
c 0 3 0 0
2 a 0 2 0 0
b 0 2 0 0
c 0 3 0 0
3 a 0 3 0 0
b 0 3 0 0
c 0 2 0 0
Y 1 a 0 0 2 0
b 0 0 3 0
c 0 0 3 0
2 a 2 3 2 0
b 3 3 2 0
c 2 3 2 0
3 a 2 0 3 2
b 3 0 3 3
c 3 0 3 3
现在,您甚至可以在中提供level
参数,以便在那些匹配的索引处进行广播。我不明白为什么要进行下一票。似乎OP需要一个纯粹的pandas
解决方案,如果真的存在的话。但这不是贬低某人的理由。不管怎样,我已经投了赞成票。这是一个很好的干净的解决方案!对于其他使用这个(很棒)答案的人,请注意,较大数据帧中的“额外”索引级别需要排在最后。这里甚至不需要使用fill方法。如果A有不同的列名,但您想保留B的列名,只需使用values属性,如B*A.reindex(B.index).values
>>> B
A B C D
X 1 a 3 3 3 3
b 3 3 2 2
c 3 3 3 2
2 a 3 2 2 2
b 2 2 3 3
c 3 3 3 2
3 a 3 3 2 3
b 2 3 2 3
c 3 2 2 2
Y 1 a 2 2 2 2
b 2 3 3 2
c 3 3 3 3
2 a 2 3 2 3
b 3 3 2 3
c 2 3 2 3
3 a 2 2 3 2
b 3 3 3 3
c 3 3 3 3
>>> B.multiply(A.reindex(B.index, method='ffill'))
A B C D
X 1 a 0 3 0 0
b 0 3 0 0
c 0 3 0 0
2 a 0 2 0 0
b 0 2 0 0
c 0 3 0 0
3 a 0 3 0 0
b 0 3 0 0
c 0 2 0 0
Y 1 a 0 0 2 0
b 0 0 3 0
c 0 0 3 0
2 a 2 3 2 0
b 3 3 2 0
c 2 3 2 0
3 a 2 0 3 2
b 3 0 3 3
c 3 0 3 3