版本 0.19.0 (2016 年 10 月 2 日)#

这是 0.18.1 版本的一个主要更新,包含多项 API 变更、一些新特性、增强功能和性能改进,以及大量的 bug 修复。我们建议所有用户升级到此版本。

主要亮点包括

  • 用于 asof 风格时间序列连接的 merge_asof(),详见此处

  • .rolling() 现在具备时间序列感知能力,详见此处

  • read_csv() 现在支持解析 Categorical 数据,详见此处

  • 新增了用于合并 Categorical 数据的函数 union_categorical(),详见此处

  • PeriodIndex 现在拥有自己的 period dtype,并且变得与其他 Index 类更加一致。详见此处

  • 稀疏数据结构增强了对 intbool dtypes 的支持,详见此处

  • Series 的比较操作不再忽略索引,关于 API 变更的概述,详见此处

  • 引入了用于实用函数的 pandas 开发 API,详见此处

  • Panel4DPanelND 已弃用。我们建议使用 xarray 包来表示这类 n 维数据。

  • 移除了先前已弃用的模块 pandas.io.datapandas.io.wbpandas.tools.rplot

警告

pandas >= 0.19.0 在导入时不再静默处理 numpy ufunc 警告,详见此处

新特性#

用于 asof 风格时间序列连接的函数 merge_asof#

通过函数 merge_asof() 添加了一个长期以来被请求的功能,以支持 asof 风格的时间序列连接(GH 1870, GH 13695, GH 13709, GH 13902)。完整文档请参阅此处

merge_asof() 执行 asof 合并,这类似于左连接,但不是基于相等键匹配,而是基于最近键匹配。

In [1]: left = pd.DataFrame({"a": [1, 5, 10], "left_val": ["a", "b", "c"]})

In [2]: right = pd.DataFrame({"a": [1, 2, 3, 6, 7], "right_val": [1, 2, 3, 6, 7]})

In [3]: left
Out[3]: 
    a left_val
0   1        a
1   5        b
2  10        c

[3 rows x 2 columns]

In [4]: right
Out[4]: 
   a  right_val
0  1          1
1  2          2
2  3          3
3  6          6
4  7          7

[5 rows x 2 columns]

通常,我们希望尽可能精确匹配,否则使用最近的值。

In [5]: pd.merge_asof(left, right, on="a")
Out[5]: 
    a left_val  right_val
0   1        a          1
1   5        b          3
2  10        c          7

[3 rows x 3 columns]

我们也可以只匹配先行数据(prior data),而不是精确匹配。

In [6]: pd.merge_asof(left, right, on="a", allow_exact_matches=False)
Out[6]: 
    a left_val  right_val
0   1        a        NaN
1   5        b        3.0
2  10        c        7.0

[3 rows x 3 columns]

在典型的时间序列示例中,我们有 tradesquotes,我们想对它们进行 asof-join。这也说明了如何使用 by 参数在合并前对数据进行分组。

In [7]: trades = pd.DataFrame(
   ...:     {
   ...:         "time": pd.to_datetime(
   ...:             [
   ...:                 "20160525 13:30:00.023",
   ...:                 "20160525 13:30:00.038",
   ...:                 "20160525 13:30:00.048",
   ...:                 "20160525 13:30:00.048",
   ...:                 "20160525 13:30:00.048",
   ...:             ]
   ...:         ),
   ...:         "ticker": ["MSFT", "MSFT", "GOOG", "GOOG", "AAPL"],
   ...:         "price": [51.95, 51.95, 720.77, 720.92, 98.00],
   ...:         "quantity": [75, 155, 100, 100, 100],
   ...:     },
   ...:     columns=["time", "ticker", "price", "quantity"],
   ...: )
   ...: 

In [8]: quotes = pd.DataFrame(
   ...:     {
   ...:         "time": pd.to_datetime(
   ...:             [
   ...:                 "20160525 13:30:00.023",
   ...:                 "20160525 13:30:00.023",
   ...:                 "20160525 13:30:00.030",
   ...:                 "20160525 13:30:00.041",
   ...:                 "20160525 13:30:00.048",
   ...:                 "20160525 13:30:00.049",
   ...:                 "20160525 13:30:00.072",
   ...:                 "20160525 13:30:00.075",
   ...:             ]
   ...:         ),
   ...:         "ticker": ["GOOG", "MSFT", "MSFT", "MSFT", "GOOG", "AAPL", "GOOG", "MSFT"],
   ...:         "bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],
   ...:         "ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03],
   ...:     },
   ...:     columns=["time", "ticker", "bid", "ask"],
   ...: )
   ...: 
In [9]: trades
Out[9]: 
                     time ticker   price  quantity
0 2016-05-25 13:30:00.023   MSFT   51.95        75
1 2016-05-25 13:30:00.038   MSFT   51.95       155
2 2016-05-25 13:30:00.048   GOOG  720.77       100
3 2016-05-25 13:30:00.048   GOOG  720.92       100
4 2016-05-25 13:30:00.048   AAPL   98.00       100

[5 rows x 4 columns]

In [10]: quotes
Out[10]: 
                     time ticker     bid     ask
0 2016-05-25 13:30:00.023   GOOG  720.50  720.93
1 2016-05-25 13:30:00.023   MSFT   51.95   51.96
2 2016-05-25 13:30:00.030   MSFT   51.97   51.98
3 2016-05-25 13:30:00.041   MSFT   51.99   52.00
4 2016-05-25 13:30:00.048   GOOG  720.50  720.93
5 2016-05-25 13:30:00.049   AAPL   97.99   98.01
6 2016-05-25 13:30:00.072   GOOG  720.50  720.88
7 2016-05-25 13:30:00.075   MSFT   52.01   52.03

[8 rows x 4 columns]

Asof 合并基于 on 字段进行连接,通常是一个有序的日期时间字段,在此示例中,我们在 by 字段中使用了分组器。这类似于左外连接,不同之处在于会自动进行向前填充,获取最近的非 NaN 值。

In [11]: pd.merge_asof(trades, quotes, on="time", by="ticker")
Out[11]: 
                     time ticker   price  quantity     bid     ask
0 2016-05-25 13:30:00.023   MSFT   51.95        75   51.95   51.96
1 2016-05-25 13:30:00.038   MSFT   51.95       155   51.97   51.98
2 2016-05-25 13:30:00.048   GOOG  720.77       100  720.50  720.93
3 2016-05-25 13:30:00.048   GOOG  720.92       100  720.50  720.93
4 2016-05-25 13:30:00.048   AAPL   98.00       100     NaN     NaN

[5 rows x 6 columns]

这将返回一个合并后的 DataFrame,其条目顺序与原始左侧传入的 DataFrame(在此例中为 trades)相同,并合并了 quotes 的字段。

方法 .rolling() 现在具备时间序列感知能力#

.rolling() 对象现在具备时间序列感知能力,并且可以为 window 参数接受时间序列偏移量(或可转换类型)(GH 13327, GH 12995)。请参阅完整文档此处

In [12]: dft = pd.DataFrame(
   ....:     {"B": [0, 1, 2, np.nan, 4]},
   ....:     index=pd.date_range("20130101 09:00:00", periods=5, freq="s"),
   ....: )
   ....: 

In [13]: dft
Out[13]: 
                       B
2013-01-01 09:00:00  0.0
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  2.0
2013-01-01 09:00:03  NaN
2013-01-01 09:00:04  4.0

[5 rows x 1 columns]

这是一个常规频率索引。使用整数窗口参数可以沿着窗口频率滚动。

In [14]: dft.rolling(2).sum()
Out[14]: 
                       B
2013-01-01 09:00:00  NaN
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  NaN
2013-01-01 09:00:04  NaN

[5 rows x 1 columns]

In [15]: dft.rolling(2, min_periods=1).sum()
Out[15]: 
                       B
2013-01-01 09:00:00  0.0
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  2.0
2013-01-01 09:00:04  4.0

[5 rows x 1 columns]

指定偏移量可以更直观地指定滚动频率。

In [16]: dft.rolling("2s").sum()
Out[16]: 
                       B
2013-01-01 09:00:00  0.0
2013-01-01 09:00:01  1.0
2013-01-01 09:00:02  3.0
2013-01-01 09:00:03  2.0
2013-01-01 09:00:04  4.0

[5 rows x 1 columns]

对于非规则但单调的索引,使用整数窗口进行滚动不会进行任何特殊计算。

In [17]: dft = pd.DataFrame(
   ....:     {"B": [0, 1, 2, np.nan, 4]},
   ....:     index=pd.Index(
   ....:         [
   ....:             pd.Timestamp("20130101 09:00:00"),
   ....:             pd.Timestamp("20130101 09:00:02"),
   ....:             pd.Timestamp("20130101 09:00:03"),
   ....:             pd.Timestamp("20130101 09:00:05"),
   ....:             pd.Timestamp("20130101 09:00:06"),
   ....:         ],
   ....:         name="foo",
   ....:     ),
   ....: )
   ....: 

In [18]: dft
Out[18]: 
                       B
foo                     
2013-01-01 09:00:00  0.0
2013-01-01 09:00:02  1.0
2013-01-01 09:00:03  2.0
2013-01-01 09:00:05  NaN
2013-01-01 09:00:06  4.0

[5 rows x 1 columns]

In [19]: dft.rolling(2).sum()
Out[19]: 
                       B
foo                     
2013-01-01 09:00:00  NaN
2013-01-01 09:00:02  1.0
2013-01-01 09:00:03  3.0
2013-01-01 09:00:05  NaN
2013-01-01 09:00:06  NaN

[5 rows x 1 columns]

使用时间规范会为这些稀疏数据生成可变窗口。

In [20]: dft.rolling("2s").sum()
Out[20]: 
                       B
foo                     
2013-01-01 09:00:00  0.0
2013-01-01 09:00:02  1.0
2013-01-01 09:00:03  3.0
2013-01-01 09:00:05  NaN
2013-01-01 09:00:06  4.0

[5 rows x 1 columns]

此外,我们现在允许使用可选的 on 参数来指定 DataFrame 中的一个列(而不是默认的索引)。

In [21]: dft = dft.reset_index()

In [22]: dft
Out[22]: 
                  foo    B
0 2013-01-01 09:00:00  0.0
1 2013-01-01 09:00:02  1.0
2 2013-01-01 09:00:03  2.0
3 2013-01-01 09:00:05  NaN
4 2013-01-01 09:00:06  4.0

[5 rows x 2 columns]

In [23]: dft.rolling("2s", on="foo").sum()
Out[23]: 
                  foo    B
0 2013-01-01 09:00:00  0.0
1 2013-01-01 09:00:02  1.0
2 2013-01-01 09:00:03  3.0
3 2013-01-01 09:00:05  NaN
4 2013-01-01 09:00:06  4.0

[5 rows x 2 columns]

方法 read_csv 对重复列名有了更好的支持#

重复列名现在在 read_csv() 中受到支持,无论它们是在文件中还是作为 names 参数传入(GH 7160, GH 9424

In [24]: data = "0,1,2\n3,4,5"

In [25]: names = ["a", "b", "a"]

旧的行为:

In [2]: pd.read_csv(StringIO(data), names=names)
Out[2]:
   a  b  a
0  2  1  2
1  5  4  5

第一个 a 列包含了与第二个 a 列相同的数据,而它本应包含值 [0, 3]

新的行为:

In [26]: pd.read_csv(StringIO(data), names=names)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[26], line 1
----> 1 pd.read_csv(StringIO(data), names=names)

File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
   1013 kwds_defaults = _refine_defaults_read(
   1014     dialect,
   1015     delimiter,
   (...)
   1022     dtype_backend=dtype_backend,
   1023 )
   1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)

File ~/work/pandas/pandas/pandas/io/parsers/readers.py:617, in _read(filepath_or_buffer, kwds)
    614 nrows = kwds.get("nrows", None)
    616 # Check for duplicates in names.
--> 617 _validate_names(kwds.get("names", None))
    619 # Create the parser.
    620 parser = TextFileReader(filepath_or_buffer, **kwds)

File ~/work/pandas/pandas/pandas/io/parsers/readers.py:576, in _validate_names(names)
    574 if names is not None:
    575     if len(names) != len(set(names)):
--> 576         raise ValueError("Duplicate names are not allowed.")
    577     if not (
    578         is_list_like(names, allow_sets=False) or isinstance(names, abc.KeysView)
    579     ):
    580         raise ValueError("Names should be an ordered collection.")

ValueError: Duplicate names are not allowed.

方法 read_csv 直接支持解析 Categorical 数据#

read_csv() 函数现在支持在指定为 dtype 时解析 Categorical 列(GH 10153)。根据数据的结构,与解析后再转换为 Categorical 相比,这可以加快解析时间并降低内存使用。请参阅 io 文档此处

In [27]: data = """
   ....: col1,col2,col3
   ....: a,b,1
   ....: a,b,2
   ....: c,d,3
   ....: """
   ....: 

In [28]: pd.read_csv(StringIO(data))
Out[28]: 
  col1 col2  col3
0    a    b     1
1    a    b     2
2    c    d     3

[3 rows x 3 columns]

In [29]: pd.read_csv(StringIO(data)).dtypes
Out[29]: 
col1    object
col2    object
col3     int64
Length: 3, dtype: object

In [30]: pd.read_csv(StringIO(data), dtype="category").dtypes
Out[30]: 
col1    category
col2    category
col3    category
Length: 3, dtype: object

可以使用字典规范将单独的列解析为 Categorical

In [31]: pd.read_csv(StringIO(data), dtype={"col1": "category"}).dtypes
Out[31]: 
col1    category
col2      object
col3       int64
Length: 3, dtype: object

注意

生成的类别将始终被解析为字符串(object dtype)。如果类别是数字,可以使用 to_numeric() 函数进行转换,或者根据需要使用其他转换器,例如 to_datetime()

In [32]: df = pd.read_csv(StringIO(data), dtype="category")

In [33]: df.dtypes
Out[33]: 
col1    category
col2    category
col3    category
Length: 3, dtype: object

In [34]: df["col3"]
Out[34]: 
0    1
1    2
2    3
Name: col3, Length: 3, dtype: category
Categories (3, object): ['1', '2', '3']

In [35]: new_categories = pd.to_numeric(df["col3"].cat.categories)

In [36]: df["col3"] = df["col3"].cat.rename_categories(new_categories)

In [37]: df["col3"]
Out[37]: 
0    1
1    2
2    3
Name: col3, Length: 3, dtype: category
Categories (3, int64): [1, 2, 3]

Categorical 数据连接#

  • 新增了用于组合 Categorical 数据的函数 union_categoricals(),详见合并 Categorical 数据GH 13361, GH 13763, GH 13846, GH 14173

    In [38]: from pandas.api.types import union_categoricals
    
    In [39]: a = pd.Categorical(["b", "c"])
    
    In [40]: b = pd.Categorical(["a", "b"])
    
    In [41]: union_categoricals([a, b])
    Out[41]: 
    ['b', 'c', 'a', 'b']
    Categories (3, object): ['b', 'c', 'a']
    
  • concatappend 现在可以将具有不同 categoriescategory dtypes 合并为 object dtype(GH 13524

    In [42]: s1 = pd.Series(["a", "b"], dtype="category")
    
    In [43]: s2 = pd.Series(["b", "c"], dtype="category")
    

旧的行为:

In [1]: pd.concat([s1, s2])
ValueError: incompatible categories in categorical concat

新的行为:

In [44]: pd.concat([s1, s2])
Out[44]: 
0    a
1    b
0    b
1    c
Length: 4, dtype: object

半月偏移#

pandas 新增了频率偏移量:SemiMonthEnd ('SM') 和 SemiMonthBegin ('SMS')。它们分别提供了默认锚定到每月 15 日和月末,以及每月 15 日和月初的日期偏移量。(GH 1543

In [45]: from pandas.tseries.offsets import SemiMonthEnd, SemiMonthBegin

SemiMonthEnd:

In [46]: pd.Timestamp("2016-01-01") + SemiMonthEnd()
Out[46]: Timestamp('2016-01-15 00:00:00')

In [47]: pd.date_range("2015-01-01", freq="SM", periods=4)
Out[47]: DatetimeIndex(['2015-01-15', '2015-01-31', '2015-02-15', '2015-02-28'], dtype='datetime64[ns]', freq='SM-15')

SemiMonthBegin:

In [46]: pd.Timestamp("2016-01-01") + SemiMonthBegin()
Out[46]: Timestamp('2016-01-15 00:00:00')

In [47]: pd.date_range("2015-01-01", freq="SMS", periods=4)
Out[47]: DatetimeIndex(['2015-01-01', '2015-01-15', '2015-02-01', '2015-02-15'], dtype='datetime64[ns]', freq='SMS-15')

使用锚定后缀,您还可以指定月份中的某一天来替代 15 日。

In [50]: pd.date_range("2015-01-01", freq="SMS-16", periods=4)
Out[50]: DatetimeIndex(['2015-01-01', '2015-01-16', '2015-02-01', '2015-02-16'], dtype='datetime64[ns]', freq='SMS-16')

In [51]: pd.date_range("2015-01-01", freq="SM-14", periods=4)
Out[51]: DatetimeIndex(['2015-01-14', '2015-01-31', '2015-02-14', '2015-02-28'], dtype='datetime64[ns]', freq='SM-14')

新的 Index 方法#

为了与 SeriesDataFrame API 更一致,Index 添加了以下方法和选项。

Index 现在支持用于相同形状索引的 .where() 函数(GH 13170

In [48]: idx = pd.Index(["a", "b", "c"])

In [49]: idx.where([True, False, True])
Out[49]: Index(['a', None, 'c'], dtype='object')

Index 现在支持 .dropna() 以排除缺失值(GH 6194

In [50]: idx = pd.Index([1, 2, np.nan, 4])

In [51]: idx.dropna()
Out[51]: Index([1.0, 2.0, 4.0], dtype='float64')

对于 MultiIndex,默认情况下如果任何级别有缺失值,则会删除对应的值。指定 how='all' 只删除所有级别都有缺失值的情况。

In [52]: midx = pd.MultiIndex.from_arrays([[1, 2, np.nan, 4], [1, 2, np.nan, np.nan]])

In [53]: midx
Out[53]: 
MultiIndex([(1.0, 1.0),
            (2.0, 2.0),
            (nan, nan),
            (4.0, nan)],
           )

In [54]: midx.dropna()
Out[54]: 
MultiIndex([(1, 1),
            (2, 2)],
           )

In [55]: midx.dropna(how="all")
Out[55]: 
MultiIndex([(1, 1.0),
            (2, 2.0),
            (4, nan)],
           )

Index 现在支持 .str.extractall(),它返回一个 DataFrame,详见此处文档GH 10008, GH 13156

In [56]: idx = pd.Index(["a1a2", "b1", "c1"])

In [57]: idx.str.extractall(r"[ab](?P<digit>\d)")
Out[57]: 
        digit
  match      
0 0         1
  1         2
1 0         1

[3 rows x 1 columns]

Index.astype() 现在接受一个可选的布尔参数 copy,如果 dtype 要求满足,它允许可选地进行复制(GH 13209

Google BigQuery 增强功能#

  • read_gbq() 方法新增了 dialect 参数,允许用户指定使用 BigQuery 的旧版 SQL 还是标准 SQL。更多详情请参阅文档GH 13615)。

  • to_gbq() 方法现在允许 DataFrame 的列顺序与目标表 schema 不同(GH 11359)。

细粒度 NumPy 错误状态处理#

之前版本的 pandas 在导入 pandas 时会永久静默 numpy 的 ufunc 错误处理。pandas 这样做是为了抑制在使用 numpy ufuncs 处理缺失数据(通常表示为 NaN)时产生的警告。不幸的是,这也会静默应用程序中非 pandas 代码产生的合法警告。从 0.19.0 版本开始,pandas 将使用 numpy.errstate 上下文管理器以更细粒度的方式静默这些警告,仅在 pandas 代码库中实际使用这些操作的地方进行。(GH 13109, GH 13145)

升级 pandas 后,您可能会看到 新的 RuntimeWarnings 被代码发出。这些警告很可能是合法的,并且其根本原因在使用先前版本 pandas(仅静默了警告)时就已存在。请在 RuntimeWarning 的来源处使用 numpy.errstate 来控制如何处理这些情况。

方法 get_dummies 现在返回整数 dtypes#

pd.get_dummies 函数现在将独热编码(dummy-encoded)的列返回为小整数,而不是浮点数(GH 8725)。这应该可以改善内存占用。

旧的行为:

In [1]: pd.get_dummies(['a', 'b', 'a', 'c']).dtypes

Out[1]:
a    float64
b    float64
c    float64
dtype: object

新的行为:

In [58]: pd.get_dummies(["a", "b", "a", "c"]).dtypes
Out[58]: 
a    bool
b    bool
c    bool
Length: 3, dtype: object

to_numeric 中将值向下转换为最小可能的 dtype#

pd.to_numeric() 现在接受一个 downcast 参数,如果可能,它会将数据向下转换为指定的最小数值 dtype(GH 13352

In [59]: s = ["1", 2, 3]

In [60]: pd.to_numeric(s, downcast="unsigned")
Out[60]: array([1, 2, 3], dtype=uint8)

In [61]: pd.to_numeric(s, downcast="integer")
Out[61]: array([1, 2, 3], dtype=int8)

pandas 开发 API#

作为未来使 pandas API 更统一和易于访问的一部分,我们创建了一个标准的 pandas 子包 pandas.api 来存放公共 API。我们首先在 pandas.api.types 中暴露类型自省函数。更多子包和官方认可的 API 将在未来版本的 pandas 中发布(GH 13147, GH 13634

以下现在是此 API 的一部分

In [62]: import pprint

In [63]: from pandas.api import types

In [64]: funcs = [f for f in dir(types) if not f.startswith("_")]

In [65]: pprint.pprint(funcs)
['CategoricalDtype',
 'DatetimeTZDtype',
 'IntervalDtype',
 'PeriodDtype',
 'infer_dtype',
 'is_any_real_numeric_dtype',
 'is_array_like',
 'is_bool',
 'is_bool_dtype',
 'is_categorical_dtype',
 'is_complex',
 'is_complex_dtype',
 'is_datetime64_any_dtype',
 'is_datetime64_dtype',
 'is_datetime64_ns_dtype',
 'is_datetime64tz_dtype',
 'is_dict_like',
 'is_dtype_equal',
 'is_extension_array_dtype',
 'is_file_like',
 'is_float',
 'is_float_dtype',
 'is_hashable',
 'is_int64_dtype',
 'is_integer',
 'is_integer_dtype',
 'is_interval',
 'is_interval_dtype',
 'is_iterator',
 'is_list_like',
 'is_named_tuple',
 'is_number',
 'is_numeric_dtype',
 'is_object_dtype',
 'is_period_dtype',
 'is_re',
 'is_re_compilable',
 'is_scalar',
 'is_signed_integer_dtype',
 'is_sparse',
 'is_string_dtype',
 'is_timedelta64_dtype',
 'is_timedelta64_ns_dtype',
 'is_unsigned_integer_dtype',
 'pandas_dtype',
 'union_categoricals']

注意

现在从内部模块 pandas.core.common 调用这些函数将显示 DeprecationWarningGH 13990

其他增强功能#

  • Timestamp 现在可以接受类似于 datetime.datetime() 的位置参数和关键字参数(GH 10758, GH 11630

    In [66]: pd.Timestamp(2012, 1, 1)
    Out[66]: Timestamp('2012-01-01 00:00:00')
    
    In [67]: pd.Timestamp(year=2012, month=1, day=1, hour=8, minute=30)
    Out[67]: Timestamp('2012-01-01 08:30:00')
    
  • .resample() 函数现在接受 on=level= 参数,用于在日期时间列或 MultiIndex 级别上进行重采样(GH 13500

    In [68]: df = pd.DataFrame(
       ....:     {"date": pd.date_range("2015-01-01", freq="W", periods=5), "a": np.arange(5)},
       ....:     index=pd.MultiIndex.from_arrays(
       ....:         [[1, 2, 3, 4, 5], pd.date_range("2015-01-01", freq="W", periods=5)],
       ....:         names=["v", "d"],
       ....:     ),
       ....: )
       ....: 
    
    In [69]: df
    Out[69]: 
                       date  a
    v d                       
    1 2015-01-04 2015-01-04  0
    2 2015-01-11 2015-01-11  1
    3 2015-01-18 2015-01-18  2
    4 2015-01-25 2015-01-25  3
    5 2015-02-01 2015-02-01  4
    
    [5 rows x 2 columns]
    
    In [74]: df.resample("M", on="date")[["a"]].sum()
    Out[74]:
                a
    date
    2015-01-31  6
    2015-02-28  4
    
    [2 rows x 1 columns]
    
    In [75]: df.resample("M", level="d")[["a"]].sum()
    Out[75]:
                a
    d
    2015-01-31  6
    2015-02-28  4
    
    [2 rows x 1 columns]
    
  • GbqConnector.get_credentials() 方法现在可以首先尝试获取应用程序默认凭据。更多详情请参阅文档(GH 13577)。

  • DatetimeIndexTimestamp.tz_localize() 方法新增了 errors 关键字,因此您可以潜在地将不存在的时间戳强制转换为 NaT。默认行为仍然是引发 NonExistentTimeErrorGH 13057)。

  • .to_hdf/read_hdf() 现在接受文件路径的路径对象(例如 pathlib.Path, py.path.local)(GH 11773

  • 带有 engine='python'pd.read_csv() 现在支持 decimalGH 12933)、na_filterGH 13321)和 memory_map 选项(GH 13381)。

  • 与 Python API 一致,pd.read_csv() 现在将 +inf 解释为正无穷大(GH 13274

  • pd.read_html() 新增支持 na_valuesconverterskeep_default_na 选项(GH 13461

  • Categorical.astype() 现在接受一个可选的布尔参数 copy,当 dtype 是 categorical 时有效(GH 13209

  • DataFrame 新增了 .asof() 方法,用于根据选定的子集返回最后一个非 NaN 值(GH 13358

  • 如果传入 OrderedDict 对象的列表,DataFrame 构造函数现在将尊重键的顺序(GH 13304

  • pd.read_html() 新增支持 decimal 选项(GH 12907

  • Series 新增了属性 .is_monotonic, .is_monotonic_increasing, .is_monotonic_decreasing,类似于 IndexGH 13336

  • DataFrame.to_sql() 现在允许将单个值作为所有列的 SQL 类型(GH 11886)。

  • Series.append 现在支持 ignore_index 选项(GH 13677

  • .to_stata()StataWriter 现在可以使用字典将列名映射到变量标签,并写入 Stata dta 文件(GH 13535, GH 13536

  • .to_stata()StataWriter 会自动将 datetime64[ns] 列转换为 Stata 格式 %tc,而不是引发 ValueErrorGH 12259

  • 当读取带有重复值标签的 Stata 文件且 convert_categoricals=True 时,read_stata()StataReader 会引发更明确的错误消息(GH 13923

  • DataFrame.style 现在将渲染稀疏化的 MultiIndex(GH 11655

  • DataFrame.style 现在将显示列级别的名称(例如 DataFrame.columns.names)(GH 13775

  • DataFrame 新增支持使用 df.sort_values(by='...', axis=1) 根据行中的值重新排序列(GH 10806

    In [70]: df = pd.DataFrame({"A": [2, 7], "B": [3, 5], "C": [4, 8]}, index=["row1", "row2"])
    
    In [71]: df
    Out[71]: 
          A  B  C
    row1  2  3  4
    row2  7  5  8
    
    [2 rows x 3 columns]
    
    In [72]: df.sort_values(by="row2", axis=1)
    Out[72]: 
          B  A  C
    row1  3  2  4
    row2  5  7  8
    
    [2 rows x 3 columns]
    
  • I/O 文档中增加了关于读取混合 dtype 列的风险以及如何处理的说明(GH 13746

  • to_html() 现在有一个 border 参数来控制开头的 <table> 标签中的值。默认值为 html.border 选项的值,该选项默认为 1。这也影响 notebook 的 HTML repr,但由于 Jupyter 的 CSS 包含了 border-width 属性,视觉效果是相同的。(GH 11563)。

  • 在 sql 函数中使用连接字符串时,如果未安装 sqlalchemy,则抛出 ImportError (GH 11920)。

  • 与 matplotlib 2.0 的兼容性。旧版本的 pandas 也应与 matplotlib 2.0 兼容 (GH 13333)

  • Timestamp, Period, DatetimeIndex, PeriodIndex.dt 访问器新增了 .is_leap_year 属性,用于检查日期是否属于闰年 (GH 13727)。

  • astype() 现在接受列名到数据类型映射的字典作为 dtype 参数 (GH 12086)。

  • pd.read_jsonDataFrame.to_json 新增支持使用 lines 选项读取和写入 json lines,详见 行分隔的 json (GH 9180)。

  • read_excel() 现在支持 true_values 和 false_values 关键字参数 (GH 13347)。

  • groupby() 现在接受标量和单元素列表,用于在非 MultiIndex 分组器上指定 level (GH 13907)。

  • Excel 日期列中不可转换的日期将直接返回,不进行转换,并且该列的 object dtype 将是 object,而不是抛出异常 (GH 10001)。

  • pd.Timedelta(None) 现在被接受并返回 NaT,与 pd.Timestamp 保持一致 (GH 13687)。

  • pd.read_stata() 现在可以处理一些格式 111 文件,这些文件由 SAS 在生成 Stata dta 文件时产生 (GH 11526)。

  • SeriesIndex 现在支持 divmod,这将返回一个 Series 或 Index 的元组。这在广播规则方面表现得像标准的二元运算符 (GH 14208)。

API 变更#

Series.tolist() 现在将返回 Python 类型#

Series.tolist() 现在将在输出中返回 Python 类型,模仿 NumPy .tolist() 的行为 (GH 10904)。

In [73]: s = pd.Series([1, 2, 3])

旧的行为:

In [7]: type(s.tolist()[0])
Out[7]:
 <class 'numpy.int64'>

新的行为:

In [74]: type(s.tolist()[0])
Out[74]: int

Series 不同索引的运算符#

以下 Series 运算符已更改,以便所有运算符(包括 DataFrame)保持一致 (GH 1134, GH 4581, GH 13538)

  • Series 比较运算符在 index 不同时现在抛出 ValueError

  • Series 逻辑运算符会对其左右两边的 index 进行对齐。

警告

在 0.18.1 版本之前,长度相同的 Series 即使 .index 不同也可以成功比较(结果忽略 .index)。从 0.19.0 版本开始,这将抛出 ValueError 以更严格。本节还描述了如何保留以前的行为或对齐不同的索引,使用灵活的比较方法,如 .eq

因此,SeriesDataFrame 运算符的行为如下所示

算术运算符#

算术运算符对齐两个 index(无变化)。

In [75]: s1 = pd.Series([1, 2, 3], index=list("ABC"))

In [76]: s2 = pd.Series([2, 2, 2], index=list("ABD"))

In [77]: s1 + s2
Out[77]: 
A    3.0
B    4.0
C    NaN
D    NaN
Length: 4, dtype: float64

In [78]: df1 = pd.DataFrame([1, 2, 3], index=list("ABC"))

In [79]: df2 = pd.DataFrame([2, 2, 2], index=list("ABD"))

In [80]: df1 + df2
Out[80]: 
     0
A  3.0
B  4.0
C  NaN
D  NaN

[4 rows x 1 columns]

比较运算符#

比较运算符在 .index 不同时抛出 ValueError

以前的行为Series

只要两个 Series 长度相同,比较值时会忽略 .index

In [1]: s1 == s2
Out[1]:
A    False
B     True
C    False
dtype: bool

新的行为Series

In [2]: s1 == s2
Out[2]:
ValueError: Can only compare identically-labeled Series objects

注意

要实现与以前版本相同的行为(基于位置比较值,忽略 .index),请比较两者的 .values

In [81]: s1.values == s2.values
Out[81]: array([False,  True, False])

如果你想对齐 .index 后比较 Series,请参阅下面的灵活比较方法部分

In [82]: s1.eq(s2)
Out[82]: 
A    False
B     True
C    False
D    False
Length: 4, dtype: bool

目前的行为DataFrame,无变化)

In [3]: df1 == df2
Out[3]:
ValueError: Can only compare identically-labeled DataFrame objects

逻辑运算符#

逻辑运算符对齐左右两边的 .index

以前的行为Series),只保留左侧的 index

In [4]: s1 = pd.Series([True, False, True], index=list('ABC'))
In [5]: s2 = pd.Series([True, True, True], index=list('ABD'))
In [6]: s1 & s2
Out[6]:
A     True
B    False
C    False
dtype: bool

新的行为Series

In [83]: s1 = pd.Series([True, False, True], index=list("ABC"))

In [84]: s2 = pd.Series([True, True, True], index=list("ABD"))

In [85]: s1 & s2
Out[85]: 
A     True
B    False
C    False
D    False
Length: 4, dtype: bool

注意

Series 逻辑运算符用 False 填充 NaN 结果。

注意

要实现与以前版本相同的行为(仅基于左侧索引比较值),可以使用 reindex_like

In [86]: s1 & s2.reindex_like(s1)
Out[86]: 
A     True
B    False
C    False
Length: 3, dtype: bool

目前的行为DataFrame,无变化)

In [87]: df1 = pd.DataFrame([True, False, True], index=list("ABC"))

In [88]: df2 = pd.DataFrame([True, True, True], index=list("ABD"))

In [89]: df1 & df2
Out[89]: 
       0
A   True
B  False
C  False
D  False

[4 rows x 1 columns]

灵活的比较方法#

Series 的灵活比较方法,如 eq, ne, le, lt, gegt,现在都会对齐两个 index。如果想要比较具有不同 index 的两个 Series,请使用这些运算符。

In [90]: s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])

In [91]: s2 = pd.Series([2, 2, 2], index=["b", "c", "d"])

In [92]: s1.eq(s2)
Out[92]: 
a    False
b     True
c    False
d    False
Length: 4, dtype: bool

In [93]: s1.ge(s2)
Out[93]: 
a    False
b     True
c     True
d    False
Length: 4, dtype: bool

以前,这与比较运算符的行为相同(见上文)。

Series 在赋值时的类型提升#

Series 在进行赋值时,如果赋值的值与当前 dtype 不兼容,现在会正确地提升 dtype (GH 13234)。

In [94]: s = pd.Series()

旧的行为:

In [2]: s["a"] = pd.Timestamp("2016-01-01")

In [3]: s["b"] = 3.0
TypeError: invalid type promotion

新的行为:

In [95]: s["a"] = pd.Timestamp("2016-01-01")

In [96]: s["b"] = 3.0

In [97]: s
Out[97]: 
a    2016-01-01 00:00:00
b                    3.0
Length: 2, dtype: object

In [98]: s.dtype
Out[98]: dtype('O')

.to_datetime() 函数的变更#

以前,如果 .to_datetime() 遇到混合的整数/浮点数和字符串,但没有日期时间,并且使用了 errors='coerce',它会将所有值转换为 NaT

旧的行为:

In [2]: pd.to_datetime([1, 'foo'], errors='coerce')
Out[2]: DatetimeIndex(['NaT', 'NaT'], dtype='datetime64[ns]', freq=None)

目前的行为:

现在,它将以默认单位 ns 转换整数/浮点数。

In [99]: pd.to_datetime([1, "foo"], errors="coerce")
Out[99]: DatetimeIndex(['1970-01-01 00:00:00.000000001', 'NaT'], dtype='datetime64[ns]', freq=None)

.to_datetime() 相关的 Bug 修复#

  • 修复了 pd.to_datetime() 在传递整数或浮点数且未指定 unit 但指定了 errors='coerce' 时的 bug (GH 13180)。

  • 修复了 pd.to_datetime() 在传递无效数据类型(如 bool)时的 bug;现在将尊重 errors 关键字参数 (GH 13176)。

  • 修复了 pd.to_datetime() 在处理 int8int16 dtypes 时可能溢出的 bug (GH 13451)。

  • 修复了 pd.to_datetime() 在使用 errors='ignore' 时,如果包含 NaN 且其他字符串无效,会抛出 AttributeError 的 bug (GH 12424)。

  • 修复了 pd.to_datetime() 在指定 unit 时未正确转换浮点数,导致日期时间被截断的 bug (GH 13834)。

合并变更#

合并现在将保留连接键的 dtype (GH 8596)。

In [100]: df1 = pd.DataFrame({"key": [1], "v1": [10]})

In [101]: df1
Out[101]: 
   key  v1
0    1  10

[1 rows x 2 columns]

In [102]: df2 = pd.DataFrame({"key": [1, 2], "v1": [20, 30]})

In [103]: df2
Out[103]: 
   key  v1
0    1  20
1    2  30

[2 rows x 2 columns]

旧的行为:

In [5]: pd.merge(df1, df2, how='outer')
Out[5]:
   key    v1
0  1.0  10.0
1  1.0  20.0
2  2.0  30.0

In [6]: pd.merge(df1, df2, how='outer').dtypes
Out[6]:
key    float64
v1     float64
dtype: object

新的行为:

我们现在可以保留连接键的 dtype。

In [104]: pd.merge(df1, df2, how="outer")
Out[104]: 
   key  v1
0    1  10
1    1  20
2    2  30

[3 rows x 2 columns]

In [105]: pd.merge(df1, df2, how="outer").dtypes
Out[105]: 
key    int64
v1     int64
Length: 2, dtype: object

当然,如果引入了缺失值,结果 dtype 将会被向上转型,这与以前的行为相同。

In [106]: pd.merge(df1, df2, how="outer", on="key")
Out[106]: 
   key  v1_x  v1_y
0    1  10.0    20
1    2   NaN    30

[2 rows x 3 columns]

In [107]: pd.merge(df1, df2, how="outer", on="key").dtypes
Out[107]: 
key       int64
v1_x    float64
v1_y      int64
Length: 3, dtype: object

.describe() 方法的变更#

.describe() 输出索引中的百分位数标识符现在将四舍五入到能保持它们区别开的最低精度 (GH 13104)。

In [108]: s = pd.Series([0, 1, 2, 3, 4])

In [109]: df = pd.DataFrame([0, 1, 2, 3, 4])

旧的行为:

以前,百分位数最多四舍五入到小数点后一位,如果百分位数重复,可能会导致 DataFrame 抛出 ValueError

In [3]: s.describe(percentiles=[0.0001, 0.0005, 0.001, 0.999, 0.9995, 0.9999])
Out[3]:
count     5.000000
mean      2.000000
std       1.581139
min       0.000000
0.0%      0.000400
0.1%      0.002000
0.1%      0.004000
50%       2.000000
99.9%     3.996000
100.0%    3.998000
100.0%    3.999600
max       4.000000
dtype: float64

In [4]: df.describe(percentiles=[0.0001, 0.0005, 0.001, 0.999, 0.9995, 0.9999])
Out[4]:
...
ValueError: cannot reindex from a duplicate axis

新的行为:

In [110]: s.describe(percentiles=[0.0001, 0.0005, 0.001, 0.999, 0.9995, 0.9999])
Out[110]: 
count     5.000000
mean      2.000000
std       1.581139
min       0.000000
0.01%     0.000400
0.05%     0.002000
0.1%      0.004000
50%       2.000000
99.9%     3.996000
99.95%    3.998000
99.99%    3.999600
max       4.000000
Length: 12, dtype: float64

In [111]: df.describe(percentiles=[0.0001, 0.0005, 0.001, 0.999, 0.9995, 0.9999])
Out[111]: 
               0
count   5.000000
mean    2.000000
std     1.581139
min     0.000000
0.01%   0.000400
0.05%   0.002000
0.1%    0.004000
50%     2.000000
99.9%   3.996000
99.95%  3.998000
99.99%  3.999600
max     4.000000

[12 rows x 1 columns]

此外

  • 现在传递重复的 percentiles 将会抛出 ValueError

  • 修复了 .describe() 在具有混合 dtype 列索引的 DataFrame 上可能抛出 TypeError 的 bug (GH 13288)。

Period 变更#

PeriodIndex 现在具有 period dtype#

PeriodIndex 现在有了自己的 period dtype。period dtype 是 pandas 的扩展 dtype,类似于 category时区感知 dtypedatetime64[ns, tz]) (GH 13941)。这一变更的结果是,PeriodIndex 不再具有整数 dtype。

旧的行为:

In [1]: pi = pd.PeriodIndex(['2016-08-01'], freq='D')

In [2]: pi
Out[2]: PeriodIndex(['2016-08-01'], dtype='int64', freq='D')

In [3]: pd.api.types.is_integer_dtype(pi)
Out[3]: True

In [4]: pi.dtype
Out[4]: dtype('int64')

新的行为:

In [112]: pi = pd.PeriodIndex(["2016-08-01"], freq="D")

In [113]: pi
Out[113]: PeriodIndex(['2016-08-01'], dtype='period[D]')

In [114]: pd.api.types.is_integer_dtype(pi)
Out[114]: False

In [115]: pd.api.types.is_period_dtype(pi)
Out[115]: True

In [116]: pi.dtype
Out[116]: period[D]

In [117]: type(pi.dtype)
Out[117]: pandas.core.dtypes.dtypes.PeriodDtype

Period('NaT') 现在返回 pd.NaT#

以前,Period 有自己的 Period('NaT') 表示形式,不同于 pd.NaT。现在,Period('NaT') 已更改为返回 pd.NaT (GH 12759, GH 13582)。

旧的行为:

In [5]: pd.Period('NaT', freq='D')
Out[5]: Period('NaT', 'D')

新的行为:

在不提供 freq 选项的情况下,这些操作现在返回 pd.NaT

In [118]: pd.Period("NaT")
Out[118]: NaT

In [119]: pd.Period(None)
Out[119]: NaT

为了与 Period 的加减法兼容,pd.NaT 现在支持与 int 的加减法。以前会抛出 ValueError

旧的行为:

In [5]: pd.NaT + 1
...
ValueError: Cannot add integral value to Timestamp without freq.

新的行为:

In [120]: pd.NaT + 1
Out[120]: NaT

In [121]: pd.NaT - 1
Out[121]: NaT

PeriodIndex.values 现在返回 Period 对象的数组#

.values 已更改为返回 Period 对象的数组,而不是整数数组 (GH 13988)。

旧的行为:

In [6]: pi = pd.PeriodIndex(['2011-01', '2011-02'], freq='M')
In [7]: pi.values
Out[7]: array([492, 493])

新的行为:

In [122]: pi = pd.PeriodIndex(["2011-01", "2011-02"], freq="M")

In [123]: pi.values
Out[123]: array([Period('2011-01', 'M'), Period('2011-02', 'M')], dtype=object)

Index 的 + / - 不再用于集合操作#

基本 Index 类型和 DatetimeIndex(非数字索引类型)的加减法以前执行集合操作(集合并集和差集)。此行为自 0.15.0 版本以来已被弃用(推荐使用特定的 .union().difference() 方法),现在已禁用。如果可能,+- 现在用于元素级操作,例如字符串连接或日期时间相减 (GH 8227, GH 14127)。

旧的行为

In [1]: pd.Index(['a', 'b']) + pd.Index(['a', 'c'])
FutureWarning: using '+' to provide set union with Indexes is deprecated, use '|' or .union()
Out[1]: Index(['a', 'b', 'c'], dtype='object')

新的行为: 相同的操作现在将执行元素级加法。

In [124]: pd.Index(["a", "b"]) + pd.Index(["a", "c"])
Out[124]: Index(['aa', 'bc'], dtype='object')

请注意,数字 Index 对象已经执行元素级操作。例如,两个整数 Index 相加的行为没有改变。现在基本 Index 与此行为保持一致。

In [125]: pd.Index([1, 2, 3]) + pd.Index([2, 3, 4])
Out[125]: Index([3, 5, 7], dtype='int64')

此外,由于此更改,现在可以减去两个 DatetimeIndex 对象,结果是一个 TimedeltaIndex。

旧的行为:

In [1]: (pd.DatetimeIndex(['2016-01-01', '2016-01-02'])
   ...:  - pd.DatetimeIndex(['2016-01-02', '2016-01-03']))
FutureWarning: using '-' to provide set differences with datetimelike Indexes is deprecated, use .difference()
Out[1]: DatetimeIndex(['2016-01-01'], dtype='datetime64[ns]', freq=None)

新的行为:

In [126]: (
   .....:     pd.DatetimeIndex(["2016-01-01", "2016-01-02"])
   .....:     - pd.DatetimeIndex(["2016-01-02", "2016-01-03"])
   .....: )
   .....: 
Out[126]: TimedeltaIndex(['-1 days', '-1 days'], dtype='timedelta64[ns]', freq=None)

Index.difference 和 .symmetric_difference 的变更#

Index.differenceIndex.symmetric_difference 现在将更一致地将 NaN 值视为其他任何值 (GH 13514)。

In [127]: idx1 = pd.Index([1, 2, 3, np.nan])

In [128]: idx2 = pd.Index([0, 1, np.nan])

旧的行为:

In [3]: idx1.difference(idx2)
Out[3]: Float64Index([nan, 2.0, 3.0], dtype='float64')

In [4]: idx1.symmetric_difference(idx2)
Out[4]: Float64Index([0.0, nan, 2.0, 3.0], dtype='float64')

新的行为:

In [129]: idx1.difference(idx2)
Out[129]: Index([2.0, 3.0], dtype='float64')

In [130]: idx1.symmetric_difference(idx2)
Out[130]: Index([0.0, 2.0, 3.0], dtype='float64')

Index.unique 始终返回 Index#

Index.unique() 现在将唯一值作为具有相应 dtypeIndex 返回 (GH 13395)。以前,大多数 Index 类返回 np.ndarray,而 DatetimeIndex, TimedeltaIndexPeriodIndex 返回 Index 以保留元数据(如时区)。

旧的行为:

In [1]: pd.Index([1, 2, 3]).unique()
Out[1]: array([1, 2, 3])

In [2]: pd.DatetimeIndex(['2011-01-01', '2011-01-02',
   ...:                   '2011-01-03'], tz='Asia/Tokyo').unique()
Out[2]:
DatetimeIndex(['2011-01-01 00:00:00+09:00', '2011-01-02 00:00:00+09:00',
               '2011-01-03 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Tokyo]', freq=None)

新的行为:

In [131]: pd.Index([1, 2, 3]).unique()
Out[131]: Index([1, 2, 3], dtype='int64')

In [132]: pd.DatetimeIndex(
   .....:     ["2011-01-01", "2011-01-02", "2011-01-03"], tz="Asia/Tokyo"
   .....: ).unique()
   .....: 
Out[132]: 
DatetimeIndex(['2011-01-01 00:00:00+09:00', '2011-01-02 00:00:00+09:00',
               '2011-01-03 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Tokyo]', freq=None)

MultiIndex 构造函数、groupby 和 set_index 保留 categorical dtypes#

MultiIndex.from_arraysMultiIndex.from_product 现在将在 MultiIndex 的 level 中保留 categorical dtype (GH 13743, GH 13854)。

In [133]: cat = pd.Categorical(["a", "b"], categories=list("bac"))

In [134]: lvl1 = ["foo", "bar"]

In [135]: midx = pd.MultiIndex.from_arrays([cat, lvl1])

In [136]: midx
Out[136]: 
MultiIndex([('a', 'foo'),
            ('b', 'bar')],
           )

旧的行为:

In [4]: midx.levels[0]
Out[4]: Index(['b', 'a', 'c'], dtype='object')

In [5]: midx.get_level_values[0]
Out[5]: Index(['a', 'b'], dtype='object')

新的行为: 单个 level 现在是一个 CategoricalIndex

In [137]: midx.levels[0]
Out[137]: CategoricalIndex(['b', 'a', 'c'], categories=['b', 'a', 'c'], ordered=False, dtype='category')

In [138]: midx.get_level_values(0)
Out[138]: CategoricalIndex(['a', 'b'], categories=['b', 'a', 'c'], ordered=False, dtype='category')

MultiIndex.from_product 也进行了类似的更改。因此,groupbyset_index 在索引中也保留了 categorical dtypes。

In [139]: df = pd.DataFrame({"A": [0, 1], "B": [10, 11], "C": cat})

In [140]: df_grouped = df.groupby(by=["A", "C"], observed=False).first()

In [141]: df_set_idx = df.set_index(["A", "C"])

旧的行为:

In [11]: df_grouped.index.levels[1]
Out[11]: Index(['b', 'a', 'c'], dtype='object', name='C')
In [12]: df_grouped.reset_index().dtypes
Out[12]:
A      int64
C     object
B    float64
dtype: object

In [13]: df_set_idx.index.levels[1]
Out[13]: Index(['b', 'a', 'c'], dtype='object', name='C')
In [14]: df_set_idx.reset_index().dtypes
Out[14]:
A      int64
C     object
B      int64
dtype: object

新的行为:

In [142]: df_grouped.index.levels[1]
Out[142]: CategoricalIndex(['b', 'a', 'c'], categories=['b', 'a', 'c'], ordered=False, dtype='category', name='C')

In [143]: df_grouped.reset_index().dtypes
Out[143]: 
A       int64
C    category
B     float64
Length: 3, dtype: object

In [144]: df_set_idx.index.levels[1]
Out[144]: CategoricalIndex(['b', 'a', 'c'], categories=['b', 'a', 'c'], ordered=False, dtype='category', name='C')

In [145]: df_set_idx.reset_index().dtypes
Out[145]: 
A       int64
C    category
B       int64
Length: 3, dtype: object

read_csv 函数将逐步枚举块#

当调用 read_csv() 并指定 chunksize=n 且未指定索引时,以前每个块都会生成独立的从 0n-1 的索引。现在,它们改为生成递进的索引,第一个块从 0 开始,第二个块从 n 开始,依此类推,以便连接后与不带 chunksize= 参数调用 read_csv() 的结果相同 (GH 12185)。

In [146]: data = "A,B\n0,1\n2,3\n4,5\n6,7"

旧的行为:

In [2]: pd.concat(pd.read_csv(StringIO(data), chunksize=2))
Out[2]:
   A  B
0  0  1
1  2  3
0  4  5
1  6  7

新的行为:

In [147]: pd.concat(pd.read_csv(StringIO(data), chunksize=2))
Out[147]: 
   A  B
0  0  1
1  2  3
2  4  5
3  6  7

[4 rows x 2 columns]

Sparse 变更#

这些变更使得 pandas 可以处理具有更多 dtypes 的 sparse 数据,并使其数据处理体验更顺畅。

int64 和 bool 类型的支持增强#

Sparse 数据结构现在增强了对 int64bool dtype 的支持 (GH 667, GH 13849)。

以前,sparse 数据默认为 float64 dtype,即使所有输入都是 intbool dtype。必须显式指定 dtype 才能创建 int64 dtype 的 sparse 数据。此外,必须显式指定 fill_value,因为默认值是 np.nan,它不会出现在 int64bool 数据中。

In [1]: pd.SparseArray([1, 2, 0, 0])
Out[1]:
[1.0, 2.0, 0.0, 0.0]
Fill: nan
IntIndex
Indices: array([0, 1, 2, 3], dtype=int32)

# specifying int64 dtype, but all values are stored in sp_values because
# fill_value default is np.nan
In [2]: pd.SparseArray([1, 2, 0, 0], dtype=np.int64)
Out[2]:
[1, 2, 0, 0]
Fill: nan
IntIndex
Indices: array([0, 1, 2, 3], dtype=int32)

In [3]: pd.SparseArray([1, 2, 0, 0], dtype=np.int64, fill_value=0)
Out[3]:
[1, 2, 0, 0]
Fill: 0
IntIndex
Indices: array([0, 1], dtype=int32)

从 v0.19.0 版本开始,sparse 数据保留输入的 dtype,并使用更合适的 fill_value 默认值(int64 dtype 为 0bool dtype 为 False)。

In [148]: pd.arrays.SparseArray([1, 2, 0, 0], dtype=np.int64)
Out[148]: 
[1, 2, 0, 0]
Fill: 0
IntIndex
Indices: array([0, 1], dtype=int32)

In [149]: pd.arrays.SparseArray([True, False, False, False])
Out[149]: 
[True, False, False, False]
Fill: False
IntIndex
Indices: array([0], dtype=int32)

更多详情请参阅文档

运算符现在保留 dtypes#

  • Sparse 数据结构现在可以在算术运算后保留 dtype (GH 13848)。

s = pd.SparseSeries([0, 2, 0, 1], fill_value=0, dtype=np.int64)
s.dtype

s + 1
  • Sparse 数据结构现在支持 astype 来转换内部 dtype (GH 13900)。

s = pd.SparseSeries([1.0, 0.0, 2.0, 0.0], fill_value=0)
s
s.astype(np.int64)

如果数据包含无法转换为指定 dtype 的值,astype 会失败。请注意,此限制也适用于默认值为 np.nanfill_value

In [7]: pd.SparseSeries([1., np.nan, 2., np.nan], fill_value=np.nan).astype(np.int64)
Out[7]:
ValueError: unable to coerce current fill_value nan to int64 dtype

其他 sparse 修复#

  • 子类化的 SparseDataFrameSparseSeries 现在在切片或转置时保留类类型 (GH 13787)。

  • 具有 bool dtype 的 SparseArray 现在支持逻辑(bool)运算符 (GH 14000)。

  • 修复了具有 MultiIndexSparseSeries 在使用 [] 索引时可能抛出 IndexError 的 bug (GH 13144)。

  • 修复了具有 MultiIndexSparseSeries 在使用 [] 索引时结果可能具有普通 Index 的 bug (GH 13144)。

  • 修复了 SparseDataFrameaxis=None 没有默认设置为 axis=0 的 bug (GH 13048)。

  • 修复了使用 object dtype 创建 SparseSeriesSparseDataFrame 时可能抛出 TypeError 的 bug (GH 11633)。

  • 修复了 SparseDataFrame 不尊重传入的 SparseArraySparseSeriesdtypefill_value 的 bug (GH 13866)。

  • 修复了 SparseArraySparseSeries 不将 ufunc 应用于 fill_value 的 bug (GH 13853)。

  • 修复了 SparseSeries.abs 错误地保留负 fill_value 的 bug (GH 13853)。

  • 修复了对多类型 SparseDataFrame 进行单行切片时,以前类型被强制转换为 float 的 bug (GH 13917)。

  • 修复了 SparseSeries 切片将整数 dtype 更改为 float 的 bug (GH 8292)。

  • 修复了 SparseDataFrame 比较操作可能抛出 TypeError 的 bug (GH 13001)。

  • 修复了 SparseDataFrame.isnull 抛出 ValueError 的 bug (GH 8276)。

  • 修复了具有 bool dtype 的 SparseSeries 在表示时可能抛出 IndexError 的 bug (GH 13110)。

  • SparseSeriesSparseDataFrameboolint64 dtype 的错误可能导致其值显示为 float64 dtype 的形式 (GH 13110)

  • 使用 SparseArraybool dtype 进行稀疏索引时,错误可能返回不正确的结果 (GH 13985)

  • SparseSeries 创建的 SparseArray 中,错误可能导致其丢失 dtype (GH 13999)

  • SparseSeries 与密集 Series 进行比较时,错误会返回正常的 Series 而不是 SparseSeries (GH 13999)

Indexer dtype 变化#

注意

此变化仅影响在 Windows 上运行的 64 位 Python,并且仅影响相对高级的索引操作

返回索引器数组的方法(如 Index.get_indexer)会将该数组强制转换为“平台整数”,以便可以直接用于第三方库操作,例如 numpy.take。以前,平台整数定义为 np.int_,它对应于 C 整数;但正确的类型,也是现在使用的类型是 np.intp,它对应于可以容纳指针的 C 整数大小 (GH 3033, GH 13972)。

这些类型在许多平台上是相同的,但在 Windows 上的 64 位 Python 中,np.int_ 是 32 位,而 np.intp 是 64 位。此行为的改变提高了在该平台上的许多操作的性能。

旧的行为:

In [1]: i = pd.Index(['a', 'b', 'c'])

In [2]: i.get_indexer(['b', 'b', 'c']).dtype
Out[2]: dtype('int32')

新的行为:

In [1]: i = pd.Index(['a', 'b', 'c'])

In [2]: i.get_indexer(['b', 'b', 'c']).dtype
Out[2]: dtype('int64')

其他 API 变化#

  • warn=True 且实例具有非零纳秒数时,Timestamp.to_pydatetime 将发出 UserWarning,此前这会将消息打印到 stdout (GH 14101)。

  • 带有日期时间和时区的 Series.unique() 现在返回带有时区的 Timestamp 数组 (GH 13565)。

  • 调用 Panel.to_sparse() 将引发 NotImplementedError 异常 (GH 13778)。

  • 调用 Index.reshape() 将引发 NotImplementedError 异常 (GH 12882)。

  • .filter() 强制关键字参数互斥 (GH 12399)。

  • evalfloat32 类型的向上转型规则已更新,使其与 NumPy 的规则更加一致。新行为在将 pandas float32 对象乘以标量 float64 时不会向上转型为 float64 (GH 12388)。

  • 如果在 groupby 或 resample 对象上调用 NumPy ufuncs(如 np.mean),现在将引发 UnsupportedFunctionCall 错误 (GH 12811)。

  • __setitem__ 不再将可调用的 rhs 应用为函数,而是直接存储它。直接调用 where 以获得之前的行为 (GH 13299)。

  • 调用 .sample() 将遵循通过 numpy.random.seed(n) 设置的随机种子 (GH 13161)

  • Styler.apply 现在对您的函数必须返回的输出要求更严格。对于 axis=0axis=1,输出形状必须相同。对于 axis=None,输出必须是一个 DataFrame,其列和索引标签必须相同 (GH 13222)。

  • 如果 Float64Index 包含 NaN 值,Float64Index.astype(int) 现在将引发 ValueError (GH 13149)

  • TimedeltaIndex.astype(int)DatetimeIndex.astype(int) 现在将返回 Int64Index 而不是 np.array (GH 13209)

  • 将具有多种频率的 Period 传递给普通 Index 现在返回带有 object dtype 的 Index (GH 13664)

  • 带有不同频率的 PeriodPeriodIndex.fillna 现在强制转换为 object dtype (GH 13664)

  • 来自 DataFrame.boxplot(by=col) 的分面箱线图在 return_type 不为 None 时现在返回一个 Series。此前它们返回一个 OrderedDict。请注意,当 return_type=None(默认值)时,它们仍然返回一个二维 NumPy 数组 (GH 12216, GH 7096)。

  • 如果提供的模式不是 rr+apd.read_hdf 现在将引发 ValueError 而不是 KeyError。 (GH 13623)

  • pd.read_csv()pd.read_table()pd.read_hdf() 在 Python 3.x 中处理不存在的文件时,将引发内置的 FileNotFoundError 异常;在 Python 2.x 中则向后移植为 IOError (GH 14086)

  • csv 解析器现在会传递更具信息性的异常。异常类型现在是原始异常类型,而不是 CParserError (GH 13652)。

  • C 引擎中的 pd.read_csv() 现在会在编码的 sep 长度超过一个字符时发出 ParserWarning 或引发 ValueError (GH 14065)

  • DataFrame 包含混合的 int64uint64 dtypes 时,DataFrame.values 现在将返回 float64,这符合 np.find_common_type 的规则 (GH 10364, GH 13917)

  • .groupby.groups 现在将返回一个由 Index 对象组成的字典,而不是由 np.ndarraylists 组成的字典 (GH 14293)

弃用#

  • Series.reshapeCategorical.reshape 已被弃用,并将在后续版本中移除 (GH 12882, GH 12882)

  • PeriodIndex.to_datetime 已被弃用,建议使用 PeriodIndex.to_timestamp (GH 8254)

  • Timestamp.to_datetime 已被弃用,建议使用 Timestamp.to_pydatetime (GH 8254)

  • Index.to_datetimeDatetimeIndex.to_datetime 已被弃用,建议使用 pd.to_datetime (GH 8254)

  • pandas.core.datetools 模块已弃用,并将在后续版本中移除 (GH 14094)

  • SparseList 已被弃用,并将在未来版本中移除 (GH 13784)

  • DataFrame.to_html()DataFrame.to_latex() 已弃用 colSpace 参数,建议使用 col_space (GH 13857)

  • DataFrame.to_sql() 已弃用 flavor 参数,因为在未安装 SQLAlchemy 时该参数是多余的 (GH 13611)

  • 弃用的 read_csv 关键字

    • compact_intsuse_unsigned 已被弃用,并将在未来版本中移除 (GH 13320)

    • buffer_lines 已被弃用,并将在未来版本中移除 (GH 13360)

    • as_recarray 已被弃用,并将在未来版本中移除 (GH 13373)

    • skip_footer 已被弃用,建议使用 skipfooter,并将在未来版本中移除 (GH 13349)

  • 顶层函数 pd.ordered_merge() 已重命名为 pd.merge_ordered(),原名称将在未来版本中移除 (GH 13358)

  • Timestamp.offset 属性(以及构造函数中的命名参数)已弃用,建议使用 freq (GH 12160)

  • pd.tseries.util.pivot_annual 已弃用。建议使用 pivot_table 作为替代,示例请参见 此处 (GH 736)

  • pd.tseries.util.isleapyear 已弃用,并将在后续版本中移除。类似 datetime 的对象现在具有 .is_leap_year 属性 (GH 13727)

  • Panel4DPanelND 构造函数已弃用,并将在未来版本中移除。建议使用 xarray 包来表示这些类型的 n 维数据。pandas 提供了 to_xarray() 方法来自动化此转换 (GH 13564)。

  • pandas.tseries.frequencies.get_standard_freq 已弃用。请使用 pandas.tseries.frequencies.to_offset(freq).rule_code 替代 (GH 13874)

  • pandas.tseries.frequencies.to_offsetfreqstr 关键字已弃用,建议使用 freq (GH 13874)

  • Categorical.from_array 已弃用,并将在未来版本中移除 (GH 13854)

移除先前版本弃用/变化#

  • SparsePanel 类已被移除 (GH 13778)

  • pd.sandbox 模块已被移除,建议使用外部库 pandas-qt (GH 13670)

  • pandas.io.datapandas.io.wb 模块已被移除,建议使用 pandas-datareader 包 (GH 13724)。

  • pandas.tools.rplot 模块已被移除,建议使用 seaborn 包 (GH 13855)

  • DataFrame.to_csv() 已弃用 engine 参数,该参数已在 0.17.1 版本中弃用 (GH 11274, GH 13419)

  • DataFrame.to_dict() 已弃用 outtype 参数,建议使用 orient (GH 13627, GH 8486)

  • pd.Categorical 已弃用直接设置 ordered 属性,建议使用 set_ordered 方法 (GH 13671)

  • pd.Categorical 已弃用 levels 属性,建议使用 categories (GH 8376)

  • DataFrame.to_sql() 已弃用 flavor 参数的 mysql 选项 (GH 13611)

  • Panel.shift() 已弃用 lags 参数,建议使用 periods (GH 14041)

  • pd.Index 已弃用 diff 方法,建议使用 difference (GH 13669)

  • pd.DataFrame 已弃用 to_wide 方法,建议使用 to_panel (GH 14039)

  • Series.to_csv 已弃用 nanRep 参数,建议使用 na_rep (GH 13804)

  • Series.xsDataFrame.xsPanel.xsPanel.major_xsPanel.minor_xs 已弃用 copy 参数 (GH 13781)

  • str.split 已弃用 return_type 参数,建议使用 expand (GH 13701)

  • 移除旧版时间规则(偏移别名),该规则自 0.17.0 版本起已弃用(自 0.8.0 版本起已是别名)(GH 13590, GH 13868)。现在旧版时间规则会引发 ValueError。有关当前支持的偏移量列表,请参见 此处

  • DataFrame.plot.boxDataFrame.boxplotreturn_type 参数的默认值从 None 更改为 "axes"。这些方法现在默认返回一个 matplotlib 轴对象,而不是艺术家字典。请参见 此处 (GH 6581)。

  • pandas.io.sql 模块中的 tqueryuquery 函数已被移除 (GH 5950)。

性能改进#

  • 改进了稀疏 IntIndex.intersect 的性能 (GH 13082)

  • 改进了块数量较大时使用 BlockIndex 进行稀疏算术运算的性能,尽管在此类情况下建议使用 IntIndex (GH 13082)

  • 改进了 DataFrame.quantile() 的性能,因为它现在按块操作 (GH 11623)

  • 改进了 float64 哈希表操作的性能,修复了 Python 3 中一些非常慢的索引和 groupby 操作 (GH 13166, GH 13334)

  • 改进了 DataFrameGroupBy.transform 的性能 (GH 12737)

  • 改进了 IndexSeries.duplicated 性能 (GH 10235)

  • 改进了 Index.difference 的性能 (GH 12044)

  • 改进了 RangeIndex.is_monotonic_increasingis_monotonic_decreasing 的性能 (GH 13749)

  • 改进了 DatetimeIndex 中 datetime 字符串解析的性能 (GH 13692)

  • 改进了 Period 哈希计算的性能 (GH 12817)

  • 改进了带时区的 datetime factorize 的性能 (GH 13750)

  • 通过在较大的 Index 上惰性创建索引哈希表,改进了性能 (GH 14266)

  • 改进了 groupby.groups 的性能 (GH 14293)

  • 内省内存使用情况时,不再不必要地物化 MultiIndex (GH 14308)

错误修复#

  • groupby().shift() 中的错误,在极少数情况下按包含缺失值的列分组时,可能导致段错误或数据损坏 (GH 13813)

  • axis=1 时,groupby().cumsum() 计算 cumprod 的错误。 (GH 13994)

  • pd.to_timedelta() 中的错误,其中 errors 参数未被遵守 (GH 13613)

  • io.json.json_normalize() 中的错误,其中非 ASCII 键会引发异常 (GH 13213)

  • .plot() 中将非默认索引的 Series 作为 xerryerr 传递时的错误 (GH 11858)

  • 面积图中的错误,如果启用子图或在绘图后移动图例,则图例绘制不正确(需要 matplotlib 1.5.0 才能正确绘制面积图图例)(GH 9161, GH 13544)

  • 使用 object-dtyped Index 进行 DataFrame 赋值时的错误,其中结果列相对于原始对象是可变的。(GH 13522)

  • matplotlib AutoDataFormatter 中的错误;这恢复了第二级缩放格式并重新添加了微秒级缩放格式 (GH 13131)

  • 从固定格式的 HDFStore 中进行选择并指定了 start 和/或 stop 时,错误现在将返回所选范围 (GH 8287)

  • Categorical.from_codes() 中的错误,当传入无效的 ordered 参数时会引发无意义的错误 (GH 14058)

  • 在 Windows 上从整数元组构造 Series 时,未返回默认 dtype (int64) 的错误 (GH 13646)

  • TimedeltaIndex 与类似 datetime 的对象相加时,未捕获加法溢出的错误 (GH 14068)

  • 多次调用同一对象时,.groupby(..).resample(..) 中的错误 (GH 13174)

  • 当索引名称为 unicode 字符串时,调用 .to_records() 中的错误 (GH 13172)

  • 在未实现 .memory_usage() 的对象上调用该方法时的错误 (GH 12924)

  • 带有 nans 的 Series.quantile 中的回归错误(也出现在 .median().describe() 中);此外,现在使用分位数命名 Series (GH 13098, GH 13146)

  • 带有 datetime 值和缺失组的 SeriesGroupBy.transform 中的错误 (GH 13191)

  • Series 在类似 datetime 的数值运算中被错误强制转换的错误 (GH 13844)

  • 当传入包含带时区 datetime 的 Categorical 时,Categorical 构造函数中的错误 (GH 14190)

  • 带有 str 索引的 Series.str.extractall() 中的错误,会引发 ValueError (GH 13156)

  • 带有单个组和量词的 Series.str.extractall() 中的错误 (GH 13382)

  • DatetimeIndexPeriod 相减时,错误会引发 ValueErrorAttributeError,而不是 TypeError (GH 13078)

  • 使用 NaNNaT 混合数据创建的 IndexSeries 可能没有 datetime64 dtype 的错误 (GH 13324)

  • IndexSeries 可能忽略 np.datetime64('nat')np.timdelta64('nat') 来推断 dtype 的错误 (GH 13324)

  • PeriodIndexPeriod 相减时,错误会引发 AttributeError (GH 13071)

  • PeriodIndex 构造在某些情况下返回 float64 索引的错误 (GH 13067)

  • 当空时,带 PeriodIndex.resample(..) 未正确更改其 freq 的错误 (GH 13067)

  • 当空 DataFrame 时,.resample(..)PeriodIndex 的错误,无法正确保留其类型或名称 (GH 13212)

  • 当传递的函数为每组返回标量值时,groupby(..).apply(..) 中的错误 (GH 13468)。

  • groupby(..).resample(..) 中的错误,传递某些关键字时会引发异常 (GH 13235)

  • 在时区感知的 DateTimeIndex 上使用 .tz_convert 时发生的错误,该方法依赖索引排序才能得到正确结果 (GH 13306)

  • 在使用 dateutil.tz.tzlocal 时,.tz_localize 中的错误,可能返回不正确的结果 (GH 13583)

  • 在使用 dateutil.tz.tzlocal 时,DatetimeTZDtype 类型中的错误,无法视为有效的 dtype (GH 13583)

  • pd.read_hdf() 中的错误,当尝试加载一个包含单个 dataset 且带有一个或多个 categorical 列的 HDF 文件时,除非将 key 参数设置为 dataset 的名称,否则会失败。(GH 13231)

  • .rolling() 中的错误,允许在构建 Rolling() 对象时使用负整数窗口,但在后续聚合时会失败 (GH 13383)

  • 使用元组值数据和数字索引对 Series 进行索引时的错误 (GH 13509)

  • 打印 pd.DataFrame 时的错误,其中具有 object 类型的不寻常元素导致了段错误 (GH 13717)

  • Series 进行排序(ranking)时的错误,可能导致段错误 (GH 13445)

  • 各种索引类型中的错误,未传播传递的索引的名称 (GH 12309)

  • DatetimeIndex 中的错误,未遵守 copy=True 参数的设置 (GH 13205)

  • 在本地时区情况下,DatetimeIndex.is_normalized 在标准化 date_range 时返回不正确的结果 (GH 13459)

  • pd.concat.append 中的错误,可能将 datetime64timedelta 强制转换为包含 Python 内置 datetimetimedeltaobject 类型,而不是 TimestampTimedelta (GH 13626)

  • PeriodIndex.append 中的错误,当结果为 object 类型时,可能引发 AttributeError (GH 13221)

  • CategoricalIndex.append 中的错误,可能接受普通的 list (GH 13626)

  • pd.concat.append 中的错误,具有相同时区的数据被重置为 UTC (GH 7795)

  • SeriesDataFrame.append 中的错误,如果数据包含夏令时边界附近的 datetime,则引发 AmbiguousTimeError (GH 13626)

  • DataFrame.to_csv() 中的错误,即使仅为非数字值指定了引用,浮点值也被引用 (GH 12922, GH 13259)

  • 仅包含布尔列时,DataFrame.describe() 引发 ValueError 的错误 (GH 13898)

  • MultiIndex 切片中的错误,当 level 非唯一时,返回了额外元素 (GH 12896)

  • .str.replace 中的错误,对于无效替换未引发 TypeError (GH 13438)

  • MultiIndex.from_arrays 中的错误,未检查输入数组长度是否匹配 (GH 13599)

  • cartesian_productMultiIndex.from_product 中的错误,当输入数组为空时可能引发异常 (GH 12258)

  • pd.read_csv() 中的错误,在极少数情况下,当分块迭代流/文件时,可能导致段错误或数据损坏 (GH 13703)

  • pd.read_csv() 中的错误,当为 na_values 传递包含标量的字典时,导致引发错误 (GH 12224)

  • pd.read_csv() 中的错误,由于未忽略 BOM,导致 BOM 文件被错误解析 (GH 4793)

  • 使用 engine='python' 时,pd.read_csv() 中的错误,当为 usecols 传递 numpy 数组时引发错误 (GH 12546)

  • pd.read_csv() 中的错误,当索引列作为日期解析并带有 thousands 参数时,被错误解析 (GH 14066)

  • 使用 engine='python' 时,pd.read_csv() 中的错误,数据转换为数字值后,未检测到 NaN 值 (GH 13314)

  • pd.read_csv() 中的错误,其中 nrows 参数未针对两种引擎进行适当验证 (GH 10476)

  • 使用 engine='python' 时,pd.read_csv() 中的错误,其中大小写混排形式的无穷值未被正确解释 (GH 13274)

  • 使用 engine='python' 时,pd.read_csv() 中的错误,其中尾随的 NaN 值未被解析 (GH 13320)

  • 在 Windows Python 3 上从 tempfile.TemporaryFile 读取时,使用 engine='python'pd.read_csv() 中的错误 (GH 13398)

  • pd.read_csv() 中的错误,阻止 usecols kwarg 接受单字节 unicode 字符串 (GH 13219)

  • pd.read_csv() 中的错误,阻止 usecols 成为一个空集合 (GH 13402)

  • 在使用 C 引擎时,pd.read_csv() 中的错误,其中 NULL 字符未被解析为 NULL (GH 14012)

  • 使用 engine='c' 时,pd.read_csv() 中的错误,即使指定了 quotingNone,也未接受 NULL quotechar (GH 13411)

  • 使用 engine='c' 时,pd.read_csv() 中的错误,当指定 quoting 为非数字时,字段未被正确地转换为浮点数 (GH 13411)

  • 在 Python 2.x 中,处理非 UTF-8 编码的多字符分隔数据时,pd.read_csv() 中的错误 (GH 3404)

  • pd.read_csv() 中的错误,其中 utf-xx 的别名(例如 UTF-xx, UTF_xx, utf_xx)引发了 UnicodeDecodeError (GH 13549)

  • pd.read_csv, pd.read_table, pd.read_fwf, pd.read_statapd.read_sas 中的错误,当 chunksizeiterator 都为 None 时,文件被解析器打开但未关闭。(GH 13940)

  • StataReader, StataWriter, XportReaderSAS7BDATReader 中的错误,当引发错误时,文件未被正确关闭。(GH 13940)

  • pd.pivot_table() 中的错误,当 aggfunc 是一个列表时,margins_name 被忽略 (GH 13354)

  • 在传递非整数时,pd.Series.str.zfill, center, ljust, rjust, 和 pad 中的错误,未引发 TypeError (GH 13598)

  • 检查 TimedeltaIndex 中是否存在任何空对象时的错误,该检查总是返回 True (GH 13603)

  • 如果包含具有 object 类型的日期时间类对象,则 Series 算术中的错误会引发 TypeError (GH 13043)

  • Series.isnull()Series.notnull() 中的错误,忽略 Period('NaT') (GH 13737)

  • Series.fillna()Series.dropna() 中的错误,不影响 Period('NaT') (GH 13737

  • category 类型的 Series 上,.fillna(value=np.nan) 错误地引发了 KeyError (GH 14021)

  • 扩展 dtype 创建中的错误,其中创建的类型不相同/一致 (GH 13285)

  • .resample(..) 中的错误,其中 IPython 自省触发了不正确的警告 (GH 13618)

  • NaT - Period 中的错误,会引发 AttributeError (GH 13071)

  • Series 比较中的错误,如果右侧(rhs)包含 NaT,可能输出不正确的结果 (GH 9005)

  • SeriesIndex 比较中的错误,如果它包含具有 object 类型的 NaT,可能输出不正确的结果 (GH 13592)

  • Period 加法中的错误,如果 Period 在右侧,则引发 TypeError (GH 13069)

  • PeriodSeriesIndex 比较中的错误,引发 TypeError (GH 13200)

  • pd.set_eng_float_format() 中的错误,会阻止 NaNInf 进行格式化 (GH 11981)

  • 使用 Categorical 类型时,.unstack 中的错误,将 .ordered 重置为 True (GH 13249)

  • 清理日期时间解析中的一些编译时警告 (GH 13607)

  • factorize 中的错误,如果数据包含夏令时边界附近的 datetime,则引发 AmbiguousTimeError (GH 13750)

  • .set_index 中的错误,如果新索引包含夏令时边界和多层级,则引发 AmbiguousTimeError (GH 12920)

  • .shift 中的错误,如果数据包含夏令时边界附近的 datetime,则引发 AmbiguousTimeError (GH 13926)

  • pd.read_hdf() 中的错误,当 DataFrame 包含 categorical 列且 query 不匹配任何值时,返回不正确的结果 (GH 13792)

  • 使用非字典顺序排序的 MultiIndex 进行索引时,.iloc 中的错误 (GH 13797)

  • 在反向排序的 DatetimeIndex 中使用日期字符串进行索引时,.loc 中的错误 (GH 14316)

  • 处理零维 NumPy 数组时,Series 比较运算符中的错误 (GH 13006)

  • .combine_first 中的错误,可能返回不正确的 dtype (GH 7630, GH 10567)

  • groupby 中的错误,其中 apply 返回的结果取决于第一个结果是否为 None (GH 12824)

  • groupby(..).nth() 中的错误,如果在调用 .head()/.tail() 后调用,组键(group key)会被不一致地包含 (GH 12839)

  • .to_html, .to_latex.to_string 中的错误,静默忽略通过 formatters 关键字传递的自定义日期时间格式化器 (GH 10690)

  • DataFrame.iterrows() 中的错误,如果定义了 Series 子类,则不产生该子类实例 (GH 13977)

  • errors='coerce' 且 input 包含不可哈希对象时,pd.to_numeric 中的错误 (GH 13324)

  • 无效的 Timedelta 算术和比较中的错误,可能引发 ValueError 而不是 TypeError (GH 13624)

  • to_datetimeDatetimeIndex 中的无效日期时间解析错误,可能引发 TypeError 而不是 ValueError (GH 11169, GH 11287)

  • 使用时区感知的 Timestamp 和不匹配的 tz 选项创建 Index 时的错误,错误地强制转换了时区 (GH 13692)

  • 具有纳秒频率的 DatetimeIndex 中的错误,不包含使用 end 指定的时间戳 (GH 13672)

  • 使用 np.timedelta64 设置切片时,Series 中的错误 (GH 14155)

  • Index 中的错误,如果 datetime 超过 datetime64[ns] 边界,则引发 OutOfBoundsDatetime,而不是强制转换为 object 类型 (GH 13663)

  • Index 中的错误,可能忽略作为 dtype 传递的指定 datetime64timedelta64 (GH 13981)

  • RangeIndex 中的错误,可以在没有参数的情况下创建,而不是引发 TypeError (GH 13793)

  • .value_counts() 中的错误,如果数据超过 datetime64[ns] 边界,则引发 OutOfBoundsDatetime (GH 13663)

  • DatetimeIndex 中的错误,如果输入的 np.datetime64 单位不是 ns,则可能引发 OutOfBoundsDatetime (GH 9114)

  • 使用单位不是 nsnp.datetime64 作为 object 类型创建 Series 时的错误,导致值不正确 (GH 13876)

  • 使用 timedelta 数据进行 resample 时的错误,其中数据被转换为浮点数 (GH 13119)。

  • pd.isnull() pd.notnull() 中的错误,如果输入日期时间类对象的单位不是 ns,则引发 TypeError (GH 13389)

  • pd.merge() 中的错误,如果输入日期时间类对象的单位不是 ns,则可能引发 TypeError (GH 13389)

  • HDFStore / read_hdf() 中的错误,如果设置了 tz,则丢弃了 DatetimeIndex.name (GH 13884)

  • Categorical.remove_unused_categories() 中的错误,将 .codes dtype 更改为平台 int (GH 13261)

  • 使用 as_index=Falsegroupby 中的错误,当按包含 categorical 列的多个列进行分组时,返回所有 NaN 值 (GH 13204)

  • df.groupby(...)[...] 中的 bug,当使用 Int64Index 进行 getitem 操作时会引发错误 (GH 13731)

  • 在分配给 DataFrame.style 的 CSS 类中,针对索引名称的 bug。之前它们被分配 "col_heading level<n> col<c>",其中 n 是级别数 + 1。现在它们被分配 "index_name level<n>",其中 n 是该 MultiIndex 的正确级别。

  • pd.read_gbq() 中可能引发 ImportError: No module named discovery 的 bug,这是由于与另一个名为 apiclient 的 python 包存在命名冲突 (GH 13454)

  • Index.union 中,在使用带名称的空索引时返回不正确结果的 bug (GH 13432)

  • 在 Python3 中使用混合整数索引时,Index.differenceDataFrame.join 引发错误的 bug (GH 13432, GH 12814)

  • 从时区感知的 datetime64 Series 中减去时区感知的 datetime.datetime 时出现的 bug (GH 14088)

  • .to_excel() 中的 bug,当 DataFrame 包含带有 NaN 值的标签的 MultiIndex 时出现 (GH 13511)

  • 无效的频率偏移字符串(如“D1”、“-2-3H”)可能不会引发 ValueError 的 bug (GH 13930)

  • 使用 RangeIndex 级别对分层框架进行 concatgroupby 时出现的 bug (GH 13542)。

  • Series.str.contains() 中的 bug,针对仅包含 object dtype 的 NaN 值的 Series (GH 14171)

  • groupby dataframe 上的 agg() 函数中的 bug,将 datetime64[ns] 列的 dtype 更改为 float64 (GH 12821)

  • 使用 NumPy ufunc 对 PeriodIndex 进行整数加减操作时引发 IncompatibleFrequency 的 bug。注意,建议使用标准运算符如 +-,因为标准运算符使用更高效的路径 (GH 13980)

  • NaT 进行操作时返回 float 而不是 datetime64[ns] 的 bug (GH 12941)

  • Series 灵活算术方法(如 .add())中的 bug,当 axis=None 时引发 ValueError (GH 13894)

  • DataFrame.to_csv() 中,当使用 MultiIndex 列时添加了一个多余空行的 bug (GH 6618)

  • DatetimeIndex, TimedeltaIndexPeriodIndex.equals() 中的 bug,当输入不是 Index 但包含相同值时可能返回 True (GH 13107)

  • 对带时区的 datetime 进行赋值时出现的 bug,如果 datetime 接近 DST 边界,赋值可能不起作用 (GH 14146)

  • 在 python 2 中,pd.eval()HDFStore 查询截断长浮点文字的 bug (GH 14241)

  • Index 中的 bug,当列不在 df 中且列包含重复值时,引发 KeyError 并显示错误的列 (GH 13822)

  • PeriodPeriodIndex 中的 bug,当频率具有组合偏移别名时创建错误日期 (GH 13874)

  • .to_string() 中的 bug,当使用整数 line_widthindex=False 调用时,由于 idx 在赋值前被引用,引发 UnboundLocalError 异常。

  • eval() 中的 bug,其中 resolvers 参数不接受列表 (GH 14095)

  • stack, get_dummies, make_axis_dummies 中的 bug,它们不保留 (multi)indexes 中的分类 dtype (GH 13854)

  • PeriodIndex 现在可以接受包含 pd.NaTlistarray (GH 13430)

  • df.groupby 中的 bug,如果分组后的 dataframe 包含空 bin,则 .median() 返回任意值 (GH 13629)

  • Index.copy() 中的 bug,其中 name 参数被忽略了 (GH 14302)

贡献者#

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

  • Adrien Emery +

  • Alex Alekseyev

  • Alex Vig +

  • Allen Riddell +

  • Amol +

  • Amol Agrawal +

  • Andy R. Terrel +

  • Anthonios Partheniou

  • Ben Kandel +

  • Bob Baxley +

  • Brett Rosen +

  • Camilo Cota +

  • Chris

  • Chris Grinolds

  • Chris Warth

  • Christian Hudon

  • Christopher C. Aycock

  • Daniel Siladji +

  • Douglas McNeil

  • Drewrey Lupton +

  • Eduardo Blancas Reyes +

  • Elliot Marsden +

  • Evan Wright

  • Felix Marczinowski +

  • Francis T. O’Donovan

  • Geraint Duck +

  • Giacomo Ferroni +

  • Grant Roch +

  • Gábor Lipták

  • Haleemur Ali +

  • Hassan Shamim +

  • Iulius Curt +

  • Ivan Nazarov +

  • Jeff Reback

  • Jeffrey Gerard +

  • Jenn Olsen +

  • Jim Crist

  • Joe Jevnik

  • John Evans +

  • John Freeman

  • John Liekezer +

  • John W. O’Brien

  • John Zwinck +

  • Johnny Gill +

  • Jordan Erenrich +

  • Joris Van den Bossche

  • Josh Howes +

  • Jozef Brandys +

  • Ka Wo Chen

  • Kamil Sindi +

  • Kerby Shedden

  • Kernc +

  • Kevin Sheppard

  • Matthieu Brucher +

  • Maximilian Roos

  • Michael Scherer +

  • Mike Graham +

  • Mortada Mehyar

  • Muhammad Haseeb Tariq +

  • Nate George +

  • Neil Parley +

  • Nicolas Bonnotte

  • OXPHOS

  • Pan Deng / Zora +

  • Paul +

  • Paul Mestemaker +

  • Pauli Virtanen

  • Pawel Kordek +

  • Pietro Battiston

  • Piotr Jucha +

  • Ravi Kumar Nimmi +

  • Robert Gieseke

  • Robert Kern +

  • Roger Thomas

  • Roy Keyes +

  • Russell Smith +

  • Sahil Dua +

  • Sanjiv Lobo +

  • Sašo Stanovnik +

  • Shawn Heide +

  • Sinhrks

  • Stephen Kappel +

  • Steve Choi +

  • Stewart Henderson +

  • Sudarshan Konge +

  • Thomas A Caswell

  • Tom Augspurger

  • Tom Bird +

  • Uwe Hoffmann +

  • WillAyd +

  • Xiang Zhang +

  • YG-Riku +

  • Yadunandan +

  • Yaroslav Halchenko

  • Yuichiro Kaneko +

  • adneu

  • agraboso +

  • babakkeyvani +

  • c123w +

  • chris-b1

  • cmazzullo +

  • conquistador1492 +

  • cr3 +

  • dsm054

  • gfyoung

  • harshul1610 +

  • iamsimha +

  • jackieleng +

  • mpuels +

  • pijucha +

  • priyankjain +

  • sinhrks

  • wcwagner +

  • yui-knk +

  • zhangjinjie +

  • znmean +

  • 颜发才(Yan Facai) +