处理缺失数据#

被视为“缺失”的值#

pandas 根据数据类型使用不同的哨兵值来表示缺失(也称为 NA)。

numpy.nan对于 NumPy 数据类型。使用 NumPy 数据类型的缺点是原始数据类型将被强制为np.float64or object

In [1]: pd.Series([1, 2], dtype=np.int64).reindex([0, 1, 2])
Out[1]: 
0    1.0
1    2.0
2    NaN
dtype: float64

In [2]: pd.Series([True, False], dtype=np.bool_).reindex([0, 1, 2])
Out[2]: 
0     True
1    False
2      NaN
dtype: object

NaT对于 NumPy np.datetime64np.timedelta64PeriodDtype.对于打字应用程序,请使用api.types.NaTType.

In [3]: pd.Series([1, 2], dtype=np.dtype("timedelta64[ns]")).reindex([0, 1, 2])
Out[3]: 
0   0 days 00:00:00.000000001
1   0 days 00:00:00.000000002
2                         NaT
dtype: timedelta64[ns]

In [4]: pd.Series([1, 2], dtype=np.dtype("datetime64[ns]")).reindex([0, 1, 2])
Out[4]: 
0   1970-01-01 00:00:00.000000001
1   1970-01-01 00:00:00.000000002
2                             NaT
dtype: datetime64[ns]

In [5]: pd.Series(["2020", "2020"], dtype=pd.PeriodDtype("D")).reindex([0, 1, 2])
Out[5]: 
0    2020-01-01
1    2020-01-01
2           NaT
dtype: period[D]

NA对于StringDtype, Int64Dtype(和其他位宽) 和.这些类型将保持数据的原始数据类型。对于打字应用程序,请使用.Float64Dtype`(and other bit widths), :class:`BooleanDtypeArrowDtypeapi.types.NAType

In [6]: pd.Series([1, 2], dtype="Int64").reindex([0, 1, 2])
Out[6]: 
0       1
1       2
2    <NA>
dtype: Int64

In [7]: pd.Series([True, False], dtype="boolean[pyarrow]").reindex([0, 1, 2])
Out[7]: 
0     True
1    False
2     <NA>
dtype: bool[pyarrow]

要检测这些缺失值,请使用isna()notna()方法。

In [8]: ser = pd.Series([pd.Timestamp("2020-01-01"), pd.NaT])

In [9]: ser
Out[9]: 
0   2020-01-01
1          NaT
dtype: datetime64[ns]

In [10]: pd.isna(ser)
Out[10]: 
0    False
1     True
dtype: bool

笔记

isna()或者notna()也会考虑None缺失值。

In [11]: ser = pd.Series([1, None], dtype=object)

In [12]: ser
Out[12]: 
0       1
1    None
dtype: object

In [13]: pd.isna(ser)
Out[13]: 
0    False
1     True
dtype: bool

警告

np.nanNaT、 和之间的相等比较NA 并不像None

In [14]: None == None  # noqa: E711
Out[14]: True

In [15]: np.nan == np.nan
Out[15]: False

In [16]: pd.NaT == pd.NaT
Out[16]: False

In [17]: pd.NA == pd.NA
Out[17]: <NA>

DataFrame因此, a或与这些缺失值之一之间的相等比较Series 不会提供与 isna()或相同的信息notna()

In [18]: ser = pd.Series([True, None], dtype="boolean[pyarrow]")

In [19]: ser == pd.NA
Out[19]: 
0    <NA>
1    <NA>
dtype: bool[pyarrow]

In [20]: pd.isna(ser)
Out[20]: 
0    False
1     True
dtype: bool

NA语义#

警告

实验性: 的行为NA`仍然可以在没有警告的情况下发生变化。

从pandas 1.0开始,NA可以使用实验值(单例)来表示标量缺失值。的目标NA是提供一个可以跨数据类型一致使用的“缺失”指示符(而不是np.nanNonepd.NaT取决于数据类型)。

例如,当 a 中存在Series可为空整数数据类型的缺失值时,它将使用NA

In [21]: s = pd.Series([1, 2, None], dtype="Int64")

In [22]: s
Out[22]: 
0       1
1       2
2    <NA>
dtype: Int64

In [23]: s[2]
Out[23]: <NA>

In [24]: s[2] is pd.NA
Out[24]: True

目前,pandas 尚未使用NA默认使用 aDataFrame或 的这些数据类型Series,因此您需要显式指定 dtype。转换部分解释了转换为这些数据类型的简单方法 。

算术和比较运算中的传播#

一般来说,缺失值会在涉及 的操作中传播NA。当其中一个操作数未知时,运算的结果也是未知的。

例如,NA在算术运算中传播,类似于 np.nan

In [25]: pd.NA + 1
Out[25]: <NA>

In [26]: "a" * pd.NA
Out[26]: <NA>

在一些特殊情况下,结果是已知的,即使操作数之一是NA

In [27]: pd.NA ** 0
Out[27]: 1

In [28]: 1 ** pd.NA
Out[28]: 1

在相等和比较运算中,NA也会传播。这偏离了np.nan, 与 的比较np.nan总是返回的行为False

In [29]: pd.NA == 1
Out[29]: <NA>

In [30]: pd.NA == pd.NA
Out[30]: <NA>

In [31]: pd.NA < 2.5
Out[31]: <NA>

要检查值是否等于NA,请使用isna()

In [32]: pd.isna(pd.NA)
Out[32]: True

笔记

此基本传播规则的一个例外是缩减(例如平均值或最小值),其中 pandas 默认跳过缺失值。更多信息请参见 计算部分。

逻辑运算#

对于逻辑运算,遵循三值逻辑(或 Kleene 逻辑,类似于 R、SQL 和 Julia)NA的规则 。此逻辑意味着仅在逻辑需要时才传播缺失值。

例如,对于逻辑“或”运算 ( |),如果其中一个操作数是True,我们已经知道结果将为True,而不管其他值如何(因此无论缺失值都是TrueFalse)。在这种情况下,NA不会传播:

In [33]: True | False
Out[33]: True

In [34]: True | pd.NA
Out[34]: True

In [35]: pd.NA | True
Out[35]: True

另一方面,如果其中一个操作数是False,则结果取决于另一个操作数的值。因此,在这种情况下NA 传播:

In [36]: False | True
Out[36]: True

In [37]: False | False
Out[37]: False

In [38]: False | pd.NA
Out[38]: <NA>

逻辑“与”运算 ( ) 的行为&可以使用类似的逻辑导出(如果操作数之一已经是 ,则 nowNA不会传播False):

In [39]: False & True
Out[39]: False

In [40]: False & False
Out[40]: False

In [41]: False & pd.NA
Out[41]: False
In [42]: True & True
Out[42]: True

In [43]: True & False
Out[43]: False

In [44]: True & pd.NA
Out[44]: <NA>

NA在布尔上下文中#

由于 NA 的实际值未知,因此将 NA 转换为布尔值是不明确的。

In [45]: bool(pd.NA)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[45], line 1
----> 1 bool(pd.NA)

File missing.pyx:392, in pandas._libs.missing.NAType.__bool__()

TypeError: boolean value of NA is ambiguous

这也意味着NA不能在计算为布尔值的上下文中使用,例如where can might be 。在这种情况下,可用于检查或避免,例如通过预先填充缺失值。if condition: ...conditionNAisna()NAconditionNA

在语句中使用SeriesorDataFrame对象时会出现类似的情况,请参阅在 pandas 中使用 if/truth 语句if

NumPy ufunc #

pandas.NA实现 NumPy 的__array_ufunc__协议。大多数 ufunc 与 一起工作NA,并且通常返回NA

In [46]: np.log(pd.NA)
Out[46]: <NA>

In [47]: np.add(pd.NA, 1)
Out[47]: <NA>

警告

目前,ufuncs 涉及 ndarray 并将NA返回一个填充 NA 值的对象数据类型。

In [48]: a = np.array([1, 2, 3])

In [49]: np.greater(a, pd.NA)
Out[49]: array([<NA>, <NA>, <NA>], dtype=object)

这里的返回类型将来可能会更改以返回不同的数组类型。

有关 ufunc 的更多信息,请参阅DataFrame 与 NumPy 函数的互操作性。

转换

如果您有DataFrameor Seriesusing np.nanSeries.convert_dtypes()并且DataFrame.convert_dtypes() 可以将数据转换为使用使用or 等DataFrame​​数据类型。在从推断数据类型的 IO 方法读取数据集后,这尤其有用。NAInt64DtypeArrowDtype

在此示例中,虽然所有列的数据类型均已更改,但我们显示前 10 列的结果。

In [50]: import io

In [51]: data = io.StringIO("a,b\n,True\n2,")

In [52]: df = pd.read_csv(data)

In [53]: df.dtypes
Out[53]: 
a    float64
b     object
dtype: object

In [54]: df_conv = df.convert_dtypes()

In [55]: df_conv
Out[55]: 
      a     b
0  <NA>  True
1     2  <NA>

In [56]: df_conv.dtypes
Out[56]: 
a      Int64
b    boolean
dtype: object

插入缺失数据#

您可以通过简单地分配给 aSeries或来插入缺失值DataFrame。将根据数据类型选择使用的缺失值哨兵。

In [57]: ser = pd.Series([1., 2., 3.])

In [58]: ser.loc[0] = None

In [59]: ser
Out[59]: 
0    NaN
1    2.0
2    3.0
dtype: float64

In [60]: ser = pd.Series([pd.Timestamp("2021"), pd.Timestamp("2021")])

In [61]: ser.iloc[0] = np.nan

In [62]: ser
Out[62]: 
0          NaT
1   2021-01-01
dtype: datetime64[ns]

In [63]: ser = pd.Series([True, False], dtype="boolean[pyarrow]")

In [64]: ser.iloc[0] = None

In [65]: ser
Out[65]: 
0     <NA>
1    False
dtype: bool[pyarrow]

对于object类型,pandas 将使用给定的值:

In [66]: s = pd.Series(["a", "b", "c"], dtype=object)

In [67]: s.loc[0] = None

In [68]: s.loc[1] = np.nan

In [69]: s
Out[69]: 
0    None
1     NaN
2       c
dtype: object

缺失数据的计算#

缺失值通过 pandas 对象之间的算术运算传播。

In [70]: ser1 = pd.Series([np.nan, np.nan, 2, 3])

In [71]: ser2 = pd.Series([np.nan, 1, np.nan, 4])

In [72]: ser1
Out[72]: 
0    NaN
1    NaN
2    2.0
3    3.0
dtype: float64

In [73]: ser2
Out[73]: 
0    NaN
1    1.0
2    NaN
3    4.0
dtype: float64

In [74]: ser1 + ser2
Out[74]: 
0    NaN
1    NaN
2    NaN
3    7.0
dtype: float64

数据结构概述中讨论的描述性统计和计算方法 (并在此处此处列出)都是针对缺失数据的说明。

对数据求和时,NA 值或空数据将被视为零。

In [75]: pd.Series([np.nan]).sum()
Out[75]: 0.0

In [76]: pd.Series([], dtype="float64").sum()
Out[76]: 0.0

取乘积时,NA值或空数据将被视为1。

In [77]: pd.Series([np.nan]).prod()
Out[77]: 1.0

In [78]: pd.Series([], dtype="float64").prod()
Out[78]: 1.0

默认情况下,累积方法(如cumsum()cumprod() 忽略 NA 值)将它们保留在结果中。可以通过以下方式更改此行为skipna

  • 默认情况下,累积方法cumsum()cumprod()忽略 NA 值,但会将它们保留在结果数组中。要覆盖此行为并包含 NA 值,请使用skipna=False

In [79]: ser = pd.Series([1, np.nan, 3, np.nan])

In [80]: ser
Out[80]: 
0    1.0
1    NaN
2    3.0
3    NaN
dtype: float64

In [81]: ser.cumsum()
Out[81]: 
0    1.0
1    NaN
2    4.0
3    NaN
dtype: float64

In [82]: ser.cumsum(skipna=False)
Out[82]: 
0    1.0
1    NaN
2    NaN
3    NaN
dtype: float64

删除丢失的数据#

dropna()dropa 缺少数据的行或列。

In [83]: df = pd.DataFrame([[np.nan, 1, 2], [1, 2, np.nan], [1, 2, 3]])

In [84]: df
Out[84]: 
     0  1    2
0  NaN  1  2.0
1  1.0  2  NaN
2  1.0  2  3.0

In [85]: df.dropna()
Out[85]: 
     0  1    2
2  1.0  2  3.0

In [86]: df.dropna(axis=1)
Out[86]: 
   1
0  1
1  2
2  2

In [87]: ser = pd.Series([1, pd.NA], dtype="int64[pyarrow]")

In [88]: ser.dropna()
Out[88]: 
0    1
dtype: int64[pyarrow]

填充缺失数据#

按值填充#

fillna()用非 NA 数据替换 NA 值。

将 NA 替换为标量值

In [89]: data = {"np": [1.0, np.nan, np.nan, 2], "arrow": pd.array([1.0, pd.NA, pd.NA, 2], dtype="float64[pyarrow]")}

In [90]: df = pd.DataFrame(data)

In [91]: df
Out[91]: 
    np  arrow
0  1.0    1.0
1  NaN   <NA>
2  NaN   <NA>
3  2.0    2.0

In [92]: df.fillna(0)
Out[92]: 
    np  arrow
0  1.0    1.0
1  0.0    0.0
2  0.0    0.0
3  2.0    2.0

向前或向后填补空白

In [93]: df.ffill()
Out[93]: 
    np  arrow
0  1.0    1.0
1  1.0    1.0
2  1.0    1.0
3  2.0    2.0

In [94]: df.bfill()
Out[94]: 
    np  arrow
0  1.0    1.0
1  2.0    2.0
2  2.0    2.0
3  2.0    2.0

限制填充的 NA 值的数量

In [95]: df.ffill(limit=1)
Out[95]: 
    np  arrow
0  1.0    1.0
1  1.0    1.0
2  NaN   <NA>
3  2.0    2.0

NA 值可以替换为来自 或 的相应值,Series其中DataFrame 索引和列在原始对象和填充对象之间对齐。

In [96]: dff = pd.DataFrame(np.arange(30, dtype=np.float64).reshape(10, 3), columns=list("ABC"))

In [97]: dff.iloc[3:5, 0] = np.nan

In [98]: dff.iloc[4:6, 1] = np.nan

In [99]: dff.iloc[5:8, 2] = np.nan

In [100]: dff
Out[100]: 
      A     B     C
0   0.0   1.0   2.0
1   3.0   4.0   5.0
2   6.0   7.0   8.0
3   NaN  10.0  11.0
4   NaN   NaN  14.0
5  15.0   NaN   NaN
6  18.0  19.0   NaN
7  21.0  22.0   NaN
8  24.0  25.0  26.0
9  27.0  28.0  29.0

In [101]: dff.fillna(dff.mean())
Out[101]: 
       A     B          C
0   0.00   1.0   2.000000
1   3.00   4.0   5.000000
2   6.00   7.0   8.000000
3  14.25  10.0  11.000000
4  14.25  14.5  14.000000
5  15.00  14.5  13.571429
6  18.00  19.0  13.571429
7  21.00  22.0  13.571429
8  24.00  25.0  26.000000
9  27.00  28.0  29.000000

笔记