如何在MultiIndex pandas dataframe的子集上根据条件设置值

22

我想从一个MultiIndex pandas数据框中取一个子集,测试小于零的值并将它们设置为零。

例如:

df = pd.DataFrame({('A','a'): [-1,-1,0,10,12],
                   ('A','b'): [0,1,2,3,-1],
                   ('B','a'): [-20,-10,0,10,20],
                   ('B','b'): [-200,-100,0,100,200]})

df[df['A']<0] = 0.0

提供

    A        B
    a   b    a     b
0  -1   0  -20  -200
1  -1   1  -10  -100
2   0   2    0     0
3  10   3   10   100
4  12  -1   20   200

这表明它无法根据条件进行设置。或者,如果我执行链接赋值:
df.loc[:,'A'][df['A']<0] = 0.0

这将给出相同的结果(并设置复制警告)。

我可以根据第一级是我想要的条件循环遍历每个列:

for one,two in df.columns.values:
    if one == 'A':
        df.loc[df[(one,two)]<0, (one,two)] = 0.0

这将产生所期望的结果:

    A       B
    a  b    a     b
0   0  0  -20  -200
1   0  1  -10  -100
2   0  2    0     0
3  10  3   10   100
4  12  0   20   200

在pandas中,最好的方法是什么?

2个回答

20

这是使用MultiIndex分层器的应用之一(也是使用它的主要动机之一),请参阅此处的文档。

In [20]: df = pd.DataFrame({('A','a'): [-1,-1,0,10,12],
                   ('A','b'): [0,1,2,3,-1],
                   ('B','a'): [-20,-10,0,10,20],
                   ('B','b'): [-200,-100,0,100,200]})

In [21]: df
Out[21]: 
    A      B     
    a  b   a    b
0  -1  0 -20 -200
1  -1  1 -10 -100
2   0  2   0    0
3  10  3  10  100
4  12 -1  20  200

In [22]: idx = pd.IndexSlice

In [23]: mask = df.loc[:,idx['A',:]]<0

In [24]: mask
Out[24]: 
       A       
       a      b
0   True  False
1   True  False
2  False  False
3  False  False
4  False   True

In [25]: df[mask] = 0

In [26]: df
Out[26]: 
    A      B     
    a  b   a    b
0   0  0 -20 -200
1   0  1 -10 -100
2   0  2   0    0
3  10  3  10  100
4  12  0  20  200

因为您正在使用列索引的第1级,所以下面的方法同样适用。上面的例子更通用,比如说您想对“a”这个列做同样的操作。

In [30]: df[df[['A']]<0] = 0

In [31]: df
Out[31]: 
    A      B     
    a  b   a    b
0   0  0 -20 -200
1   0  1 -10 -100
2   0  2   0    0
3  10  3  10  100
4  12  0  20  200

1
啊,好的,谢谢!使用切片器创建掩码看起来非常有用(可能需要在我的代码中更多地使用它)。第二个例子确实解决了我的具体问题。我之前不知道 df['A']df[['A']] 之间的区别。 - pbreach

0

您还可以使用内置的slice()函数。例如,要选择'A'列,请创建一个元组(Pandas将元组解释为MultiIndex),并使用slice(None)指示您想要第二级中的所有内容(('A', slice(None)))。

df = pd.DataFrame({
    ('A','a'): [-1,-1,0,10,12], ('A','b'): [0,1,2,3,-1], 
    ('B','a'): [-20,-10,0,10,20],('B','b'): [-200,-100,0,100,200]})


# replace every value in the 'A' columns less than 0 by 0
msk = df.loc[:, ('A', slice(None))] < 0
df[msk] = 0

要在第二层中选择列;例如,选择所有'a'列,请使用(slice(None), 'a'),其中slice(None)表示您不关心第一级中的内容。

# replace every value in the 'a' columns less than 0 by 0
msk = df.loc[:, (slice(None), 'a')] < 0
df[msk] = 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接