Python 从数据帧中删除包含空单元格的行

Python 从数据帧中删除包含空单元格的行,python,pandas,dataframe,drop,Python,Pandas,Dataframe,Drop,我有一个pd.DataFrame,它是通过解析一些excel电子表格创建的。具有空单元格的列。例如,下面是该列的频率输出,32320条记录缺少租户的值 我试图删除缺少租户的行,但是.isnull()选项无法识别缺少的值 >>> df['Tenant'].isnull().sum() 0 该列的数据类型为“Object”。在这种情况下发生了什么?如何删除缺少租户的记录?如果是np.nan对象,Pandas会将一个值识别为null,该对象将在数据框中打印为nan。缺少的值

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

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

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

该列的数据类型为“Object”。在这种情况下发生了什么?如何删除缺少租户的记录?

如果是
np.nan
对象,Pandas会将一个值识别为null,该对象将在数据框中打印为
nan
。缺少的值可能是空字符串,Pandas无法识别为null。要解决此问题,可以使用
replace()
,将空stings(或空单元格中的任何内容)转换为
np.nan
对象,然后在数据帧上调用
dropna()
,删除租户为空的行

为了演示,我们在
租户
列中创建了一个包含一些随机值和一些空字符串的数据帧:

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

如果某个值是
np.nan
对象,Pandas会将其识别为null,该对象将在数据帧中打印为
nan
。缺少的值可能是空字符串,Pandas无法识别为null。要解决此问题,可以使用
replace()
,将空stings(或空单元格中的任何内容)转换为
np.nan
对象,然后在数据帧上调用
dropna()
,删除租户为空的行

为了演示,我们在
租户
列中创建了一个包含一些随机值和一些空字符串的数据帧:

>>> 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_counts忽略NaN,因此您很可能处理的是“”

所以你可以像这样过滤掉它们

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

默认情况下,value_counts忽略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
这将输出(**-仅突出显示所需行):

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

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

您可以使用此变体:

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
这将输出(**-仅突出显示所需行):

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

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'])

有一种情况,单元格有空白,你看不见,使用

df['col'].replace('  ', np.nan, inplace=True)
若要将空白替换为NaN,则

df= df.dropna(subset=['col'])
Pythonic+Pandorable:
df[df['col'].astype(bool)]
空字符串是falsy,这意味着您可以对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
如果您的目标不仅是删除空字符串,而且还删除仅包含空格的字符串,请事先使用
str.strip

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz
比你想象的要快
.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)
Pythonic+Pandorable:
df[df['col'].astype(bool)]
空字符串是falsy,这意味着您可以对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
如果您的目标不仅是删除空字符串,而且还删除仅包含空格的字符串,请事先使用
str.strip

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz
比你想象的要快
.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)

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

New = New.drop_duplicates()
如果您特别希望删除列
Tenant
中空值的行,这将完成此工作

New = New[New.Tenant != '']
这也可用于删除具有特定值的行-只需将字符串更改为所需的值即可

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

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

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

New = New.drop_duplicates()
如果您特别希望删除列
Tenant
中空值的行,这将完成此工作

New = New[New.Tenant != '']
这也可用于删除具有特定值的行-只需将字符串更改为所需的值即可

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

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

非常感谢,我会尝试一下,然后回来@麦克马斯,有点好奇。当你可以做
pd.np.nan
时,为什么要导入numpy并使用
np.nan
?@propjk007,就像生活中的很多事情一样,有很多方法可以做很多事情,从my开始,似乎做
df[df['Tenant'].astype(bool)]
(假设没有空格字符——仅空字符串)比
df.replace('',np.nan).dropna(子集)快=['Tenant']
非常感谢,我会尝试一下,然后回来!@mcmath,有点好奇。当你可以做
pd.np.nan
的时候,你为什么要导入numpy并使用
np.nan
?@propjk007,就像生活中的很多事情一样,有很多方法可以做很多事情,从我的角度来看,它似乎在做
df[df]