【问题标题】:Replace invalid values with None in Pandas DataFrame在 Pandas DataFrame 中用 None 替换无效值
【发布时间】:2013-06-10 10:31:51
【问题描述】:

有没有什么方法可以在 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 脚本,供您参考。

【问题讨论】:

  • write_frame 不会将NaNs 解析为nones 吗?
  • 是的。您遇到InternalError: (1054, u"Unknown column 'nan' in 'field list'") 错误。除了在执行write_frame 方法之前将NaN 转换为None 之外,我不知道任何解决方案。
  • 你用的是什么版本的熊猫?
  • Scipy 超级包发布开发?好的,我绝对认为你应该 raise this as an issue on github,不应该太难修复。
  • 如果您从 CSV/Excel 读取此数据,您可以使用 na_values 参数将这些值读取为 NaN。 More information in this answer.

标签: python pandas dataframe replace nan


【解决方案1】:

实际上在更高版本的 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

【讨论】:

  • 或者只是一个列表,例如df.replace(['-'], [None]),或df.replace({'-': None}),我想。使用None 作为哨兵也排除了将其用作值..
  • @user2360798 replace 实际上是一个功能非常丰富(读取复杂)的功能,不过(dev)docstring 确实不错。
  • 我不知道这是否明显,但必须将df 分配回自身,例如:df = df.replace({'?': np.nan})
  • @AndyHayden df.replace('-', df.replace(['-'], [None]) 看起来很时髦,是错字吗?
  • @lin_bug 虽然它似乎在最近的熊猫版本中不再有效。 df.where(df!='-', None) 有效
【解决方案2】:

where 可能是您正在寻找的。所以

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

来自panda docs

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

【讨论】:

  • 这实际上是不准确的。 data=data.where(data=='-', None) 将用 None 替换任何不等于 '-' 的内容。 Pandas 版本 where 保留第一个 arg 的值(在本例中为 data=='-'),并用第二个 arg 替换其他任何内容(在本例中为 None)。这有点令人困惑,因为 np.where 更明确,因为它在第一个 arg 中询问条件,然后在第二个 arg 中询问 if true,然后在第三个 arg 中询问 if false。
【解决方案3】:

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

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

你也可以有更多的替代品:

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

即使对于较大的替换,用什么替换什么总是显而易见的——在我看来,这对于长列表来说更难。

【讨论】:

  • 值得注意的是,这种技术之所以有效,部分原因是在to_replace 中使用dict 类型会导致method 参数不被评估,因此method='pad' 默认值没有不良影响。
【解决方案4】:
df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9])
df = df.where(df!='-', None)

【讨论】:

    【解决方案5】:

    设置空值可以通过np.nan:

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

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

    【讨论】:

      【解决方案6】:

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

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

      但是要回答你的问题...

      pandas >= 0.18:使用na_values=['-'] 参数和read_csv

      如果您从 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找到。

      【讨论】:

        【解决方案7】:

        使用替换并分配一个新的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
        

        【讨论】:

          【解决方案8】:
          df.replace('-', np.nan).astype("object")
          

          这将确保您以后可以在数据帧上使用isnull()

          【讨论】:

            【解决方案9】:

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

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

            这更好有两个原因:

            1. 它使用pd.NA 而不是Nonenp.nan
            2. 它可以选择就地工作,这可能会根据内部实现更有效地使用内存。

            【讨论】:

              猜你喜欢
              • 2022-12-17
              • 2017-08-06
              • 1970-01-01
              • 2017-07-04
              • 2019-08-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多