【问题标题】:Drop Columns with more than 60 Percent of "empty" Values in Pandas删除 Pandas 中“空”值超过 60% 的列
【发布时间】:2022-04-13 02:08:21
【问题描述】:

我有一个这样的数据框:

import pandas as pd
data = {
    'c1': ['Test1','Test2','NULL','Test3',' ','Test4','Test4','Test1',"Test3"],
    'c2': [' ','Test1',' ','NULL',' ','NULL','NULL','NULL','NULL'],
    'c3': [0,0,0,0,0,1,5,0,0],
    'c4': ['NULL', 'Test2', 'Test1','Test1', 'Test2', 'Test2','Test1','Test1','Test2']
}
df = pd.DataFrame(data)
df

数据框如下所示:

    c1      c2      c3      c4
0   Test1           0       NULL
1   Test2   Test1   0       Test2
2   NULL            0       Test1
3   Test3   NULL    0       Test1
4                   0       Test2
5   Test4   NULL    1       Test2
6   Test4   NULL    5       Test1
7   Test1   NULL    0       Test1
8   Test3   NULL    0       Test2

我想删除所有“空”值超过 60% 的列。 “空”在我的情况下意味着值例如:''、'NULL' 或 0。有字符串(c1、c2、c4)和整数(c3)。

结果应该是只有 c1 和 c4 列的数据框。

    c1      c4
0   Test1   NULL
1   Test2   Test2
2   NULL    Test1
3   Test3   Test1
4           Test2
5   Test4   Test2
6   Test4   Test1
7   Test1   Test1
8   Test3   Test2

我不知道如何处理这个问题。我唯一想到的就是像

df.loc[:, (df != 0).any(axis=0)]

删除所有值为0、'NULL'等的所有列。

【问题讨论】:

标签: python pandas


【解决方案1】:

使用DataFrame.isin检查所有格式,然后获取mean作为阈值并通过boolean indexingloc过滤:

print (df.isin([' ','NULL',0]))
      c1     c2     c3     c4
0  False   True   True   True
1  False  False   True  False
2   True   True   True  False
3  False   True   True  False
4   True   True   True  False
5  False   True  False  False
6  False   True  False  False
7  False   True   True  False
8  False   True   True  False

print (df.isin([' ','NULL',0]).mean())
c1    0.222222
c2    0.888889
c3    0.777778
c4    0.111111
dtype: float64

df = df.loc[:, df.isin([' ','NULL',0]).mean() < .6]
print (df)
      c1     c4
0  Test1   NULL
1  Test2  Test2
2   NULL  Test1
3  Test3  Test1
4         Test2
5  Test4  Test2
6  Test4  Test1
7  Test1  Test1
8  Test3  Test2

【讨论】:

  • 非常感谢您的回答。尝试您的解决方案时,我注意到还有“真正的”空单元格。因此我添加了df = df.loc[:, df.isnull().mean() &lt; .6]。有没有办法将它与您的代码 (df = df.loc[:, df.isin([' ','NULL',0]).mean() &lt; .6]) 结合起来?
  • @Krypt - 我的第一个想法是df = df.loc[:, df.isin([' ','NULL',0, np.nan]).mean() &lt; .6],但未经测试。可以查一下吗?
  • @Krypt - 我只是通过data = { 'c1': ['Test1','Test2',np.nan,'Test3',' ','Test4','Test4','Test1',"Test3"], 'c2': [' ','Test1',' ','NULL',' ',np.nan,np.nan,'NULL',np.nan], 'c3': [0,0,0,0,0,1,5,0,0], 'c4': [np.nan, 'Test2', 'Test1','Test1', 'Test2', 'Test2','Test1','Test1','Test2'] } 测试它并且工作得很好。
  • 再次感谢。我应该提到我已经用np.nan 尝试过(就像你刚才建议的那样)。它适用于任何孤立的示例,但不幸的是不适用于我在 RapidMiner 中的特定应用程序。唯一可以摆脱这些列的是df.isnull。因此,我一直在寻找将这两个语句(df.isnull()df.isin())组合在“一行”中的任何解决方案。
  • @Krypt - 请检查df = df.loc[:, (df.isin([' ','NULL',0]) | df.isnull()).mean() &lt;= .6]
【解决方案2】:

您可以使用dropna thresh 参数删除列:

In [58]: df = df.replace([0,' ','NULL'],np.nan)
In[59]: df
Out[59]: 
      c1     c2   c3     c4
0  Test1    NaN  NaN    NaN
1  Test2  Test1  NaN  Test2
2    NaN    NaN  NaN  Test1
3  Test3    NaN  NaN  Test1
4    NaN    NaN  NaN  Test2
5  Test4    NaN  1.0  Test2
6  Test4    NaN  5.0  Test1
7  Test1    NaN  NaN  Test1
8  Test3    NaN  NaN  Test2

In [60]: df.dropna(thresh=df.shape[0]*0.6,how='all',axis=1)
Out[60]: 
      c1     c4
0  Test1    NaN
1  Test2  Test2
2    NaN  Test1
3  Test3  Test1
4    NaN  Test2
5  Test4  Test2
6  Test4  Test1
7  Test1  Test1
8  Test3  Test2

【讨论】:

  • 阈值定义为“需要很多非 NA 值”。所以在这个例子中,我们可能需要保持 thresh=df.shape[0]*0.4
【解决方案3】:

下面给出的解决方案非常小而且速度很快(在性能方面)

步骤:1 我们在每一列中找到空值的百分比

步骤:2 我们发现列表中的列名具有超过 60% 的空值

步骤:3 删除空值超过 60% 的列

import pandas as pd

data = {
    'c1': ['Test1','Test2','NULL','Test3',' ','Test4','Test4','Test1',"Test3"],
    'c2': [' ','Test1',' ','NULL',' ','NULL','NULL','NULL','NULL'],
    'c3': [0,0,0,0,0,1,5,0,0],
    'c4': ['NULL', 'Test2', 'Test1','Test1', 'Test2', 'Test2','Test1','Test1','Test2']
}
df = pd.DataFrame(data)

# Below code gives percentage of null in every column
null_percentage = df.isnull().sum()/df.shape[0]*100

# Below code gives list of columns having more than 60% null
col_to_drop = null_percentage[null_percentage>60].keys()

output_df = df.drop(col_to_drop, axis=1)

【讨论】:

    猜你喜欢
    • 2017-12-21
    • 2023-03-28
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    相关资源
    最近更新 更多