在熊猫中用NaN替换空白值(空白)


150

我想在包含空格(任意数量)的Pandas数据框中找到所有值,并用NaN替换这些值。

有什么想法可以改善吗?

基本上我想把这个:

                   A    B    C
2000-01-01 -0.532681  foo    0
2000-01-02  1.490752  bar    1
2000-01-03 -1.387326  foo    2
2000-01-04  0.814772  baz     
2000-01-05 -0.222552         4
2000-01-06 -1.176781  qux     

变成这个:

                   A     B     C
2000-01-01 -0.532681   foo     0
2000-01-02  1.490752   bar     1
2000-01-03 -1.387326   foo     2
2000-01-04  0.814772   baz   NaN
2000-01-05 -0.222552   NaN     4
2000-01-06 -1.176781   qux   NaN

我已经用下面的代码做到了,但是这很丑。这不是Pythonic,而且我敢肯定,这也不是最有效的熊猫使用方式。我遍历每一列,并对通过应用对每个值进行正则表达式搜索(在空格上匹配)的函数生成的列掩码进行布尔替换。

for i in df.columns:
    df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None

通过仅迭代可能包含空字符串的字段,可以对它进行一些优化:

if df[i].dtype == np.dtype('object')

但这并没有太大的改善

最后,此代码将目标字符串设置为None,该字符串可与Pandas的like函数一起使用fillna(),但是如果我实际上可以NaN直接插入而不是,那么这样做对完整性很有帮助None


2
您真正想要的是能够replace与正则表达式一起使用...(也许应该将其作为功能部件请求)。
安迪·海登

3
我为此功能发布了一个github问题:github.com/pydata/pandas/issues/2285。会感激公关!:)
Chang She

对于那些想将一个空白字符完全丢失的人,请参见下面的简单解决方案
Ted Petrou

Answers:


198

我认为可以df.replace()做到,因为熊猫0.13

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

# replace field that's entirely space (or empty) with NaN
print(df.replace(r'^\s*$', np.nan, regex=True))

产生:

                   A    B   C
2000-01-01 -0.532681  foo   0
2000-01-02  1.490752  bar   1
2000-01-03 -1.387326  foo   2
2000-01-04  0.814772  baz NaN
2000-01-05 -0.222552  NaN   4
2000-01-06 -1.176781  qux NaN

正如Temak指出的那样,请df.replace(r'^\s+$', np.nan, regex=True)在您的有效数据包含空格的情况下使用。


1
regex是一个布尔型标志。也许您是说pd.Series(["1", "#", "9", " .", None]).replace(r"( +\.)|#", "X", regex=True).values这给了['1', 'X', '9', 'X', None]
patricksurry 2015年

2
2年过去了,现在熊猫支持了,我已经改变了对此的公认答案。谢谢!
克里斯·克拉克

35
注意:如果您不希望将中间包含空格的元素替换为NaN,请使用df.replace(r'^\s+$', np.nan, regex=True)
-Temak

7
我尝试使用它,但发现r'^ \ s * $'应该是要使用的表达式。不带^和$的它将匹配具有两个连续空格的任何字符串。也将+更改为*,以在要转换为NaN的事物列表中包含空字符串“”
Master Yogurt

1
我正在我的代码中尝试您的解决方案,但是没有效果。我正在尝试“ energy [“能源供应”] .replace(to_replace =“ ...”,值= np.NaN)“。想要将字符串“ ...”更改为NaN值,但它不执行任何操作并返回相同的数据帧。
Archan Joshi

50

如果要替换空字符串并仅用空格记录,则正确答案是!:

df = df.replace(r'^\s*$', np.nan, regex=True)

接受的答案

df.replace(r'\s+', np.nan, regex=True)

不替换空字符串!,您可以尝试使用稍作更新的示例进行尝试:

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'fo o', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', ''],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

请注意,尽管'fo o'包含空格,但并未用Nan代替。进一步注意,这很简单:

df.replace(r'', np.NaN)

也不起作用-试试看。


33

怎么样:

d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

applymap函数将一个函数应用于数据帧的每个单元。


多么不错的进步!我本该回想起来,但是由于某种原因却挂断了布尔替换。一个问题-与只使用str(x).isspace()相比,进行基字符串检查是否有优势?
克里斯·克拉克

1
@ChrisClark:哪一种都可以,尽管我猜这isinstance会更快一些。
布伦·巴恩(BrenBarn)2012年

13
上面的代码中对“ basestring”的引用在Python 3中不起作用。在这种情况下,请尝试使用“ str”代替。
斯派克·威廉姆斯

4
请注意,此解决方案不会替换空字符串''。要同时考虑空字符串,请使用:d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and (not x or x.isspace()) else x)
tuomastik '17

18

我将这样做:

df = df.apply(lambda x: x.str.strip()).replace('', np.nan)

要么

df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)

您可以剥离所有str,然后将空str替换为np.nan


lambda x:x.str.strip()应该是lambda x:x.strip()吗?小建议:在前面添加.astype(str),这可以为我解决其他数据问题。这对我有用:df = df.apply ['column']。astype(str).apply(lambda x:x.strip())。replace('',np.nan)
Wouter

第二行代码同时处理int / float和字符串类型的列。真好 Tks!
凯特·斯托尔

6

所有解决方案中最简单的:

df = df.replace(r'^\s+$', np.nan, regex=True)

5

如果要从CSV文件导出数据,则可以像这样简单:

df = pd.read_csv(file_csv, na_values=' ')

这将创建数据框并将空白值替换为Na


2
另一种选择..using skipinitialspace=True也删除定界符后的所有空格,这将导致任何长度的空格,空字符串将被读取为nan。但是,如果出于任何原因要保留初始空间,则此选项不是一个好的选择。
拉吉谢卡·雷迪

1
@RajshekarReddy能否请您将此作为答案,这真是太好了!
User2321


1

这些都是接近正确答案的方法,但是我不会说任何解决问题的方法,同时让其他人仍然最容易阅读您的代码。我会说答案是BrenBarn的答案和tuomasttik在该答案下方的评论的结合。BrenBarn的答案利用了isspace内置函数,但不支持按照OP的要求删除空字符串,而我倾向于将其归为用null替换字符串的标准用例。

我用重写了它.apply,因此可以在pd.Series或上调用它pd.DataFrame


Python 3:

替换空字符串或整个空格的字符串:

df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)

要替换整个空格字符串:

df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)

要在Python 2中使用此代码,您需要替换strbasestring

Python 2:

替换空字符串或整个空格的字符串:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)

要替换整个空格字符串:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

1

这对我有用。导入csv文件时,我添加了na_values =''。默认的NaN值中不包含空格。

df = pd.read_csv(filepath,na_values ='')


0

您还可以使用过滤器来执行此操作。

df = PD.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '])
    df[df=='']='nan'
    df=df.astype(float)

该代码的每一行(不包括数据)都是错误的。
朱利叶斯

0
print(df.isnull().sum()) # check numbers of null value in each column

modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"

# modifiedDf = fd.dropna() # Remove rows with empty values

print(modifiedDf.isnull().sum()) # check numbers of null value in each column

0

这不是一个很好的解决方案,但是似乎有效的方法是保存到XLSX,然后将其重新导入。不确定为什么,此页面上的其他解决方案对我不起作用。

data.to_excel(filepath, index=False)
data = pd.read_excel(filepath)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.