为什么 pandas 使用 numpy 中的“NaN”,而不是它自己的 null 值?

问题描述 投票:0回答:3

这是一个宽泛的话题,但我会尝试将其简化为一些具体问题。

在开始回答有关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

我已经习惯了用

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

我最近才意识到,您可以使用 Python

None
来代替类似的情况:

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
does 自 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>

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

我基于上述的问题

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

我完全预料到我对事物的解释以及

pandas
numpy
之间的区别可能有错误,所以请纠正我。

python pandas numpy null missing-data
3个回答
8
投票

pandas

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

(这种基于 numpy 的选择也会对其他事情产生影响。例如,日期和时间操作是基于

np.timedelta64
np.datetime64
dtypes 构建的,而不是标准
datetime
模块。)


您可能不知道的一件事是,

numpy
一直与
pandas

在一起
import pandas as pd
pd.np?
pd.np.nan

虽然您可能认为这种行为可能会更好,因为您不导入numpy,但不鼓励这样做,并且在不久的将来将被弃用,转而直接导入

numpy

FutureWarning:pandas.np 模块已弃用并将被删除 来自未来版本中的 pandas。而是直接导入 numpy


在 pandas 中使用

np.nan
(而不是
None
)来表示空值是否很传统?

如果数据是数字,那么是的,您应该使用

np.NaN
None
要求 dtype 为
Object
,对于 pandas,您希望将数字数据存储在数字 dtype 中。
pandas
通常会在创建或导入时强制转换为正确的空类型,以便它可以使用正确的
dtype

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

为什么 pandas 在其生命周期的大部分时间里(直到去年)都没有自己的 null 值?添加的动机是什么?

pandas
没有自己的空值,因为它与
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



1
投票
首先,您可以通过仅返回一个值的
    filter-function
  • 来统一 nan 值,比如说
    None
    我想原因是为了在对
  • numpy
  • 计算等数据进行数据挖掘时使其独一无二。因此,
    pandas
    nan 的含义有所不同。也许,在您的特殊情况下它没有意义,但在其他情况下它会有意义。
    
        

1
投票

© www.soinside.com 2019 - 2024. All rights reserved.