【问题标题】:pandas DataFrame set value on boolean maskpandas DataFrame 在布尔掩码上设置值
【发布时间】:2015-08-11 16:53:42
【问题描述】:

我正在尝试将 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

上面,我想用值30 替换掩码中的所有True 条目。

我可以改用df.replace,但这里的屏蔽感觉更高效、更直观。有人可以解释错误,并提供一种设置所有值的有效方法吗?

【问题讨论】:

  • 您能否确认我的回答或 JohnE 的结果是否是您想要的,并更新您的问题以清楚地表明这一点,谢谢
  • 谢谢,@EdChum。我想在掩码中设置True 值并保持False 值相同。为了清楚起见,我编辑了问题。
  • 别担心,我更新了我的答案,你只需反转掩码即可达到你想要的效果
  • 嘿,您的电话,但我并不是要您切换复选标记,只是想澄清所需的结果。如果您想将其切换回他的,我认为@EdChums 的答案会更简洁明了。
  • 是的,你是对的。他们都是很好的答案。对不起!

标签: python pandas


【解决方案1】:

不幸的是,您不能在混合数据类型上使用布尔掩码,您可以使用 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: 不能对带有非字符的混合类型进行就地布尔设置 np.nan 值

编辑

好的,经过一点误会你仍然可以使用where y 只是反转掩码:

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 当您使用where 时,掩码将在掩码为True 的位置生成原始值,other 值将用于掩码为False 的位置,因此other 的默认值是 NaN,所以看起来很混乱,但这是预期和期望的结果
  • 我同意这就是您的代码的工作方式和应该的方式,我只是注意到它似乎与所要求的相反。例如,如果您只在 A 列上运行 OP 的代码,它会生成 30 2 30
  • @JohnE 是的,这确实看起来模棱两可,我将他的问题读作替换 NaN 值的一种方式,但它读起来更像你的答案,但 OP 接受了我的答案,所以我不清楚他是否想要这个结果,但要求你的
  • 是的,不用担心。我刚刚注意到我们得到了完全相反的结果。我认为您的方法更简洁,并且对此表示赞同。
【解决方案2】:

如果您想使用不同的列来创建您的掩码,您需要调用 values 属性 em> 的数据框。


示例

假设我们想要根据B_1B_2 中的掩码替换A_1 和“A_2”中的值。例如,将A 中与B 中的空值相对应的值替换为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 属性正是我使我的面具工作所需要的。非常感谢!
【解决方案3】:

我不是 100% 确定,但我怀疑错误消息与跨不同 dtype 的缺失数据的处理方式不同这一事实有关。只有浮点数有 NaN,但整数可以自动转换为浮点数,所以这不是问题。但似乎混合数字 dtypes 和 object dtypes 并不那么容易......

不管怎样,您可以使用np.where 轻松绕过它:

df[:] = np.where( mask, 30, df ) 

    A   B
0  30  30
1   2   b
2  30   f

【讨论】:

    【解决方案4】:

    pandas 使用NaN 来标记无效或丢失的数据,并且可以跨类型使用,因为您的DataFrame 是混合的int 和字符串数据类型,它不会接受分配给单一类型(@987654324 除外) @) 因为这将通过就地分配在B 中创建混合类型(int 和str)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 2021-10-11
      • 2013-05-17
      • 1970-01-01
      • 2017-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多