为什么熊猫使用来自 numpy 的 "NaN",而不是它自己的 null 值?



这是一个有点宽泛的主题,但我将尝试将其简化为一些特定的问题。

在开始回答SO上的问题时,我发现自己在制作玩具数据时有时会遇到这样一个愚蠢的错误:

In[0]:
import pandas as pd
df = pd.DataFrame({"values":[1,2,3,4,5,6,7,8,9]})
df[df < 5] = np.nan
Out[0]:
NameError: name 'np' is not defined

我习惯于用pandas自动导入numpy,所以这通常不会在实际代码中发生。然而,这确实让我想知道为什么pandas没有自己的值/对象来表示null值。

我最近才意识到,对于类似的情况,可以使用PythonNone

import pandas as pd
df = pd.DataFrame({"values":[1,2,3,4,5,6,7,8,9]})
df[df < 5] = None

它按预期工作,不会产生错误。但我觉得我在SO上看到的惯例是使用np.nan,人们在讨论空值时通常会提到np.nan(这也许是我没有意识到None可以使用的原因,但这可能是我自己的特点)。

简单地说,我现在已经看到pandas自1.0.0以来确实有pandas.NA值,但我从未见过有人在帖子中使用它

In[0]:
import pandas as pd
import numpy as np
df = pd.DataFrame({'values':np.random.rand(20,)})
df['above'] = df['values']
df['below'] = df['values']
df['above'][df['values']>0.7] = np.nan
df['below'][df['values']<0.3] = pd.NA
df['names'] = ['a','b','c','a','b','c','a','b','c','a']*2
df.loc[df['names']=='a','names'] = pd.NA
df.loc[df['names']=='b','names'] = np.nan
df.loc[df['names']=='c','names'] = None
df
Out[0]:
values     above     below names
0   0.323531  0.323531  0.323531  <NA>
1   0.690383  0.690383  0.690383   NaN
2   0.692371  0.692371  0.692371  None
3   0.259712  0.259712       NaN  <NA>
4   0.473505  0.473505  0.473505   NaN
5   0.907751       NaN  0.907751  None
6   0.642596  0.642596  0.642596  <NA>
7   0.229420  0.229420       NaN   NaN
8   0.576324  0.576324  0.576324  None
9   0.823715       NaN  0.823715  <NA>
10  0.210176  0.210176       NaN  <NA>
11  0.629563  0.629563  0.629563   NaN
12  0.481969  0.481969  0.481969  None
13  0.400318  0.400318  0.400318  <NA>
14  0.582735  0.582735  0.582735   NaN
15  0.743162       NaN  0.743162  None
16  0.134903  0.134903       NaN  <NA>
17  0.386366  0.386366  0.386366   NaN
18  0.313160  0.313160  0.313160  None
19  0.695956  0.695956  0.695956  <NA>

因此,对于数值来说,这些不同的null值之间的区别似乎无关紧要,但对于字符串(也许对于其他数据类型?),它们的表示方式不同。

我的问题基于以上

  • 使用np.nan(而不是None)来表示pandas中的空值是传统的吗
  • 为什么pandas在其生命周期的大部分时间(直到去年)都没有自己的null值?添加的动机是什么
  • 在一个Series或列中可能有多种类型的缺失值的情况下,它们之间有什么区别吗?为什么它们的表示方式不相同(如数字数据)

我完全预料到我可能对事物的解释以及pandasnumpy之间的区别有缺陷,所以请纠正我。

pandas的一个主要依赖项是numpy,换句话说,panda是在numpy之上构建的。因为panda继承并使用了许多numpy方法,所以保持一致是有意义的,也就是说,丢失的数字数据用np.NaN表示。

(这种基于numpy构建的选择也会对其他事情产生影响。例如,日期和时间操作是基于np.timedelta64np.datetime64数据类型构建的,而不是标准的datetime模块。)


有一件事你可能不知道,numpy一直存在于pandas

import pandas as pd
pd.np?
pd.np.nan

尽管您可能认为这种行为可能会更好,因为您不导入numpy,但这是不鼓励的,并且在不久的将来将不赞成直接导入numpy

Future警告:pandas.np模块已弃用,将被删除来自熊猫的未来版本。直接导入numpy而不是


在Panda中使用np.nan(而不是None)来表示空值是否是惯例

如果数据是数字,那么是的,您应该使用np.NaNNone要求数据类型为Object,对于panda,您希望数字数据存储在数字数据类型中。pandas通常会在创建或导入时强制为正确的null类型,以便使用正确的dtype

pd.Series([1, None])
#0    1.0
#1    NaN        <- None became NaN so it can have dtype: float64
#dtype: float64

为什么大熊猫一生中的大部分时间(直到去年)都没有自己的零值?添加的动机是什么

pandas没有自己的null值,因为它与np.NaN相处得很好,后者在大多数情况下都有效。然而,对于pandas,丢失数据是非常常见的,文档的整个部分都专门介绍了这一点。NaN是一个浮点值,不适合整数容器,这意味着任何缺少数据的数字系列都会上变频到float。这可能会因为浮点数学而变得有问题,并且一些整数不能用浮点数完美地表示。因此,任何联接或merges都可能失败。

# Gets upcast to float
pd.Series([1,2,np.NaN])
#0    1.0
#1    2.0
#2    NaN
#dtype: float64
# Can safely do merges/joins/math because things are still Int
pd.Series([1,2,np.NaN]).astype('Int64')
#0       1
#1       2
#2    <NA>
#dtype: Int64
  • 首先,您可以通过只返回一个值的filter-function来统一nan值,比如None
  • 我想原因是为了在对numpy计算等数据进行数据挖掘时使其独一无二。因此,pandasnan的含义不同。也许,这在你的特殊情况下没有意义,但在其他情况下会有意义

这是个好问题!我的直觉是,这与NumPy函数是用C实现的这一事实有关,这使得它如此快速。Python的None可能不会给你同样的效率(或者可能被翻译成np.nan),而Pandas的pd.NA可能无论如何都会被翻译成NumPy的np.nan,因为Pandas需要NumPy。不过,我还没有找到资源来支持我的说法。

相关内容

  • 没有找到相关文章

最新更新