Python 具有多索引列的数据框架中的布尔索引

Python 具有多索引列的数据框架中的布尔索引,python,pandas,Python,Pandas,我有一个带有多索引列的数据帧: import numpy as np import pandas as pd columns = pd.MultiIndex.from_arrays([['n1', 'n1', 'n2', 'n2'], ['p', 'm', 'p', 'm']]) values = [ [1, 2, 3, 4], [np.nan, 6, 7, 8], [np.nan, 10, np.nan, 12], ] df = pd

我有一个带有多索引列的数据帧:

import numpy as np
import pandas as pd

columns = pd.MultiIndex.from_arrays([['n1', 'n1', 'n2', 'n2'], ['p', 'm', 'p', 'm']])
values = [
    [1,      2,  3,      4],
    [np.nan, 6,  7,      8],
    [np.nan, 10, np.nan, 12],
]
df = pd.DataFrame(values, columns=columns)
现在,每当
p
NaN
时,我想将
m
设置为
NaN
。以下是我想要的结果:

    n1        n2     
     p    m    p    m
0  1.0  2.0  3.0  4.0
1  NaN  NaN  7.0  8.0
2  NaN  NaN  NaN  NaN
我知道如何找出
p
在哪里
NaN
,例如使用

mask = df.xs('p', level=1, axis=1).isnull()
但是,我不知道如何使用此掩码将
df
中相应的
m
值设置为
NaN
,您可以使用该掩码获取一个布尔数据数组,指示
p
列中的
n
值是否在级别
1
上,然后将
False
替换为
NaN
,并通过乘以结果替换
m
中的值:

x = df.loc[:, pd.IndexSlice[:,'p']].notna().replace({False:float('nan')}).values
df.loc[:, pd.IndexSlice[:,'m']] *= x

       n1        n2     
     p    m    p    m
0  1.0    2  3.0    4
1  NaN  NaN  7.0    8
2  NaN  NaN  NaN  NaN
您可以使用获取一个布尔数据数组,该数组指示
1级
1
上的
p
列中的值是否为
NaN
,然后将
False
替换为
NaN
,还可以通过乘以结果替换
m
中的值:

x = df.loc[:, pd.IndexSlice[:,'p']].notna().replace({False:float('nan')}).values
df.loc[:, pd.IndexSlice[:,'m']] *= x

       n1        n2     
     p    m    p    m
0  1.0    2  3.0    4
1  NaN  NaN  7.0    8
2  NaN  NaN  NaN  NaN

您可以堆叠和取消堆叠转置的数据帧,以便能够轻松选择和更改值,然后再次堆叠、取消堆叠和转置以将其取回:

df = df.T.stack(dropna=False).unstack(level=1)
df.loc[df['p'].isna(), 'm'] = np.nan

df = df.stack(dropna=False).unstack(1).T

在第一行之后,
df
是:

         m    p
n1 0   2.0  1.0
   1   6.0  NaN
   2  10.0  NaN
n2 0   4.0  3.0
   1   8.0  7.0
   2  12.0  NaN
最后:

    n1        n2     
     m    p    m    p
0  2.0  1.0  4.0  3.0
1  NaN  NaN  8.0  7.0
2  NaN  NaN  NaN  NaN

您可以堆叠和取消堆叠转置的数据帧,以便能够轻松选择和更改值,然后再次堆叠、取消堆叠和转置以将其取回:

df = df.T.stack(dropna=False).unstack(level=1)
df.loc[df['p'].isna(), 'm'] = np.nan

df = df.stack(dropna=False).unstack(1).T

在第一行之后,
df
是:

         m    p
n1 0   2.0  1.0
   1   6.0  NaN
   2  10.0  NaN
n2 0   4.0  3.0
   1   8.0  7.0
   2  12.0  NaN
最后:

    n1        n2     
     m    p    m    p
0  2.0  1.0  4.0  3.0
1  NaN  NaN  8.0  7.0
2  NaN  NaN  NaN  NaN

这是可行的,但请注意,
堆栈
/
取消堆栈
组合对可能不需要的列进行排序。这是可行的,但请注意,
堆栈
/
取消堆栈
组合对可能不需要的列进行排序。