可空整数数据类型#

注意

IntegerArray 目前仍处于实验阶段。其 API 或实现可能会在不通知的情况下发生更改。使用 pandas.NA 作为缺失值。

处理缺失数据中,我们了解到 pandas 主要使用 NaN 来表示缺失数据。由于 NaN 是一个浮点数,这强制将包含任何缺失值的整数数组转换为浮点数。在某些情况下,这可能关系不大。但如果您的整数列是标识符,则转换为浮点数可能会有问题。有些整数甚至无法表示为浮点数。

构造#

pandas 可以使用 arrays.IntegerArray 来表示可能包含缺失值的整数数据。这是在 pandas 内部实现的一个扩展类型

In [1]: arr = pd.array([1, 2, None], dtype=pd.Int64Dtype())

In [2]: arr
Out[2]: 
<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64

或者字符串别名 "Int64"(注意大写的 "I"),以区别于 NumPy 的 'int64' 数据类型。

In [3]: pd.array([1, 2, np.nan], dtype="Int64")
Out[3]: 
<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64

所有类似 NA 的值都将被替换为 pandas.NA

In [4]: pd.array([1, 2, np.nan, None, pd.NA], dtype="Int64")
Out[4]: 
<IntegerArray>
[1, 2, <NA>, <NA>, <NA>]
Length: 5, dtype: Int64

此数组可以像任何 NumPy 数组一样存储在 DataFrameSeries 中。

In [5]: pd.Series(arr)
Out[5]: 
0       1
1       2
2    <NA>
dtype: Int64

您也可以将列表类对象传递给带有 dtype 的 Series 构造函数。

警告

目前 pandas.array()pandas.Series() 在 dtype 推断方面使用不同的规则。pandas.array() 会推断出可空的整数 dtype。

In [6]: pd.array([1, None])
Out[6]: 
<IntegerArray>
[1, <NA>]
Length: 2, dtype: Int64

In [7]: pd.array([1, 2])
Out[7]: 
<IntegerArray>
[1, 2]
Length: 2, dtype: Int64

为了向后兼容,Series 会将这些推断为整数或浮点数 dtype。

In [8]: pd.Series([1, None])
Out[8]: 
0    1.0
1    NaN
dtype: float64

In [9]: pd.Series([1, 2])
Out[9]: 
0    1
1    2
dtype: int64

我们建议显式提供 dtype 以避免混淆。

In [10]: pd.array([1, None], dtype="Int64")
Out[10]: 
<IntegerArray>
[1, <NA>]
Length: 2, dtype: Int64

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

将来,我们可能会为 Series 提供一个选项来推断可空的整数 dtype。

如果您创建一个包含 NA 值的列(例如,为了稍后填充),使用 df['new_col'] = pd.NA,新列的 dtype 将被设置为 object。该列的性能会比使用适当类型差。最好使用 df['new_col'] = pd.Series(pd.NA, dtype="Int64")(或其他支持 NAdtype)。

In [12]: df = pd.DataFrame()

In [13]: df['objects'] = pd.NA

In [14]: df.dtypes
Out[14]: 
objects    object
dtype: object

操作#

涉及整数数组的操作将类似于 NumPy 数组。缺失值将被传播,并且数据将在需要时被强制转换为其他 dtype。

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

# arithmetic
In [16]: s + 1
Out[16]: 
0       2
1       3
2    <NA>
dtype: Int64

# comparison
In [17]: s == 1
Out[17]: 
0     True
1    False
2     <NA>
dtype: boolean

# slicing operation
In [18]: s.iloc[1:3]
Out[18]: 
1       2
2    <NA>
dtype: Int64

# operate with other dtypes
In [19]: s + s.iloc[1:3].astype("Int8")
Out[19]: 
0    <NA>
1       4
2    <NA>
dtype: Int64

# coerce when needed
In [20]: s + 0.01
Out[20]: 
0    1.01
1    2.01
2    <NA>
dtype: Float64

这些 dtype 可以作为 DataFrame 的一部分进行操作。

In [21]: df = pd.DataFrame({"A": s, "B": [1, 1, 3], "C": list("aab")})

In [22]: df
Out[22]: 
      A  B  C
0     1  1  a
1     2  1  a
2  <NA>  3  b

In [23]: df.dtypes
Out[23]: 
A    Int64
B    int64
C      str
dtype: object

这些 dtype 可以被合并、重塑和转换。

In [24]: pd.concat([df[["A"]], df[["B", "C"]]], axis=1).dtypes
Out[24]: 
A    Int64
B    int64
C      str
dtype: object

In [25]: df["A"].astype(float)
Out[25]: 
0    1.0
1    2.0
2    NaN
Name: A, dtype: float64

诸如 sum() 等归约和分组操作也能正常工作。

In [26]: df.sum(numeric_only=True)
Out[26]: 
A    3
B    5
dtype: Int64

In [27]: df.sum()
Out[27]: 
A      3
B      5
C    aab
dtype: object

In [28]: df.groupby("B").A.sum()
Out[28]: 
B
1    3
3    0
Name: A, dtype: Int64

标量 NA 值#

arrays.IntegerArray 使用 pandas.NA 作为其标量缺失值。对缺失的单个元素进行切片将返回 pandas.NA

In [29]: a = pd.array([1, None], dtype="Int64")

In [30]: a[1]
Out[30]: <NA>