删除包含来自 pandas DataFrame 的空单元格的行

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

>>> value_counts(Tenant, normalize=False)
32320
Thunderhead                8170
Big Data Others            5700
Cloud Cruiser              5700
Partnerpedia               5700
Comcast                    5700
SDP                        5700
Agora                      5700
dtype: int64

我试图删除 Tenant 丢失的行,但是 .isnull()选项不能识别丢失的值。

>>> df['Tenant'].isnull().sum()
0

该列的数据类型为“ Object”。这个案子到底是怎么回事?如果 房客丢失了,我怎样才能丢失记录?

466536 次浏览

如果一个值是 np.nan对象,熊猫将识别为 null,这个值将在 DataFrame 中打印为 NaN。您丢失的值可能是空字符串,熊猫不会将其识别为 null。为了解决这个问题,您可以使用 replace()将空的 stings (或空单元格中的任何内容)转换为 np.nan对象,然后在 DataFrame 上调用 dropna()以删除包含空租户的行。

为了演示,我们在 Tenants列中创建一个带有一些随机值和一些空字符串的 DataFrame:

>>> 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

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

>>> 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

现在我们可以删除空值:

>>> 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

Value _ count 默认省略 NaN,因此最有可能处理的是“”。

所以你可以把它们过滤掉

filter = df["Tenant"] != ""
dfNew = df[filter]

你可以使用这个变体:

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

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

   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

因此,要放弃所有没有“教育”价值的东西,可以使用下面的代码:

df_vals = df_vals[~df_vals['education'].isnull()]

(‘ ~’表示非)

结果:

   age education gender name
0   39        ma      m   n1
2   27    school      f   n3
4   36        ba      f   n5

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

df['col'].replace('  ', np.nan, inplace=True)

取代空白为 NaN,然后

df= df.dropna(subset=['col'])

Python + 潘多拉: df[df['col'].astype(bool)]

空字符串是 false,这意味着您可以像下面这样过滤 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
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

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

df[df['B'].str.strip().astype(bool)]
A    B
0  0  foo
2  2  bar
4  4  xyz

比你想的要快

.astype是一个矢量化的操作,这比目前为止提出的所有选项都要快。至少,从我的测试来看是这样的。

这里是一个时间比较,我已经抛出了一些其他方法,我可以想到的。

enter image description here

参考基准代码:

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)

如果您不关心丢失文件所在的列,考虑到数据框名为 New,并且希望将新的数据框分配给同一个变量,那么只需运行

New = New.drop_duplicates()

如果您特别希望删除列 Tenant中的空值的行,这将完成这项工作

New = New[New.Tenant != '']

这也可用于移除具有特定值的行——只需将字符串更改为所需的值即可。

注意 : 如果不是空字符串,而是 NaN,则

New = New.dropna(subset=['Tenant'])

或者,您可以使用 query

  • 如果缺少的值是空字符串:

    df.query('Tenant != ""')
    
  • 如果缺少的值是 NaN:

    df.query('Tenant == Tenant')
    

    (这是从 np.nan != np.nan开始的)

对于从包含空字符串单元格的 csv/tsv 文件中读取数据的任何人,“熊猫”会自动将其转换为 NaN 值(参见 文件)。假设这些单元格在列“ c2”中,过滤它们的方法是:

df[~df["c2"].isna()]

请注意,波浪线运算符是按位求逆的。