pandas DataFrame 布尔索引设置值

21

我试图将pandas DataFrame中的多个不同值全部设置为相同的值。我以为我理解了pandas的布尔索引,但是我没有找到任何关于这个特定错误的资源。

import pandas as pd 
df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
mask = df.isin([1, 3, 12, 'a'])
df[mask] = 30
Traceback (most recent call last):
...
TypeError: Cannot do inplace boolean setting on mixed-types with a non np.nan value
上面,我想将遮罩中所有的True替换为值30。 我可以使用df.replace进行替换,但在这里使用遮罩感觉更有效和直观。有人能解释一下错误,并提供一种高效的方法来设置所有的值吗?

1
你能否确认我的答案或JohnE的结果是否符合您的要求,并更新您的问题以清楚地表明这一点,谢谢。 - EdChum
谢谢,@EdChum。我想将掩码中的“True”值设置为新值,并保留“False”值不变。我已经编辑了问题以便更清楚地表达。 - Michael K
没关系,我更新了我的回答,你只需要反转掩码就可以实现你想要的。 - EdChum
嘿,你自己决定吧,但我并不是想让你改变复选框,只是想澄清期望的结果。如果你想切换回@EdChums的答案,我认为他的答案更简洁明了一些。 - JohnE
是的,你说得对。它们都是好答案。对不起! - Michael K
4个回答

27
很遗憾,您不能对混合数据类型使用布尔掩码。您可以使用pandas的where函数来设置值:
In [59]:
df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
mask = df.isin([1, 3, 12, 'a'])
df = df.where(mask, other=30)
df

Out[59]:
    A   B
0   1   a
1  30  30
2   3  30

注意:如果您在where方法中使用了inplace=True,那么上述代码将会失败,因此df.where(mask, other=30, inplace=True)会提示错误信息:

TypeError: Cannot do inplace boolean setting on mixed-types with a non np.nan value

编辑

好的,在一些误解之后,您仍然可以使用where方法,只需要翻转掩码即可:

In [2]:    
df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
mask = df.isin([1, 3, 12, 'a'])
df.where(~mask, other=30)

Out[2]:
    A   B
0  30  30
1   2   b
2  30   f

结果正确吗?应该在True或False值中填入30吗?这与我认为的要求相反(尽管我可能弄反了),通过取掩码的补集可以轻松地将其反转。 - JohnE
@JohnE 当你使用 where 时,掩码将产生原始值,其中掩码为 True,而 other 值将用于掩码为 False 的情况,因此 other 的默认值为 NaN,所以看起来很困惑,但这是预期和期望的结果。 - EdChum
我认同你的代码是这样工作的,而且应该是这样的,只是我注意到它似乎与要求相反。例如,如果在仅针对A列运行OP的代码,则会生成“30 2 30”。 - JohnE
@JohnE 是的,这似乎有歧义,我把他的问题看作是替换 NaN 值的一种方式,但它更像是你的答案,但 OP 接受了我的答案,所以我不确定他是否想要这个结果,但却问了你的答案。 - EdChum
没问题,我只是注意到我们得到了完全相反的结果。我认为你的方法更简洁,已经点赞了。 - JohnE
双重否定真的有必要吗?我想将“所有内容掩码”设置为一个值。我应该进行掩码,然后将掩码中的非非内容设置为该值吗?这对我来说毫无意义。 - Gulzar

4
如果您想使用不同的列创建掩码,您需要调用数据框的“值”属性。

示例

假设我们想根据B_1B_2中的掩码替换A_1和'A_2'中的值。例如,将与B中的空值对应的A中的那些值(更改为999)替换。

原始数据框:

   A_1  A_2  B_1  B_2
0    1    4    y    n
1    2    5    n  NaN
2    3    6  NaN  NaN

期望的数据框架

   A_1  A_2  B_1  B_2
0    1    4    y    n
1    2  999    n  NaN
2  999  999  NaN  NaN

这段代码:

df = pd.DataFrame({
     'A_1': [1, 2, 3], 
     'A_2': [4, 5, 6], 
     'B_1': ['y', 'n', np.nan], 
     'B_2': ['n', np.nan, np.nan]})

_mask = df[['B_1', 'B_2']].notnull().values
df[['A_1', 'A_2']] = df[['A_1','A_2']].where(_mask, other=999)



   A_1  A_2
0    1    4
1    2  999
2  999  999

谢谢您的答案。.values属性正是我需要的,这让我的掩码工作得很好。非常感谢! - Tim Mayes

3
我不是100%确定,但我怀疑错误信息与不同数据类型缺失数据的处理方式不相同有关。只有浮点数具有NaN,但整数可以自动转换为浮点数,因此在那里没有问题。但是混合数字数据类型和对象数据类型似乎并不容易解决... 无论如何,您可以很容易地通过np.where解决这个问题:
df[:] = np.where( mask, 30, df ) 

    A   B
0  30  30
1   2   b
2  30   f

0

pandas 使用 NaN 来标记无效或缺失的数据,并且可以跨类型使用。由于您的 DataFrame 包含混合的整数和字符串数据类型,因此它不会接受分配给单个类型(除了 NaN)的操作,因为这将在通过原地赋值创建混合类型(int 和 str)的 B 中。

@JohnE 方法使用 np.where 创建一个新的 DataFrame,其中列 B 的类型是对象而不是初始示例中的字符串。


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