Python 中 NaN 和 None 的详细比较

python原生的None和pandas, numpy中的numpy.NaN尽管在功能上都是用来标示空缺数据。但它们的行为在很多场景下确有一些相当大的差异。由于不熟悉这些差异,曾经给我的工作带来过不少麻烦。 特此整理了一份详细的实验,比较None和NaN在不同场景下的差异。

实验的结果有些在意料之内,有些则让我大跌眼镜。希望读者看过此文后会None和NaN这对“小妖精”有更深的理解。

为了理解本文的内容,希望本文的读者需要对pandas的Series使用有一定的经验。

首先,导入所需的库

In[2]:

数据类型?

None是一个python特殊的数据类型, 但是NaN却是用一个特殊的float

In[3]:

Out[3]:

In[4]:

Out[4]:

能作为dict的key?

In[5]:

Out[5]:

In[6]:

Out[6]:

In[7]:

Out[7]:

都可以,而且会被认为是不同的key

Series函数中的表现

Series.map

In[8]:

Out[8]:

In[9]:

Out[9]:

可以看到None和NaN都会替换成了1

In[10]:

Out[10]:

同样None和NaN都会替换成了1

In[11]:

Out[11]:

将None替换成1的要求被忽略了

In[12]:

Out[12]:

将NaN替换成1的要求被忽略了

总结: 用Series.map对None进行替换时,会“顺便”把NaN也一起替换掉;NaN也会顺便把None替换掉。

如果None和NaN分别定义了不同的映射数值,那么只有一个会生效。

Series.replace中的表现

In[13]:

Out[13]:

In[14]:

Out[14]:

In[15]:

Out[15]:

和Series.map的情况类似,指定了None的替换值后,NaN会被替换掉;反之亦然。

对函数的支持

numpy有不少函数可以自动处理NaN。

In[16]:

Out[16]:

但是None不能享受这些函数的便利,如果数据包含的None的话会报错

In[17]:

unsupported operand type(s) for +: ‘int’ and ‘NoneType’

pandas中也有不少函数支持NaN却不支持None。(毕竟pandas的底层是numpy)

In[18]:

Out[18]:

In[19]:

unorderable types: int() > NoneType()

对容器数据类型的影响

混入numpy.array的影响

如果数据中含有None,会导致整个array的类型变成object。

In[20]:

Out[20]:

而np.NaN尽管会将原本用int类型就能保存的数据转型成float,但不会带来上面这个问题。

In[21]:

Out[21]:

混入Series的影响

下面的结果估计大家能猜到

In[22]:

Out[22]:

下面的这个就很意外的吧

In[23]:

Out[23]:

pandas将None自动替换成了NaN!

In[24]:

Out[24]:

却是Object类型的None被替换成了float类型的NaN。 这么设计可能是因为None无法参与numpy的大多数计算, 而pandas的底层又依赖于numpy,因此做了这样的自动转化。

不过如果本来Series就只能用object类型容纳的话, Series不会做这样的转化工作。

In[25]:

Out[25]:

如果Series里面都是None的话也不会做这样的转化

In[26]:

Out[26]:

其它的数据类型是bool时,也不会做这样的转化。

In[27]:

Out[27]:

等值性判断

单值的等值性比较

下面的实验中None和NaN的表现会作为后面的等值性判断的基准(后文称为基准)

In[28]:

Out[28]:

In[29]:

Out[29]:

In[30]:

Out[30]:

在tuple中的情况

这个不奇怪

In[31]:

Out[31]:

这个也不意外

In[32]:

Out[32]:

但是下面这个实验NaN的表现和基准不一致

In[33]:

Out[33]:

在numpy.array中的情况

In[34]:

Out[34]:

In[35]:

Out[35]:

In[36]:

Out[36]:

和基准的表现一致。

但是大部分情况我们希望上面例子中, 我们希望左右两边的array被判定成一致。这时可以用numpy.testing.assert_equal函数来处理。 注意这个函数的表现同assert, 不会返回True, False, 而是无反应或者raise Exception

In[37]:

它也可以处理两边都是None的情况

In[38]:

但是一边是None,一边是NaN时会被认为两边不一致, 导致AssertionError

In[39]:

在Series中的情况

下面两个实验中的表现和基准一致

In[40]:

Out[40]:

In[41]:

Out[41]:

你可能感兴趣的:(Python 中 NaN 和 None 的详细比较)