在Pandas DataFrame中将无效值替换为None

时间:2013-06-13 21:17:31

标签: python pandas dataframe replace nan

是否有任何方法可以用Python中的Pandas中的None替换值?

您可以使用df.replace('pre', 'post')并可以将值替换为另一个值,但如果要替换为None值,则无法执行此操作,如果尝试,则会得到奇怪的结果。

所以这是一个例子:

df = DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df.replace('-', 0)

返回成功的结果。

但是,

df.replace('-', None)

返回以下结果:

0
0   - // this isn't replaced
1   3
2   2
3   5
4   1
5  -5
6  -1
7  -1 // this is changed to `-1`...
8   9

为什么会返回这么奇怪的结果?

由于我想将此数据框倒入MySQL数据库,因此我无法将NaN值放入数据框中的任何元素中,而是想放置None。当然,您可以先将'-'更改为NaN,然后将NaN转换为None,但我想知道为什么数据框会以如此可怕的方式运行。

  

在Python 2.7和OS X 10.8上测试pandas 0.12.0 dev。 Python是一个   OS X上的预安装版本,我使用SciPy安装了pandas   Superpack脚本,供您参考。

9 个答案:

答案 0 :(得分:83)

实际上在更高版本的pandas中,这会产生TypeError:

df.replace('-', None)
TypeError: If "to_replace" and "value" are both None then regex must be a mapping

您可以通过传递列表或字典来实现:

In [11]: df.replace('-', df.replace(['-'], [None]) # or .replace('-', {0: None})
Out[11]:
      0
0  None
1     3
2     2
3     5
4     1
5    -5
6    -1
7  None
8     9

但我建议使用NaN而不是None:

In [12]: df.replace('-', np.nan)
Out[12]:
     0
0  NaN
1    3
2    2
3    5
4    1
5   -5
6   -1
7  NaN
8    9

答案 1 :(得分:14)

where可能是你正在寻找的东西。所以

data=data.where(data=='-', None) 

来自panda docs

  

where [返回]一个与self相同形状的对象,其对应的条目来自self,其中cond为True,否则来自其他)。

答案 2 :(得分:11)

我更喜欢使用replacedict的解决方案,因为它简单而优雅:

df.replace({'-': None})

您还可以拥有更多替代品:

df.replace({'-': None, 'None': None})

即使对于更大的替代品,在我看来,总是显而易见并清楚什么被什么取代 - 这对于长列表来说更难。

答案 3 :(得分:2)

df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df = df.where(df!='-', None)

答案 4 :(得分:2)

  

在继续此文章之前,务必要了解   the difference between NaN and None。   一种是浮点类型,另一种是对象类型。熊猫更好   适合使用标量类型,因为这些类型上的许多方法都可以   被向量化。熊猫确实尝试一致地处理None和NaN,   但是NumPy不能。

     

我的建议(and Andy's)是坚持使用NaN。

(v0.24 +)更好的CSV / Excel数据解决方案:na_values=['-']

如果您是从CSV / Excel加载此数据的,那么我对您来说是个好消息。您可以在数据加载过程中从根本上解决此问题,而不必在后续步骤中编写代码修复程序。

大多数pd.read_*函数(例如read_csvread_excel)都接受 na_values 属性。

file.csv

A,B
-,1
3,-
2,-
5,3
1,-2
-5,4
-1,-1
-,0
9,0

现在,要将-字符转换为NaN,请执行

import pandas as pd
df = pd.read_csv('file.csv', na_values=['-'])
df

     A    B
0  NaN  1.0
1  3.0  NaN
2  2.0  NaN
3  5.0  3.0
4  1.0 -2.0
5 -5.0  4.0
6 -1.0 -1.0
7  NaN  0.0
8  9.0  0.0

与其他功能/文件格式类似。

P.S .:在v0.24 +上,即使您的列具有NaN,您也可以保留整数类型(是的,也要谈论吃蛋糕和吃蛋糕)。您可以指定dtype='Int32'

df = pd.read_csv('file.csv', na_values=['-'], dtype='Int32')
df

     A    B
0  NaN    1
1    3  NaN
2    2  NaN
3    5    3
4    1   -2
5   -5    4
6   -1   -1
7  NaN    0
8    9    0

df.dtypes

A    Int32
B    Int32
dtype: object

dtype不是常规的int类型...而是Nullable Integer Type.还有其他选择。


处理数值数据:pd.to_numericerrors='coerce

如果要处理数字数据,更快的解决方案是将pd.to_numericerrors='coerce'参数一起使用,这会将无效值(不能转换为数字的值)强制为NaN。

pd.to_numeric(df['A'], errors='coerce')

0    NaN
1    3.0
2    2.0
3    5.0
4    1.0
5   -5.0
6   -1.0
7    NaN
8    9.0
Name: A, dtype: float64

要保留(可为空)整数dtype,请使用

pd.to_numeric(df['A'], errors='coerce').astype('Int32')

0    NaN
1      3
2      2
3      5
4      1
5     -5
6     -1
7    NaN
8      9
Name: A, dtype: Int32 

要强制多列,请使用apply

df[['A', 'B']].apply(pd.to_numeric, errors='coerce').astype('Int32')

     A    B
0  NaN    1
1    3  NaN
2    2  NaN
3    5    3
4    1   -2
5   -5    4
6   -1   -1
7  NaN    0
8    9    0

...然后将结果分配回去。

更多信息可以在this answer中找到。

答案 5 :(得分:0)

可以使用np.nan设置空值:

import numpy as np
df.replace('-', np.nan)

优点是df.last_valid_index()将其识别为无效。

答案 6 :(得分:0)

使用替换并分配新的df:

import pandas as pd
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
dfnew = df.replace('-', 0)
print(dfnew)


(venv) D:\assets>py teste2.py
   0
0  0
1  3
2  2
3  5
4  1
5 -5

答案 7 :(得分:0)

df.replace('-', np.nan).astype("object")

这将确保您稍后可以在数据框中使用isnull()

答案 8 :(得分:0)

对于Pandas版本≥1.0.0,我将使用DataFrame.replaceSeries.replace

df.replace(old_val, pd.NA, inplace=True)

这有两个更好的理由:

  1. 它使用pd.NA而不是Nonenp.nan
  2. 它替换了就地值 ,它可以提高内存效率。