从 pandas DataFrame 中删除包含空单元格的行
Drop rows containing empty cells from a pandas DataFrame
我有一个 pd.DataFrame
是通过解析一些 excel 电子表格创建的。其中一列有空单元格。例如,下面是该列频率的输出,32320 条记录缺少 Tenant.
的值
>>> 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"。在这种情况下发生了什么?如何删除缺少 Tenant 的记录?
如果 Pandas 是一个 np.nan
对象,它会将值识别为 null,这将在 DataFrame 中打印为 NaN
。您的缺失值可能是空字符串,Pandas 无法将其识别为 null。要解决此问题,您可以使用 replace()
将空字符串(或空单元格中的任何内容)转换为 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_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
这将输出(** - 仅突出显示所需的行):
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
所以要删除没有 'education' 值的所有内容,请使用以下代码:
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
出现单元格有白色的情况space,看不到,用
df['col'].replace(' ', np.nan, inplace=True)
将白色 space 替换为 NaN,然后
df= df.dropna(subset=['col'])
Pythonic + Pandorable:df[df['col'].astype(bool)]
空字符串是假的,这意味着您可以像这样过滤 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
是一个矢量化操作,这比目前提供的每个选项都快。至少,从我的测试来看。 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)
如果您不关心丢失文件所在的列,考虑到数据框的名称为 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 文件读取数据的任何人,pandas 会自动将它们转换为 NaN 值(请参阅 documentation)。假设这些单元格在“c2”列中,过滤掉它们的方法是:
df[~df["c2"].isna()]
请注意,波浪号运算符会按位求反。
我有一个 pd.DataFrame
是通过解析一些 excel 电子表格创建的。其中一列有空单元格。例如,下面是该列频率的输出,32320 条记录缺少 Tenant.
>>> 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"。在这种情况下发生了什么?如何删除缺少 Tenant 的记录?
Pandas 是一个 np.nan
对象,它会将值识别为 null,这将在 DataFrame 中打印为 NaN
。您的缺失值可能是空字符串,Pandas 无法将其识别为 null。要解决此问题,您可以使用 replace()
将空字符串(或空单元格中的任何内容)转换为 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_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
这将输出(** - 仅突出显示所需的行):
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
所以要删除没有 'education' 值的所有内容,请使用以下代码:
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
出现单元格有白色的情况space,看不到,用
df['col'].replace(' ', np.nan, inplace=True)
将白色 space 替换为 NaN,然后
df= df.dropna(subset=['col'])
Pythonic + Pandorable:df[df['col'].astype(bool)]
空字符串是假的,这意味着您可以像这样过滤 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
是一个矢量化操作,这比目前提供的每个选项都快。至少,从我的测试来看。 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)
如果您不关心丢失文件所在的列,考虑到数据框的名称为 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 文件读取数据的任何人,pandas 会自动将它们转换为 NaN 值(请参阅 documentation)。假设这些单元格在“c2”列中,过滤掉它们的方法是:
df[~df["c2"].isna()]
请注意,波浪号运算符会按位求反。