pandas中的pd.NA和np.nan有什么区别?

57

pd.NAnp.nan用于pandas。在pandas中应该使用哪一个并为什么使用它?各自在pandas中的主要优缺点是什么?

以下是使用它们两者的一些示例代码:

import pandas as pd
import numpy as np

df = pd.DataFrame({ 'object': ['a', 'b', 'c',pd.NA],
                   'numeric': [1, 2, np.nan , 4],
                    'categorical': pd.Categorical(['d', np.nan,'f', 'g'])
                 })

输出:

|    | object   |   numeric | categorical   |
|---:|:---------|----------:|:--------------|
|  0 | a        |         1 | d             |
|  1 | b        |         2 | nan           |
|  2 | c        |       nan | f             |
|  3 | <NA>     |         4 | g             |

1
我非常确定 pd.NA 在后端使用 np.nan。Pandas 倾向于在后端大量使用 numpy。 - Kenan
这是哪个版本的pandas? - roganjosh
7
与np.nan相比,pd.NA在某些操作中表现不同。除了算术运算外,pd.NA在比较操作中也作为“缺失”或“未知”值传播。 - anky
2
@kenan 不是的,在这种情况下,它是distinct - roganjosh
1
@roganjosh 啊,我明白了,这是一个Pandas 1.0函数,谢谢你为我澄清。 - Kenan
显示剩余2条评论
6个回答

34

截至现在(pandas-1.0.0发布),我很建议小心使用。

首先,它仍然是一个实验性的特性:

实验性的:pd.NA的行为可能会在没有警告的情况下更改。

第二,其行为与np.nan不同

np.nan相比,在某些操作中,pd.NA的行为不同。除了算术运算外,pd.NA还在比较运算中传播为“缺失”或“未知”。

两个引用来自发行说明

为了展示一些额外的例子,我对插值行为感到惊讶:

创建一个简单的数据框:

df = pd.DataFrame({"a": [0, pd.NA, 2], "b": [0, np.nan, 2]})
df
#       a    b
# 0     0  0.0
# 1  <NA>  NaN
# 2     2  2.0

并尝试进行插值:

df.interpolate()
#       a    b
# 0     0  0.0
# 1  <NA>  1.0
# 2     2  2.0

有一些原因导致这种情况(我仍在探索),不管怎样,我只是想强调这些差异 - 它是一个实验性功能,在某些情况下表现不同

我认为这将是非常有用的功能,但我会非常小心地使用像“完全可以使用它代替np.nan”这样的语句。对于大多数情况可能是正确的,但当您没有意识到它可能会引起一些麻烦。


1
这个还被视为实验性的吗? - Ben Jones
5
是的,最新版本(1.5)仍然被视为实验性功能:https://pandas.pydata.org/pandas-docs/version/1.5/user_guide/missing_data.html#experimental-na-scalar-to-denote-missing-values - Nerxis
5
pd.NA 经常会让人感到惊讶。最近我用它来表示缺失值,代替了 np.nan,但是这种类型会导致其他库出现任性的错误。特别是,库(Samplics)使用了 np.isfinite 以及从 np.linalg 中调用的函数,两者都会抛出关于数据形状和类型的错误。这些错误非常令人困惑。我使用的是 pandas 的版本 1.5.3 和 NumPy 的版本 1.24.2 - 所以如果有人想知道 pd.NA 在 2023 年的状态,现在请务必注意其实验性质的警告,即使它看起来运行良好。 - Joshua Megnauth

8
根据文档所述, pd.NA的目标是提供一个可在各种数据类型中一致使用的“缺失”指示符。
因此,如果您有一个包含多个数据类型的列,请使用pd.NA,否则np.nan应该也可以。
然而,由于pd.NA似乎具有与np.nan相同的功能,因此最好将pd.NA用于所有NaN目的。
请注意以下评论: pd.NA的功能不完全相同,因此切换时要小心。 pd.NA在等式操作中传播,而np.nan则不会。 pd.NA == 1产生,但np.nan == 1产生False。

1
根据@tdpr提供的https://pandas.pydata.org/pandas-docs/stable/whatsnew/v1.0.0.html,似乎`NA`现在是实验性功能,因此对于一些重要的事情,我认为现在应该避免使用它。 - vasili111
8
当你切换时要小心,pd.NA没有完全相同的功能。pd.NA在等式运算中传播,而np.nan则不传播。pd.NA == 1的结果为<NA>,但是np.nan == 1的结果为False - Steven

4

pd.NA是pandas自己的空值。很多数据类型都是从numpy借鉴而来,包括np.nan。

从pandas 1.0开始,一个实验性的pd.NA值(单例)可用于表示标量缺失值。此时,它在可空整数、布尔和专用字符串数据类型中用作缺失值指示器。

pd.NA的目标是提供一种“缺失”指示符,可以在各种数据类型中一致使用(而不是根据数据类型使用np.nan、None或pd.NaT)。

让我们构建一个包含所有不同数据类型的df。

d = {'int': pd.Series([1, None], dtype=np.dtype("O")),
    'float': pd.Series([3.0, np.NaN], dtype=np.dtype("float")),
    'str': pd.Series(['test', None], dtype=np.dtype("str")),
    "bool": pd.Series([True, np.nan], dtype=np.dtype("O")),
    "date": pd.Series(['1/1/2000', np.NaN], dtype=np.dtype("O"))}
df1 = pd.DataFrame(data=d)

df1['date'] = pd.to_datetime(df1['date'], errors='coerce')
df1.info()
df1

输出

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   int     1 non-null      object        
 1   float   1 non-null      float64       
 2   str     1 non-null      object        
 3   bool    1 non-null      object        
 4   date    1 non-null      datetime64[ns]
dtypes: datetime64[ns](1), float64(1), object(3)
memory usage: 208.0+ bytes

    int   float str     bool    date
0   1     3.0   test    True    2000-01-01
1   None  NaN   None    NaN     NaT


如果您有一个使用传统类型表示缺失数据的DataFrame或Series,那么Series中的convert_dtypes()和DataFrame中的convert_dtypes()都提供了方便的方法,可以将数据转换为使用新的整数、字符串和布尔型dtype,并从v1.2开始使用convert_integer=False来转换浮点数。
df1[['int', 'str', 'bool', 'date']] = df1[['int', 'str', 'bool', 'date']].convert_dtypes()
df1['float'] = df1['float'].convert_dtypes(convert_integer=False)
df1.info()
df1

输出

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   int     1 non-null      Int64         
 1   float   1 non-null      Float64       
 2   str     1 non-null      string        
 3   bool    1 non-null      boolean       
 4   date    1 non-null      datetime64[ns]
dtypes: Float64(1), Int64(1), boolean(1), datetime64[ns](1), string(1)
memory usage: 200.0 bytes

    int     float   str     bool    date
0   1       3.0     test    True    2000-01-01
1   <NA>    <NA>    <NA>    <NA>    NaT

注意大写字母'F'以区分于np.float32np.float64,还要注意string,它是新的pandas StringDtype(来自Pandas 1.0),而不是strobject。同时还有pd.Int64(来自pandas 0.24),可为空的整数大写'I',而不是np.int64
有关数据类型的更多信息,请阅读此处此处。此页面提供了一些关于子类型的好信息。
我正在使用pandas v1.2.4,所以希望在未来我们将拥有适用于所有数据类型的通用空值,这将温暖我们的心灵。
警告:这是新的和实验性的,请谨慎使用。

谢谢,但说实话,pd.NA 仍然有点让我困惑。你尝试过直接使用这个 NA 值吗?例如,对于你的第一列(int),像这样:'int': pd.Series([1, pd.NA], dtype=np.dtype("O"))(使用 pd.NA 而不是 None)?因为这样即使使用 convert_dtypes 方法后,列类型仍然保持不变(object 而不是 Int64)。 - Nerxis
@Nerxis 目前,pd.NA 仅用于可空整数、布尔和专用字符串数据类型。关于在此处使用对象的讨论,请参见 https://github.com/pandas-dev/pandas/issues/32931 - Cam
是的,我理解这一点,但我的观点是convert_dtypes不会将此对象类型的列转换为Int64,这应该得到支持。但是感谢提供链接,他们讨论了包括convert_dtypes函数在内的内容,其中docstring有点令人困惑(与实际行为不同)。 - Nerxis

4

在数据框中,pd.NA和np.nan都表示缺失值。
我注意到的主要区别是,np.nan是浮点数值,而pd.NA存储整数值。 如果您在数据集中有一个column1,其中所有整数都有一些缺失值,并且这些缺失值被np.nan替换,则该列的数据类型变为浮点型,因为np.nan是浮点数。 但是,如果您在数据集中有一个column2,其中所有整数都有一些缺失值,并且这些缺失值被pd.NA替换,则该列的数据类型仍然是整数,因为pd.NA是整数。 如果您想保留任何列作为int,而不将其更改为float,则这可能很有用。


2

pd.NA 仍处于实验阶段 (https://pandas.pydata.org/docs/user_guide/missing_data.html),可能会产生不良影响。

例如:

import pandas as pd
df = pd.DataFrame({'id':[1,2,3]})
df.id.replace(2, pd.NA, inplace=True)
df.id.replace(3, pd.NA, inplace=True)

Pandas 1.2.4:

id
0 1
1 <NA>
2 3

Pandas 1.4.2:

AttributeError: 'bool' object has no attribute 'to_numpy'

看起来 pd.NA 会改变数据框架,导致第二个替换不再起作用。

使用 np.nan 的相同代码可以无问题运行。

import pandas as pd
import numpy as np
df = pd.DataFrame({'id':[1,2,3]})
df.id.replace(2, np.nan, inplace=True)
df.id.replace(3, np.nan, inplace=True)

2

pd.NA是在最近发布的pandas-1.0.0中引入的。

我建议使用它而不是np.nan,因为它包含在pandas库中,所以在处理数据框时效果更佳。


1
从你的链接来看,NA现在是实验性功能,因此对于一些重要的事情,我认为现在应该避免使用它。 - vasili111
1
pd.NA的功能不完全相同,因此在切换时要小心。 pd.NA在等式操作中传播,而np.nan则不会。 pd.NA == 1产生<NA>,但np.nan == 1产生False - Steven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接