Python Pandas DataFrame删除空单元格

Amr*_*ant 53 python pandas

我有一个通过解析一些excel电子表格创建的pd.DataFrame.其中一列有空单元格.例如,下面是该列频率的输出,32320记录缺少租户的值.

   In [67]: value_counts(Tenant,normalize=False)
   Out[67]:
                              32320
   Thunderhead                8170
   Big Data Others            5700
   Cloud Cruiser              5700
   Partnerpedia               5700
   Comcast                    5700
   SDP                        5700
   Agora                      5700
   dtype: int64
Run Code Online (Sandbox Code Playgroud)

我试图删除租户丢失的行,但是isnull选项无法识别缺失的值.

   In [71]: df['Tenant'].isnull().sum()
   Out[71]: 0
Run Code Online (Sandbox Code Playgroud)

该列的数据类型为"Object".在这种情况下发生了什么?如何删除租户丢失的记录?

McM*_*ath 111

如果它是一个np.nan对象,Pandas会将值识别为null ,该对象将NaN在DataFrame中打印.您的缺失值可能是空字符串,Pandas不会将其识别为null.要解决此问题,您可以使用空转(或空单元格中的任何内容)将np.nan对象转换为对象replace(),然后调用dropna()DataFrame以删除具有空租户的行.

为了演示,我创建了一个DataFrame,其中包含一些随机值和Tenants列中的一些空字符串:

>>> import pandas as pd
>>> import numpy as np
>>> 
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
>>> df['Tenant'] = np.random.choice(['Babar', 'Rataxes', ''], 10)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239         
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214         
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640         
Run Code Online (Sandbox Code Playgroud)

现在我Tenantsnp.nan对象替换列中的任何空字符串,如下所示:

>>> df['Tenant'].replace('', np.nan, inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239      NaN
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214      NaN
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640      NaN
Run Code Online (Sandbox Code Playgroud)

现在我可以删除空值:

>>> df.dropna(subset=['Tenant'], inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
Run Code Online (Sandbox Code Playgroud)

  • @propjk007 pandas.np 模块已弃用,并将在未来版本中从 pandas 中删除。直接导入numpy而不是pd.np.nan (3认同)
  • @mcmath,有点好奇。为什么可以导入`pd.np.nan`时导入numpy并使用`np.nan`? (2认同)
  • @ propjk007,就像生活中的许多事情一样,有很多方法可以做很多事情 (2认同)
  • 从我的[测试](/sf/answers/3969604341/)来看,它似乎在做`df[df['Tenant'].astype(bool)]`(假设没有空格字符——只有空字符串) 比 `df.replace('', np.nan).dropna(subset=['Tenant'])` **更快** (2认同)

Bob*_*ner 29

value_counts默认省略NaN,因此您最有可能处理"".

所以你可以像过滤它们一样

filter = df["Tenant"] != ""
dfNew = df[filter]
Run Code Online (Sandbox Code Playgroud)


cs9*_*s95 10

Pythonic + Pandorable: df[df['col'].astype(bool)]

空字符串是虚假的,这意味着您可以像这样过滤布尔值:

df = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})
df
   A    B
0  0  foo
1  1     
2  2  bar
3  3     
4  4  xyz
Run Code Online (Sandbox Code Playgroud)

df['B'].astype(bool)                                                                                                                      
0     True
1    False
2     True
3    False
4     True
Name: B, dtype: bool

df[df['B'].astype(bool)]                                                                                                                  
   A    B
0  0  foo
2  2  bar
4  4  xyz
Run Code Online (Sandbox Code Playgroud)

如果您的目标不仅是删除空字符串,而且还删除仅包含空格的字符串,请str.strip事先使用:

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz
Run Code Online (Sandbox Code Playgroud)

比您想像的快

.astype是向量化操作,比到目前为止提供的每个选项都要快。至少从我的测试来看。YMMV。

这是一个时序比较,我想了一些其他方法。

在此处输入图片说明

基准测试代码,以供参考:

import pandas as pd
import perfplot

df1 = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})

perfplot.show(
    setup=lambda n: pd.concat([df1] * n, ignore_index=True),
    kernels=[
        lambda df: df[df['B'].astype(bool)],
        lambda df: df[df['B'] != ''],
        lambda df: df[df['B'].replace('', np.nan).notna()],  # optimized 1-col
        lambda df: df.replace({'B': {'': np.nan}}).dropna(subset=['B']),  
    ],
    labels=['astype', "!= ''", "replace + notna", "replace + dropna", ],
    n_range=[2**k for k in range(1, 15)],
    xlabel='N',
    logx=True,
    logy=True,
    equality_check=pd.DataFrame.equals)
Run Code Online (Sandbox Code Playgroud)

  • 正如 bool(math.nan) 一样,这是正确的 Python 行为。如果 math.nan 需要显式测试其存在或不存在,那么 np.NaN 也应该如此。 (2认同)
  • @chsymann 问题是关于空字符串。如果您需要删除 nan,“dropna” 是迄今为止最惯用的方法 (2认同)

Ami*_*r F 7

您可以使用此变体:

import pandas as pd
vals = {
    'name' : ['n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7'],
    'gender' : ['m', 'f', 'f', 'f',  'f', 'c', 'c'],
    'age' : [39, 12, 27, 13, 36, 29, 10],
    'education' : ['ma', None, 'school', None, 'ba', None, None]
}
df_vals = pd.DataFrame(vals) #converting dict to dataframe
Run Code Online (Sandbox Code Playgroud)

这将输出(** - 仅突出显示所需的行):

   age education gender name
0   39        ma      m   n1 **
1   12      None      f   n2    
2   27    school      f   n3 **
3   13      None      f   n4
4   36        ba      f   n5 **
5   29      None      c   n6
6   10      None      c   n7
Run Code Online (Sandbox Code Playgroud)

因此,要删除没有“教育”值的所有内容,请使用以下代码:

df_vals = df_vals[~df_vals['education'].isnull()] 
Run Code Online (Sandbox Code Playgroud)

('~' 表示 NOT)

结果:

   age education gender name
0   39        ma      m   n1
2   27    school      f   n3
4   36        ba      f   n5
Run Code Online (Sandbox Code Playgroud)


Lea*_*arn 7

有一种情况,细胞有空白,你看不到它,使用

df['col'].replace('  ', np.nan, inplace=True)
Run Code Online (Sandbox Code Playgroud)

将空白替换为NaN,

然后

df= df.dropna(subset=['col'])
Run Code Online (Sandbox Code Playgroud)