【问题标题】:Drop rows with NaNs based on combination of different columns subsets根据不同列子集的组合删除具有 NaN 的行
【发布时间】:2021-03-16 23:15:54
【问题描述】:

我想根据列子集的组合删除所有具有 NaN 值的行。让我们用一个简单的例子来演示一下:

df = pd.DataFrame(
    [[1, np.nan, 3, 4], [1, 2, 3, 4], [np.nan, np.nan, 3, 4], [1, np.nan, np.nan, 4], [1, 2, np.nan, np.nan]],
    columns=["a1", "a2", "b1", "b2"],
)

print(df)
#    a1   a2   b1   b2
# 0  1.0  NaN  3.0  4.0
# 1  1.0  2.0  3.0  4.0
# 2  NaN  NaN  3.0  4.0
# 3  1.0  NaN  NaN  4.0
# 4  1.0  2.0  NaN  NaN

我想删除 {a1, a2}{b1, b2} 集合中的 all 特征为 NaN 的行。所以输出将是(删除第 2 行和第 4 行):

   a1   a2   b1   b2
0  1.0  NaN  3.0  4.0
1  1.0  2.0  3.0  4.0
3  1.0  NaN  NaN  4.0

理想情况下,我需要df.dropna(how="all", subset=["a1", "a2"])df.dropna(how="all", subset=["b1", "b2"]) 的某种组合。在这种简单的情况下,它不会是这样的问题,但是如果有例如10 个不同的子集? (在我的真实场景中,它几乎是 50。)

是否有任何使用 pandas 或任何过滤器的智能解决方案如何组合这些子集并为dropna 方法创建正确的条件?

动机:只是为了让您了解我为什么需要这样的东西,因为我有不同的功能集(ab、...)组合在一个 DataFrame 中,我需要分别处理这些功能。一些 NaN 是可以的,但如果任何特征的任何行都充满了 NaN,这意味着测量错误,我也想为任何其他特征删除这一行(想象一下索引是测量时间,如果一组features 不正确我不想保留它,即使其他功能集都很好)。

【问题讨论】:

  • 如果您有一个可以生成列子集的生成器函数,那么您可以使用它在循环中指定您的 dropna 子集。除此之外,我不立即知道这样做的方法
  • @Nerxis 子集可以是列的任意组合,例如{'a1', 'b2'}{'c1', 'd2'}
  • 是的,它可能是。在我的情况下,它通常是 {"temp_sensor_1", "temp_sensor_2", "temp_ambient", ...} 和其他像 {"volt_p_phase_a", "volt_s_phase_a", "volt_main_lv_phase_a", ...} 等等。但通常它可能是任何组合,它取决于传感器组,因此即使是不同类型的测量也可以在一个组中。

标签: python pandas dataframe


【解决方案1】:

方法

对于预定义subsets 列表中的每个subset,您可以测试该子集的列是否存在沿axis=1 的任何非NaN 值以创建布尔掩码,然后您可以reducenp.logical_and 的每个子集对应的所有布尔掩码以创建结果布尔值mask,然后可用于过滤数据框中的行。

subs = [{'a1', 'a2'}, {'b1', 'b2'}]
mask = np.logical_and.reduce([df[s].notna().any(1) for s in subs])

结果

>>> df[mask]

    a1   a2   b1   b2
0  1.0  NaN  3.0  4.0
1  1.0  2.0  3.0  4.0
3  1.0  NaN  NaN  4.0

【讨论】:

  • @jezrael:谢谢你们的解决方案,我会接受这个答案有两个原因 - 它更通用(适用于任何子集,对于后者,我需要使用一些映射)对于大型 DataFrame,它的速度要快得多。
【解决方案2】:

首先比较所有值的不缺失值,然后按列的第一个字母与GroupBy.any 分组以测试组是否只有NaN,最后按DataFrame.all 过滤以获取匹配掩码的所有行:

print (df.columns.str[0])
Index(['a', 'a', 'b', 'b'], dtype='object')


print (df.notna().groupby(df.columns.str[0], axis=1).any())
       a      b
0   True   True
1   True   True
2  False   True
3   True   True
4   True  False

df = df[df.notna().groupby(df.columns.str[0], axis=1).any().all(axis=1)]
print (df)
    a1   a2   b1   b2
0  1.0  NaN  3.0  4.0
1  1.0  2.0  3.0  4.0
3  1.0  NaN  NaN  4.0

【讨论】:

  • 这是一个很好的解决方案,带有notna 方法和分组。您能否概括一下您的解决方案以使用自定义组(例如{"a", "b"}{"c", "d"},您不能使用str[0])?
  • @Nerxis - Groupby 需要相同的值,所以唯一可能的解决方案是再次使用df.columns.str[0],然后将a 映射到abaa,a,a,a in样本数据。不确定是否了解需要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
  • 2011-08-23
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多