【问题标题】:drops a column if it exceeds a specific number of NA values如果超过特定数量的 NA 值,则删除一列
【发布时间】:2018-12-22 11:08:42
【问题描述】:

我想编写一个程序,如果它超过特定数量的 NA 值,则删除一列。这就是我所做的。

def check(x):
for column in df:
    if df.column.isnull().sum() > 2:
        df.drop(column,axis=1)

上面的代码执行没有错误,但是在执行df.apply(check)的时候,有很多错误。

P.S:我知道df.dropna(thresh,axis)中的thresh争论

任何提示?为什么我的代码不起作用?

谢谢

【问题讨论】:

  • 是的,创建一个蒙版并应用。高效 pandas 的关键是避免循环!

标签: python python-3.x pandas dataframe data-analysis


【解决方案1】:

我认为这里最好使用dropna 和参数thresh

thresh : int,可选

需要很多非 NA 值。

所以对于矢量化解决方案,从DataFrame 的长度中减去它:

N = 2
df = df.dropna(thresh=len(df)-N, axis=1)
print (df)
   A  D    E  F
0  a  1  5.0  a
1  b  3  3.0  a
2  c  5  6.0  a
3  d  7  9.0  b
4  e  1  2.0  b
5  f  0  NaN  b

我建议将DataFrame.pipe 用于输入DataFrame 的应用函数,并将df.column 更改为df[column],因为带有来自变量的动态列名的点表示法失败(它尝试选择列名column):

df = pd.DataFrame({'A':list('abcdef'),
                   'B':[np.nan,np.nan,np.nan,5,5,np.nan],
                   'C':[np.nan,8,np.nan,np.nan,2,3],
                   'D':[1,3,5,7,1,0],
                   'E':[5,3,6,9,2,np.nan],
                   'F':list('aaabbb')})

print (df)
   A    B    C  D    E  F
0  a  NaN  NaN  1  5.0  a
1  b  NaN  8.0  3  3.0  a
2  c  NaN  NaN  5  6.0  a
3  d  5.0  NaN  7  9.0  b
4  e  5.0  2.0  1  2.0  b
5  f  NaN  3.0  0  NaN  b

def check(df):
    for column in df:
        if df[column].isnull().sum() > 2:
            df.drop(column,axis=1, inplace=True)
    return df
            
print (df.pipe(check))
   A  D    E  F
0  a  1  5.0  a
1  b  3  3.0  a
2  c  5  6.0  a
3  d  7  9.0  b
4  e  1  2.0  b
5  f  0  NaN  b
        
        

【讨论】:

  • 工作了,顺便说一句,为什么`apply`方法在这里不适用?
  • 因为.apply每列或行单独循环,这里需要输入所有DataFrame
【解决方案2】:

尽管 jezrael 的回答有效,但这不是您应该采用的方法。相反,创建一个掩码:~df.isnull().sum().gt(2) 并将其与.loc[:,m] 一起应用以访问列。

完整示例:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A':list('abcdef'),
    'B':[np.nan,np.nan,np.nan,5,5,np.nan],
    'C':[np.nan,8,np.nan,np.nan,2,3],
    'D':[1,3,5,7,1,0],
    'E':[5,3,6,9,2,np.nan],
    'F':list('aaabbb')
})

m = ~df.isnull().sum().gt(2)
df = df.loc[:,m]

print(df)

返回:

   A  D    E  F
0  a  1  5.0  a
1  b  3  3.0  a
2  c  5  6.0  a
3  d  7  9.0  b
4  e  1  2.0  b
5  f  0  NaN  b

说明

假设我们在应用之前打印列和掩码。

print(df.columns.tolist())
print(m.tolist())

它会返回这个:

['A', 'B', 'C', 'D', 'E', 'F']
[True, False, False, True, True, True]

B 和 C 列是不需要的 (False)。应用遮罩时它们会被移除。

【讨论】:

  • 谢谢,。作为 pandas 编程的初学者,您能解释一下代码中“~df”的用法吗?我也尝试阅读官方的 pandas.df.mask 页面,但什么都看不懂。您知道一些更简单的掩码功能示例吗?
  • @DRPR 好的,问题是......我的意思是带有真假的数组。 ~ 符号只做一件事。它使 True->False 和 False->True。在您的情况下,您希望删除 > 2 的列,但实际上如果您将其转过来,您希望保留 NOT 符合此条件的列。
  • @jpp - 我同意,最好使用矢量化解决方案,所以答案是用 dropna 编辑的
【解决方案3】:

或者,您可以使用计算非空值的count

In [23]: df.loc[:, df.count().gt(len(df.index) - 2)]
Out[23]:
   A  D    E  F
0  a  1  5.0  a
1  b  3  3.0  a
2  c  5  6.0  a
3  d  7  9.0  b
4  e  1  2.0  b
5  f  0  NaN  b

【讨论】:

  • 对我来说最容易理解的答案。谢谢