带条件的 MultiIndex Dataframe 操作
Operation on MultiIndex Dataframe with condition
我在 Python 中有一个 Pandas MultiIndex 数据框,其中包含两个级别的索引和列,如下所示:
miind = pd.MultiIndex.from_product([['A1','A2'],['B1','B2','B3']])
micol = pd.MultiIndex.from_product([['X1','X2'],['Y1','Y2','Y3']])
df = pd.DataFrame((np.arange(len(miind)*len(micol)) % 5).reshape(len(miind),len(micol)),
index=miind, columns=micol)
print(df)
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0 1 2 3 4 0
B2 1 2 3 4 0 1
B3 2 3 4 0 1 2
A2 B1 3 4 0 1 2 3
B2 4 0 1 2 3 4
B3 0 1 2 3 4 0
我想,对于每一行,当Y3不为0时,Y1和Y2除以Y3。我不知道如何将条件Y3>0与元素选择结合起来。
最好的方法是什么? np.where()
,掩码,还是简单的索引?我按如下方式访问 Y3:
idx = pd.IndexSlice
print(df.loc[idx[:,:],idx[:,'Y3']] > 0)
X1 X2
Y3 Y3
A1 B1 True False
B2 True True
B3 True True
A2 B1 False True
B2 True True
B3 True False
编辑:
这就是我想要的,使用 for
循环:
A = ['A1','A2']
B = ['B1','B2','B3']
X = ['X1','X2']
Y = ['Y1','Y2','Y3']
miind = pd.MultiIndex.from_product([A,B])
micol = pd.MultiIndex.from_product([X,Y])
df = pd.DataFrame((np.arange(len(miind)*len(micol)) % 5).reshape(len(miind),len(micol)),
index=miind, columns=micol)
for i, a in enumerate(A):
df1 = df.loc[a]
for j,b in enumerate(B):
df2 = df1.loc[b]
for k,x in enumerate(X):
s1 = df2.loc[x]
if s1['Y3'] > 0:
df.loc[idx[a,b],idx[x,'Y1']] /= s1['Y3']
df.loc[idx[a,b],idx[x,'Y2']] /= s1['Y3']
print(df)
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0.000000 0.500000 2 3.000000 4.000000 0
B2 0.333333 0.666667 3 4.000000 0.000000 1
B3 0.500000 0.750000 4 0.000000 0.500000 2
A2 B1 3.000000 4.000000 0 0.333333 0.666667 3
B2 4.000000 0.000000 1 0.500000 0.750000 4
B3 0.000000 0.500000 2 3.000000 4.000000 0
但是,这个解决方案并不优雅,并且可能无法很好地适应更大的数据帧...
您可以堆叠和取消堆叠您的数据框:
# stack the dataframe
tmp = df.stack(level=0)
# divide the columns of the stacked dataframe
tmp.loc[tmp['Y3']!= 0, 'Y1'] /= tmp.loc[tmp['Y3']!= 0, 'Y3']
tmp.loc[tmp['Y3']!= 0, 'Y2'] /= tmp.loc[tmp['Y3']!= 0, 'Y3']
# unstack the divided dataframe
tmp = tmp.unstack(level=2)
此时,我们有:
Y1 Y2 Y3
X1 X2 X1 X2 X1 X2
A1 B1 0.000000 3.000000 0.500000 4.000000 2 0
B2 0.333333 4.000000 0.666667 0.000000 3 1
B3 0.500000 0.000000 0.750000 0.500000 4 2
A2 B1 3.000000 0.333333 4.000000 0.666667 0 3
B2 4.000000 0.500000 0.000000 0.750000 1 4
B3 0.000000 3.000000 0.500000 4.000000 2 0
还不错,列的级别不是我们想要的。让我们继续...
# reverse the column levels
tmp.columns = pd.MultiIndex.from_tuples((j,i) for i,j in tmp.columns)
# and sort the columns
result = tmp.sort_index(axis=1)
我们现在如预期的那样:
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0.000000 0.500000 2 3.000000 4.000000 0
B2 0.333333 0.666667 3 4.000000 0.000000 1
B3 0.500000 0.750000 4 0.000000 0.500000 2
A2 B1 3.000000 4.000000 0 0.333333 0.666667 3
B2 4.000000 0.000000 1 0.500000 0.750000 4
B3 0.000000 0.500000 2 3.000000 4.000000 0
我在 Python 中有一个 Pandas MultiIndex 数据框,其中包含两个级别的索引和列,如下所示:
miind = pd.MultiIndex.from_product([['A1','A2'],['B1','B2','B3']])
micol = pd.MultiIndex.from_product([['X1','X2'],['Y1','Y2','Y3']])
df = pd.DataFrame((np.arange(len(miind)*len(micol)) % 5).reshape(len(miind),len(micol)),
index=miind, columns=micol)
print(df)
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0 1 2 3 4 0
B2 1 2 3 4 0 1
B3 2 3 4 0 1 2
A2 B1 3 4 0 1 2 3
B2 4 0 1 2 3 4
B3 0 1 2 3 4 0
我想,对于每一行,当Y3不为0时,Y1和Y2除以Y3。我不知道如何将条件Y3>0与元素选择结合起来。
最好的方法是什么? np.where()
,掩码,还是简单的索引?我按如下方式访问 Y3:
idx = pd.IndexSlice
print(df.loc[idx[:,:],idx[:,'Y3']] > 0)
X1 X2
Y3 Y3
A1 B1 True False
B2 True True
B3 True True
A2 B1 False True
B2 True True
B3 True False
编辑:
这就是我想要的,使用 for
循环:
A = ['A1','A2']
B = ['B1','B2','B3']
X = ['X1','X2']
Y = ['Y1','Y2','Y3']
miind = pd.MultiIndex.from_product([A,B])
micol = pd.MultiIndex.from_product([X,Y])
df = pd.DataFrame((np.arange(len(miind)*len(micol)) % 5).reshape(len(miind),len(micol)),
index=miind, columns=micol)
for i, a in enumerate(A):
df1 = df.loc[a]
for j,b in enumerate(B):
df2 = df1.loc[b]
for k,x in enumerate(X):
s1 = df2.loc[x]
if s1['Y3'] > 0:
df.loc[idx[a,b],idx[x,'Y1']] /= s1['Y3']
df.loc[idx[a,b],idx[x,'Y2']] /= s1['Y3']
print(df)
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0.000000 0.500000 2 3.000000 4.000000 0
B2 0.333333 0.666667 3 4.000000 0.000000 1
B3 0.500000 0.750000 4 0.000000 0.500000 2
A2 B1 3.000000 4.000000 0 0.333333 0.666667 3
B2 4.000000 0.000000 1 0.500000 0.750000 4
B3 0.000000 0.500000 2 3.000000 4.000000 0
但是,这个解决方案并不优雅,并且可能无法很好地适应更大的数据帧...
您可以堆叠和取消堆叠您的数据框:
# stack the dataframe
tmp = df.stack(level=0)
# divide the columns of the stacked dataframe
tmp.loc[tmp['Y3']!= 0, 'Y1'] /= tmp.loc[tmp['Y3']!= 0, 'Y3']
tmp.loc[tmp['Y3']!= 0, 'Y2'] /= tmp.loc[tmp['Y3']!= 0, 'Y3']
# unstack the divided dataframe
tmp = tmp.unstack(level=2)
此时,我们有:
Y1 Y2 Y3
X1 X2 X1 X2 X1 X2
A1 B1 0.000000 3.000000 0.500000 4.000000 2 0
B2 0.333333 4.000000 0.666667 0.000000 3 1
B3 0.500000 0.000000 0.750000 0.500000 4 2
A2 B1 3.000000 0.333333 4.000000 0.666667 0 3
B2 4.000000 0.500000 0.000000 0.750000 1 4
B3 0.000000 3.000000 0.500000 4.000000 2 0
还不错,列的级别不是我们想要的。让我们继续...
# reverse the column levels
tmp.columns = pd.MultiIndex.from_tuples((j,i) for i,j in tmp.columns)
# and sort the columns
result = tmp.sort_index(axis=1)
我们现在如预期的那样:
X1 X2
Y1 Y2 Y3 Y1 Y2 Y3
A1 B1 0.000000 0.500000 2 3.000000 4.000000 0
B2 0.333333 0.666667 3 4.000000 0.000000 1
B3 0.500000 0.750000 4 0.000000 0.500000 2
A2 B1 3.000000 4.000000 0 0.333333 0.666667 3
B2 4.000000 0.000000 1 0.500000 0.750000 4
B3 0.000000 0.500000 2 3.000000 4.000000 0