版本 0.22.0(2017 年 12 月 29 日)#
这是 0.21.1 版本的一个重要发布,包含一个单独的、API 兼容性破坏的改动。我们建议所有用户在仔细阅读此发布说明(单数!)后升级到此版本。
向后不兼容的 API 更改#
pandas 0.22.0 改变了处理空序列和全 NA(缺失值)序列的求和与乘积的方式。总结如下:
空或全 NA 的
Series
的和现在是0
空或全 NA 的
Series
的积现在是1
我们为
.sum()
和.prod()
添加了一个min_count
参数,用于控制结果有效所需的最小有效值数量。如果存在的非 NA 值少于min_count
,则结果为 NA。默认值为0
。要返回NaN
(0.21 版本的行为),请使用min_count=1
。
背景介绍:在 pandas 0.21 中,我们修复了全 NA 序列返回值的一个长期存在的不一致性,该不一致性取决于是否安装了 bottleneck。详见 全 NaN 或空 Series/DataFrame 的 sum/prod 现在一致返回 NaN。与此同时,我们将空 Series
的 sum 和 prod 也改为了 NaN
。
根据反馈,我们部分回滚了这些更改。
算术运算#
空或全 NA 的 Series
的默认和现在是 0
。
pandas 0.21.x
In [1]: pd.Series([]).sum()
Out[1]: nan
In [2]: pd.Series([np.nan]).sum()
Out[2]: nan
pandas 0.22.0
In [1]: pd.Series([]).sum()
Out[1]: 0
In [2]: pd.Series([np.nan]).sum()
Out[2]: 0.0
默认行为与安装了 bottleneck 的 pandas 0.20.3 相同。它也与 NumPy 的 np.nansum
在空数组和全 NA 数组上的行为一致。
要使空序列的和返回 NaN
(这是未安装 bottleneck 的 pandas 0.20.3 或 pandas 0.21.x 的默认行为),请使用 min_count
关键字参数。
In [3]: pd.Series([]).sum(min_count=1)
Out[3]: nan
由于 skipna
参数的存在,对全 NA 序列执行 .sum
在概念上与对空序列执行带 skipna=True
(默认值)的 .sum
相同。
In [4]: pd.Series([np.nan]).sum(min_count=1) # skipna=True by default
Out[4]: nan
min_count
参数指的是对于非 NA 求和或乘积所需的最小非空值数量。
Series.prod()
已更新,其行为与 Series.sum()
相同,返回 1
而不是其他值。
In [5]: pd.Series([]).prod()
Out[5]: 1
In [6]: pd.Series([np.nan]).prod()
Out[6]: 1.0
In [7]: pd.Series([]).prod(min_count=1)
Out[7]: nan
这些更改也影响 DataFrame.sum()
和 DataFrame.prod()
。最后,pandas 中一些不太明显的地方也受到了此更改的影响。
按分类变量进行分组#
现在,按 Categorical
进行分组并求和时,对于没有观测值的类别,返回 0
而不是 NaN
。乘积现在返回 1
而不是 NaN
。
pandas 0.21.x
In [8]: grouper = pd.Categorical(['a', 'a'], categories=['a', 'b'])
In [9]: pd.Series([1, 2]).groupby(grouper, observed=False).sum()
Out[9]:
a 3.0
b NaN
dtype: float64
pandas 0.22
In [8]: grouper = pd.Categorical(["a", "a"], categories=["a", "b"])
In [9]: pd.Series([1, 2]).groupby(grouper, observed=False).sum()
Out[9]:
a 3
b 0
Length: 2, dtype: int64
要恢复 0.21 版本对于未观测分组返回 NaN
的行为,请使用 min_count>=1
。
In [10]: pd.Series([1, 2]).groupby(grouper, observed=False).sum(min_count=1)
Out[10]:
a 3.0
b NaN
Length: 2, dtype: float64
重采样 (Resample)#
全 NA 分组的求和和乘积已从 NaN
更改:求和现在返回 0
,乘积现在返回 1
。
pandas 0.21.x
In [11]: s = pd.Series([1, 1, np.nan, np.nan],
....: index=pd.date_range('2017', periods=4))
....: s
Out[11]:
2017-01-01 1.0
2017-01-02 1.0
2017-01-03 NaN
2017-01-04 NaN
Freq: D, dtype: float64
In [12]: s.resample('2d').sum()
Out[12]:
2017-01-01 2.0
2017-01-03 NaN
Freq: 2D, dtype: float64
pandas 0.22.0
In [11]: s = pd.Series([1, 1, np.nan, np.nan], index=pd.date_range("2017", periods=4))
In [12]: s.resample("2d").sum()
Out[12]:
2017-01-01 2.0
2017-01-03 0.0
Freq: 2D, Length: 2, dtype: float64
要恢复 0.21 版本返回 NaN
的行为,请使用 min_count>=1
。
In [13]: s.resample("2d").sum(min_count=1)
Out[13]:
2017-01-01 2.0
2017-01-03 NaN
Freq: 2D, Length: 2, dtype: float64
特别是,上采样并进行求和或乘积的操作受到了影响,因为即使原始序列是完全有效的,上采样也会引入缺失值。
pandas 0.21.x
In [14]: idx = pd.DatetimeIndex(['2017-01-01', '2017-01-02'])
In [15]: pd.Series([1, 2], index=idx).resample('12H').sum()
Out[15]:
2017-01-01 00:00:00 1.0
2017-01-01 12:00:00 NaN
2017-01-02 00:00:00 2.0
Freq: 12H, dtype: float64
pandas 0.22.0
In [14]: idx = pd.DatetimeIndex(["2017-01-01", "2017-01-02"])
In [15]: pd.Series([1, 2], index=idx).resample("12H").sum()
Out[15]:
2017-01-01 00:00:00 1
2017-01-01 12:00:00 0
2017-01-02 00:00:00 2
Freq: 12H, Length: 3, dtype: int64
同样地,可以使用 min_count
关键字参数来恢复 0.21 版本的行为。
In [16]: pd.Series([1, 2], index=idx).resample("12H").sum(min_count=1)
Out[16]:
2017-01-01 00:00:00 1.0
2017-01-01 12:00:00 NaN
2017-01-02 00:00:00 2.0
Freq: 12H, Length: 3, dtype: float64
滚动和扩张#
滚动和扩张操作已经有一个 min_periods
关键字参数,其行为类似于 min_count
。唯一改变的情况是当进行带 min_periods=0
的滚动或扩张求和时。以前,当窗口中的非 NA 值少于 min_periods
时,会返回 NaN
。现在返回 0
。
pandas 0.21.1
In [17]: s = pd.Series([np.nan, np.nan])
In [18]: s.rolling(2, min_periods=0).sum()
Out[18]:
0 NaN
1 NaN
dtype: float64
pandas 0.22.0
In [14]: s = pd.Series([np.nan, np.nan])
In [15]: s.rolling(2, min_periods=0).sum()
Out[15]:
0 0.0
1 0.0
Length: 2, dtype: float64
默认行为 min_periods=None
(意味着 min_periods
等于窗口大小)保持不变。
兼容性#
如果您维护一个需要在不同 pandas 版本下工作的库,最简单的方法可能是从您的依赖项中排除 pandas 0.21。否则,您的所有 sum()
调用都需要在求和前检查 Series
是否为空。
使用 setuptools,在您的 setup.py
中使用
install_requires=['pandas!=0.21.*', ...]
使用 conda,使用
requirements:
run:
- pandas !=0.21.0,!=0.21.1
请注意,对于 pandas 0.20.3 及更早版本,全 NA 序列返回值的不一致性仍然存在。避免使用 pandas 0.21 只对空序列的情况有帮助。
贡献者#
共有 1 位贡献者为本次发布贡献了补丁。名字旁边带有“+”的人是首次贡献补丁。
Tom Augspurger