根据包含空值的其他列设置掩码的值

4
我想检查特定的列(大约5或6个),如果全部为空,则将名为has_nan的另一列从0更改为1。我知道如何过滤/屏蔽,但是在使用loc时,会出现可怕的SettingWithCopyWarning警告。
这里有一个小例子来说明,虽然不完全相同,但它突出了问题:
df = pd.DataFrame([np.random.randint(0,100,3), np.random.randint(0,100,3),
                 np.random.randint(0,100,3), np.random.randint(0,100,3)],
                 columns=['foo', 'bar', 'has_nan'])
for i in ['use_1', 'use_2']:
    df[i] = 2 * ['5'] + 2 * [np.nan]

df.loc[df.use_1.isna() & df.use_2.isna()]['has_nan'] = 'yes'
4个回答

4

避免链式索引。 在这里,您可以使用布尔序列:

df['has_nan'] = df[['use_1', 'use_2']].isnull().all(1)

使用布尔序列,即仅包含True/False值的序列,是推荐的方法。如果您坚持将其转换为'yes'/'no'字符串,则可以通过字典映射在后续步骤中完成:
mapper = {1: 'yes', 0: 'no'}
df['has_nan'] = df['has_nan'].map(mapper)

谢谢,这个很好用。你认为jorijnsmit的答案是链式索引吗?它非常接近我尝试的方法,但不会引发警告。 - Josh Friedlander
@JoshFriedlander,jorijnsmit的答案并不是链式索引。只是因为它不依赖于映射布尔系列而效率低下。 - jpp
1
明白了,谢谢!只是提醒一下,我正在实践中使用您的代码-决定将jorijnsmit标记为接受的答案,因为它更接近我的要求。 - Josh Friedlander

1

1
你是指这个吗?:

df['has_nan'][df['column_name'].isna()] = 0
df['has_nan'][~df['column_name'].isna()] = 1

当我这样做时,我会收到“SettingWithCopyWarning”警告。 - Josh Friedlander
我并没有得到什么特别的信息。只要你确定这就是你想要做的,我认为你可以忽略它。 - anky
1
好的,谢谢。我想我会让它保持开放状态更长一些,看看是否有人可以进一步扩展为什么会出现这个错误,并分享最佳实践。 - Josh Friedlander
1
当然可以 :) 我会一直关注这篇帖子的 :) 但是,当您使用 .loc 时,您正在切片 df 的一部分并对其进行操作,一旦切片,如果将 df 重新分配给原始数据,则实际数据将丢失,我想这就是警告的原因。 - anky
知道这点很好。所以你的答案避免使用切片来解决问题了? - Josh Friedlander

0

做法之一是:

df['has_nan'][df.use_1.isna() & df.use_2.isna()] = 'yes'

当您执行以下操作时,它会返回一份副本(这就是警告的目的),并且不起作用:
df.loc[df.use_1.isna() & df.use_2.isna()]['has_nan'] = 'yes'

这两个都会发出警告,您可以使用以下方法将其静音:

pd.set_option('mode.chained_assignment', None)

阅读评估顺序很重要以获取详细解释。


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