版本 0.22.0 (2017年12月29日)#

这是 0.21.1 之后的一个主要版本,包含一项单一的、破坏 API 兼容性的更改。我们建议所有用户在仔细阅读此发布说明(单数形式!)后升级到此版本。

向后不兼容的 API 更改#

pandas 0.22.0 更改了空和全NA求和及求积的处理方式。摘要如下:

  • 空或全NASeries的和现在为0

  • 空或全NASeries的积现在为1

  • 我们在.sum().prod()中添加了一个min_count参数,用于控制结果有效所需的最小有效值数量。如果非NA值的数量少于min_count,则结果为NA。默认值为0。要返回NaN,即0.21版本的行为,请使用min_count=1

背景介绍:在pandas 0.21中,我们修复了一个长期存在的不一致问题,即全NA series的返回值取决于是否安装了bottleneck。详见全 NaN 或空 Series/DataFrame 的和/积现在统一为 NaN。同时,我们也将空Series的和与积更改为NaN

根据反馈,我们已部分恢复了这些更改。

算术运算#

空或全NASeries的默认和现在为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数组上的行为一致。

要使空series的求和返回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 series执行.sum在概念上与对空series执行.sum并设置skipna=True(默认值)的效果相同。

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

重采样#

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

特别是,上采样并求和或求积会受到影响,因为即使原始series完全有效,上采样也会引入缺失值。

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 series返回值的不一致性仍然存在。避免使用pandas 0.21仅能帮助解决空series的情况。

贡献者#

共有1人为本次发布贡献了补丁。名字旁边带有“+”的人是首次贡献补丁。

  • Tom Augspurger