版本 0.12.0 (2013年7月24日)#

这是 0.11.0 的一个重要版本,包含了一些新特性和增强功能,以及大量的 bug 修复。

主要亮点包括:统一的 I/O API 命名方案、读取 HTML 的例程、将 MultiIndex 写入 CSV 文件、读写 STATA 数据文件、读写 JSON 格式文件、HDFStore 的 Python 3 支持、通过 filter 过滤 groupby 表达式,以及经过改进的支持正则表达式的 replace 例程。

API 变更#

  • I/O API 现在更加一致,提供了一组顶层 reader 函数,例如通过 pd.read_csv() 访问,这些函数通常返回一个 pandas 对象。

    • read_csv

    • read_excel

    • read_hdf

    • read_sql

    • read_json

    • read_html

    • read_stata

    • read_clipboard

    对应的 writer 函数是对象方法,通过 df.to_csv() 访问

    • to_csv

    • to_excel

    • to_hdf

    • to_sql

    • to_json

    • to_html

    • to_stata

    • to_clipboard

  • 修复 Series 和 DataFrame 上的模运算和整数除法,使其行为类似于 float 数据类型,适当地返回 np.nannp.inf (GH 3590)。这纠正了 numpy 将 integerfloat 数据类型区别对待的错误。

    In [1]: p = pd.DataFrame({"first": [4, 5, 8], "second": [0, 0, 3]})
    
    In [2]: p % 0
    Out[2]: 
       first  second
    0    NaN     NaN
    1    NaN     NaN
    2    NaN     NaN
    
    In [3]: p % p
    Out[3]: 
       first  second
    0    0.0     NaN
    1    0.0     NaN
    2    0.0     0.0
    
    In [4]: p / p
    Out[4]: 
       first  second
    0    1.0     NaN
    1    1.0     NaN
    2    1.0     1.0
    
    In [5]: p / 0
    Out[5]: 
       first  second
    0    inf     NaN
    1    inf     NaN
    2    inf     inf
    
  • groupby 添加 squeeze 关键字,如果组是唯一的,则允许从 DataFrame -> Series 进行归约。这是 0.10.1 版本的一个回归。我们正在恢复到之前的行为。这意味着无论组是否唯一,groupby 都将返回相同形状的对象。撤销此问题 (GH 2893) 并修复 (GH 3596)。

    In [2]: df2 = pd.DataFrame([{"val1": 1, "val2": 20},
       ...:                     {"val1": 1, "val2": 19},
       ...:                     {"val1": 1, "val2": 27},
       ...:                     {"val1": 1, "val2": 12}])
    
    In [3]: def func(dataf):
       ...:     return dataf["val2"] - dataf["val2"].mean()
       ...:
    
    In [4]: # squeezing the result frame to a series (because we have unique groups)
       ...: df2.groupby("val1", squeeze=True).apply(func)
    Out[4]:
    0    0.5
    1   -0.5
    2    7.5
    3   -7.5
    Name: 1, dtype: float64
    
    In [5]: # no squeezing (the default, and behavior in 0.10.1)
       ...: df2.groupby("val1").apply(func)
    Out[5]:
    val2    0    1    2    3
    val1
    1     0.5 -0.5  7.5 -7.5
    
  • 在使用基于标签的索引器掩码(例如布尔 Series)进行布尔索引时,即使带有整数标签,iloc 也会引发错误。由于 iloc 纯粹基于位置,Series 上的标签无法对齐 (GH 3631)

    这种情况很少使用,并且有许多替代方法。这保留了 iloc API 纯粹基于位置的特性。

    In [6]: df = pd.DataFrame(range(5), index=list("ABCDE"), columns=["a"])
    
    In [7]: mask = df.a % 2 == 0
    
    In [8]: mask
    Out[8]: 
    A     True
    B    False
    C     True
    D    False
    E     True
    Name: a, dtype: bool
    
    # this is what you should use
    In [9]: df.loc[mask]
    Out[9]: 
       a
    A  0
    C  2
    E  4
    
    # this will work as well
    In [10]: df.iloc[mask.values]
    Out[10]: 
       a
    A  0
    C  2
    E  4
    

    df.iloc[mask] 将引发 ValueError

  • 绘图函数的 raise_on_error 参数已移除。相反,当对象的 dtypeobject 时,绘图函数会引发 TypeError,以提醒您尽可能避免使用 object 数组,因此如果您需要绘图,应该将其转换为适当的数值数据类型。

  • 向 DataFrame 绘图方法添加 colormap 关键字。接受 matplotlib 颜色映射对象(例如,matplotlib.cm.jet)或此类对象的字符串名称(例如,'jet')。颜色映射被采样以选择每个列的颜色。有关更多信息,请参阅 颜色映射。( GH 3860)

  • DataFrame.interpolate() 现已弃用。请改用 DataFrame.fillna()DataFrame.replace()。( GH 3582, GH 3675, GH 3676)

  • DataFrame.replace()methodaxis 参数已弃用。

  • DataFrame.replaceinfer_types 参数已移除,现在默认执行转换。( GH 3907)

  • DataFrame.insert 添加关键字 allow_duplicates,如果为 True,则允许插入重复列,默认值为 False (与 0.12 之前相同)( GH 3679)

  • NDFrame 对象实现 __nonzero__ (GH 3691, GH 3696)

  • IO API

    • 添加了顶层函数 read_excel 以替代以下内容,原始 API 已弃用,将在未来版本中移除

      from pandas.io.parsers import ExcelFile
      
      xls = ExcelFile("path_to_file.xls")
      xls.parse("Sheet1", index_col=None, na_values=["NA"])
      

      随着

      import pandas as pd
      
      pd.read_excel("path_to_file.xls", "Sheet1", index_col=None, na_values=["NA"])
      
    • 添加了顶层函数 read_sql,其功能等同于以下内容

      from pandas.io.sql import read_frame
      
      read_frame(...)
      
  • DataFrame.to_htmlDataFrame.to_latex 现在接受路径作为第一个参数 (GH 3702)

  • 不允许 datetime64[ns] 转换为其他类型,除了 objecttimedelta64[ns] 仅允许转换为 object/int (GH 3425)

  • datetime64 数据类型的行为在某些所谓的归约操作方面有所改变 (GH 3726)。以下操作现在在 Series 上执行时会引发 TypeError,而在 DataFrame 上执行时则返回一个Series,类似于在例如 slice 对象的 DataFrame 上执行这些操作。

    • sum, prod, mean, std, var, skew, kurt, corr, and cov

  • read_html 现在在读取时默认为 None,当 lxml 解析失败时,会回退到 bs4 + html5lib。尝试多个解析器直到成功也是有效的。

  • 内部 pandas 类层次结构已(略微)改变。以前的 PandasObject 现在被称为 PandasContainer,一个新的 PandasObject 成为了 PandasContainer 以及 Index, Categorical, GroupBy, SparseList, 和 SparseArray(以及它们的基类)的基类。目前,PandasObject 提供了字符串方法(来自 StringMixin)。(GH 4090, GH 4092)

  • 新的 StringMixin,给定一个 __unicode__ 方法,可以获得与 python 2 和 python 3 兼容的字符串方法(__str____bytes____repr__)。此外,还提供了全面的字符串安全性。现在广泛应用于 pandas 库的许多地方。( GH 4090, GH 4092)

IO 增强功能#

  • pd.read_html() 现在可以解析 HTML 字符串、文件或 URL 并返回 DataFrame,这要感谢 @cpcloud。( GH 3477, GH 3605, GH 3606, GH 3616)。它与单个解析器后端配合使用:BeautifulSoup4 + html5lib 参阅文档

    你可以使用 pd.read_html() 读取 DataFrame.to_html() 的输出,如下所示:

    In [11]: df = pd.DataFrame({"a": range(3), "b": list("abc")})
    
    In [12]: print(df)
       a  b
    0  0  a
    1  1  b
    2  2  c
    
    In [13]: html = df.to_html()
    
    In [14]: alist = pd.read_html(html, index_col=0)
    
    In [15]: print(df == alist[0])
          a     b
    0  True  True
    1  True  True
    2  True  True
    

    请注意,这里的 alist 是 Python 的 list,所以 pd.read_html()DataFrame.to_html() 并非互逆操作。

    • pd.read_html() 不再对日期字符串执行硬转换 (GH 3656)。

    警告

    您可能需要安装旧版本的 BeautifulSoup4,请参阅安装文档

  • 添加了用于读写 Stata 文件的模块:pandas.io.stata (GH 1512),可通过顶层函数 read_stata 进行读取,并通过 DataFrame 方法 to_stata 进行写入。请参阅文档

  • 添加了用于读写 JSON 格式文件的模块:pandas.io.json,可通过顶层函数 read_json 进行读取,并通过 DataFrame 方法 to_json 进行写入。请参阅文档,解决了各种问题 (GH 1226, GH 3804, GH 3876, GH 3867, GH 1305)

  • 对 CSV 格式文件读写的 MultiIndex 列支持。

    • read_csv 中的 header 选项现在接受一个列表,该列表指定要读取索引的行。

    • 选项 tupleize_cols 现在可以在 to_csvread_csv 中指定,以提供与 0.12 之前版本兼容的行为,即通过元组列表写入和读取 MultIndex 列。0.12 版本的默认行为是写入元组列表,并且将元组列表解释为 MultiIndex 列。

      注意:0.12 版本的默认行为与之前版本保持不变,但从 0.13 版本开始,写入和读取 MultiIndex 列的默认行为将采用新格式。( GH 3571, GH 1651, GH 3141)

    • 如果未指定 index_col(例如,您没有索引,或者使用 df.to_csv(..., index=False 写入),那么列索引上的任何 names 都将丢失

      In [16]: mi_idx = pd.MultiIndex.from_arrays([[1, 2, 3, 4], list("abcd")], names=list("ab"))
      
      In [17]: mi_col = pd.MultiIndex.from_arrays([[1, 2], list("ab")], names=list("cd"))
      
      In [18]: df = pd.DataFrame(np.ones((4, 2)), index=mi_idx, columns=mi_col)
      
      In [19]: df.to_csv("mi.csv")
      
      In [20]: print(open("mi.csv").read())
      c,,1,2
      d,,a,b
      a,b,,
      1,a,1.0,1.0
      2,b,1.0,1.0
      3,c,1.0,1.0
      4,d,1.0,1.0
      
      
      In [21]: pd.read_csv("mi.csv", header=[0, 1, 2, 3], index_col=[0, 1])
      Out[21]: 
      c                    1                  2
      d                    a                  b
      a   Unnamed: 2_level_2 Unnamed: 3_level_2
      1                  1.0                1.0
      2 b                1.0                1.0
      3 c                1.0                1.0
      4 d                1.0                1.0
      
  • 支持 Python3 上的 HDFStore (通过 PyTables 3.0.0)

  • 通过 read_hdf 支持迭代器,当迭代完成时自动打开和关闭存储。这仅适用于

    In [25]: path = 'store_iterator.h5'
    
    In [26]: pd.DataFrame(np.random.randn(10, 2)).to_hdf(path, 'df', table=True)
    
    In [27]: for df in pd.read_hdf(path, 'df', chunksize=3):
       ....:     print(df)
       ....:
              0         1
    0  0.713216 -0.778461
    1 -0.661062  0.862877
    2  0.344342  0.149565
              0         1
    3 -0.626968 -0.875772
    4 -0.930687 -0.218983
    5  0.949965 -0.442354
              0         1
    6 -0.402985  1.111358
    7 -0.241527 -0.670477
    8  0.049355  0.632633
              0         1
    9 -1.502767 -1.225492
    
  • read_csv 现在在文件不包含任何列(例如,只有换行符)时会抛出更具信息性的错误消息。

其他增强功能#

  • DataFrame.replace() 现在允许对包含 object 数据类型的 Series 使用正则表达式。请参阅常规文档中的示例部分:通过字符串表达式替换

    例如,你可以这样做:

    In [22]: df = pd.DataFrame({"a": list("ab.."), "b": [1, 2, 3, 4]})
    
    In [23]: df.replace(regex=r"\s*\.\s*", value=np.nan)
    Out[23]: 
         a  b
    0    a  1
    1    b  2
    2  NaN  3
    3  NaN  4
    

    NaN 替换所有字符串 '.' 及其周围的零个或多个空白字符的出现。

    常规字符串替换仍然按预期工作。例如,你可以这样做

    In [24]: df.replace(".", np.nan)
    Out[24]: 
         a  b
    0    a  1
    1    b  2
    2  NaN  3
    3  NaN  4
    

    NaN 替换所有字符串 '.' 的出现。

  • pd.melt() 现在接受可选参数 var_namevalue_name 来指定返回 DataFrame 的自定义列名。

  • pd.set_option() 现在允许 N 对选项-值 (GH 3667)。

    假设我们有一个选项 'a.b' 和另一个选项 'b.c'。我们可以同时设置它们:

    In [31]: pd.get_option('a.b')
    Out[31]: 2
    
    In [32]: pd.get_option('b.c')
    Out[32]: 3
    
    In [33]: pd.set_option('a.b', 1, 'b.c', 4)
    
    In [34]: pd.get_option('a.b')
    Out[34]: 1
    
    In [35]: pd.get_option('b.c')
    Out[35]: 4
    
  • 组对象的 filter 方法返回原始对象的一个子集。假设我们只想获取属于组总和大于 2 的组中的元素。

    In [25]: sf = pd.Series([1, 1, 2, 3, 3, 3])
    
    In [26]: sf.groupby(sf).filter(lambda x: x.sum() > 2)
    Out[26]: 
    3    3
    4    3
    5    3
    dtype: int64
    

    filter 的参数必须是一个函数,该函数应用于整个组时返回 TrueFalse

    另一个有用的操作是过滤掉只包含少数成员的组中的元素。

    In [27]: dff = pd.DataFrame({"A": np.arange(8), "B": list("aabbbbcc")})
    
    In [28]: dff.groupby("B").filter(lambda x: len(x) > 2)
    Out[28]: 
       A  B
    2  2  b
    3  3  b
    4  4  b
    5  5  b
    

    或者,我们可以在不删除不符合过滤条件的组的情况下,返回一个具有相同索引的对象,其中不符合过滤条件的组填充为 NaN。

    In [29]: dff.groupby("B").filter(lambda x: len(x) > 2, dropna=False)
    Out[29]: 
         A    B
    0  NaN  NaN
    1  NaN  NaN
    2  2.0    b
    3  3.0    b
    4  4.0    b
    5  5.0    b
    6  NaN  NaN
    7  NaN  NaN
    
  • Series 和 DataFrame 的 hist 方法现在接受 figsize 参数 (GH 3834)

  • DatetimeIndex 在连接操作期间不再尝试转换混合整数索引 (GH 3877)

  • Timestamp.min 和 Timestamp.max 现在分别表示有效的 Timestamp 实例,而不是默认的 datetime.min 和 datetime.max,感谢 @SleepingPills。

  • 当没有找到表且检测到 BeautifulSoup==4.2.0 时,read_html 现在会引发错误 (GH 4214)

实验性功能#

  • 添加了实验性 CustomBusinessDay 类,以支持带有自定义假期日历和自定义周掩码的 DateOffsets。( GH 2301)

    注意

    这使用了 Numpy 1.7 中引入的 numpy.busdaycalendar API,因此需要 Numpy 1.7.0 或更高版本。

    In [30]: from pandas.tseries.offsets import CustomBusinessDay
    
    In [31]: from datetime import datetime
    
    # As an interesting example, let's look at Egypt where
    # a Friday-Saturday weekend is observed.
    In [32]: weekmask_egypt = "Sun Mon Tue Wed Thu"
    
    # They also observe International Workers' Day so let's
    # add that for a couple of years
    In [33]: holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
    
    In [34]: bday_egypt = CustomBusinessDay(holidays=holidays, weekmask=weekmask_egypt)
    
    In [35]: dt = datetime(2013, 4, 30)
    
    In [36]: print(dt + 2 * bday_egypt)
    2013-05-05 00:00:00
    
    In [37]: dts = pd.date_range(dt, periods=5, freq=bday_egypt)
    
    In [38]: print(pd.Series(dts.weekday, dts).map(pd.Series("Mon Tue Wed Thu Fri Sat Sun".split())))
    2013-04-30    Tue
    2013-05-02    Thu
    2013-05-05    Sun
    2013-05-06    Mon
    2013-05-07    Tue
    Freq: C, dtype: object
    

Bug 修复#

  • 如果相关对象的 dtype 是 object,绘图函数现在会在尝试绘图之前引发 TypeError (GH 1818, GH 3572, GH 3911, GH 3912),但如果可能,它们会尝试将 object 数组转换为数值数组,以便您仍然可以绘制例如包含浮点数的 object 数组。这发生在任何绘图操作之前,从而消除了任何虚假绘图的出现。

  • 如果 value 参数是列表或元组,fillna 方法现在会引发 TypeError

  • Series.str 现在支持迭代 (GH 3638)。您可以迭代 Series 中每个字符串的单个元素。每次迭代都会生成一个 Series,其中包含原始 Series 的每个索引处的一个字符或 NaN。例如,

    In [38]: strs = "go", "bow", "joe", "slow"
    
    In [32]: ds = pd.Series(strs)
    
    In [33]: for s in ds.str:
        ...:     print(s)
    
    0    g
    1    b
    2    j
    3    s
    dtype: object
    0    o
    1    o
    2    o
    3    l
    dtype: object
    0    NaN
    1      w
    2      e
    3      o
    dtype: object
    0    NaN
    1    NaN
    2    NaN
    3      w
    dtype: object
    
    In [41]: s
    Out[41]:
    0    NaN
    1    NaN
    2    NaN
    3      w
    dtype: object
    
    In [42]: s.dropna().values.item() == "w"
    Out[42]: True
    

    迭代器产生的最后一个元素将是一个 Series,其中包含 Series 中最长字符串的最后一个元素,所有其他元素均为 NaN。在这里,由于 'slow' 是最长的字符串,并且没有其他长度相同的字符串,因此 'w' 是生成的 Series 中唯一的非空字符串。

  • HDFStore

    • 在重新创建时将保留索引属性(freq、tz、name)(GH 3499)

    • 如果尝试附加一个与现有索引频率不同的索引,或者尝试附加一个与现有索引名称不同的索引,将发出 AttributeConflictWarning 警告

    • 支持带有 timezone 的日期时间列作为 data_columns (GH 2852)

  • 非唯一索引支持已澄清 (GH 3468)。

    • 修复在 DataFrame 中将新索引分配给重复索引时失败的问题 (GH 3468)

    • 修复了构造具有重复索引的 DataFrame 的问题。

    • ref_locs 支持允许跨 dtype 的重复索引,使 iget 支持始终能够找到索引(即使跨 dtype)(GH 2194)

    • 在具有非唯一索引的 DataFrame 上使用 applymap 现在可以正常工作(移除了警告)(GH 2786),并修复了 (GH 3230)

    • 修复 to_csv 以处理非唯一列 (GH 3495)

    • 通过 getitem 处理重复索引时将按正确顺序返回项目 (GH 3455, GH 3457),并像唯一索引一样处理缺失元素 (GH 3561)

    • 通过 DataFrame.from_records 使用重复索引和空DataFrame将返回一个正确的DataFrame (GH 3562)

    • 修复了当重复列跨越不同数据类型时,Concat 会产生非唯一列的问题 (GH 3602)

    • 允许插入/删除到非唯一列 (GH 3679)

    • 修复了通过 loc 及相关方法进行非唯一索引切片的问题 (GH 3659)

    • 允许插入/删除到非唯一列 (GH 3679)

    • 扩展 reindex 以正确处理非唯一索引 (GH 3679)

    • DataFrame.itertuples() 现在可以与具有重复列名的 DataFrame 一起使用 (GH 3873)

    • iloc 在非唯一索引中的 bug 修复 (GH 4017);向 reindex 添加了 takeable 参数,用于基于位置的选取

    • 允许通过 .ix/.loc__getitem__ 在 Series 中进行非唯一索引 (GH 4246)

    • 修复了 .ix/.loc 在非唯一索引中的内存分配问题 (GH 4280)

  • DataFrame.from_records 不接受空记录数组 (GH 3682)

  • read_html 现在可以正确跳过测试 (GH 3741)

  • 修复了 DataFrame.replace 中,当 to_replace 参数中包含编译的正则表达式时无法正常工作的 bug (GH 3907)

  • 改进了 network 测试装饰器,以捕获 IOError (也因此捕获 URLError)。添加了 with_connectivity_check 装饰器,允许显式检查网站以作为网络连接的代理。此外,还新增了 optional_args 装饰器工厂,用于装饰器。( GH 3910, GH 3914)

  • 修复了测试问题,即打开了过多套接字,导致连接重置问题 (GH 3982, GH 3985, GH 4028, GH 4054)

  • 修复了 test_yahoo、test_google 中测试失败的问题,其中符号未检索但被访问 (GH 3982, GH 3985, GH 4028, GH 4054)

  • Series.hist 如果未传入 figure,则将从当前环境中获取 figure。

  • 修复了 1xN DataFrame 在 1xN 掩码上崩溃的 bug (GH 4071)

  • 修复了在 python3 下运行 tox 时 pickle 导入被以不兼容方式重写的问题 (GH 4062, GH 4063)

  • 修复了 sharex 和 sharey 未传递给 grouped_hist 的 bug (GH 4089)

  • 修复了 DataFrame.replace 中当 regex=False 时嵌套字典未被迭代的 bug (GH 4115)

  • 修复了在使用 to_datetimeformat 参数时解析微秒的 bug (GH 4152)

  • 修复了 PandasAutoDateLocatorinvert_xaxis 错误触发 MilliSecondLocator 的 bug (GH 3990)

  • 修复了 matplotlib 1.1.1 在无效颜色映射时未引发错误的绘图 bug (GH 4215)

  • 修复了 DataFrame.plot(kind='kde') 中图例显示的问题 (GH 4216)

  • 修复了 Index 切片未携带 name 属性的 bug (GH 4226)

  • 修复了在特定时区中使用字符串数组初始化 DatetimeIndex 的 bug (GH 4229)

  • 修复了 html5lib 未正确跳过的 bug (GH 4265)

  • 修复了 get_data_famafrench 未使用正确文件边界的 bug (GH 4281)

请参阅 完整的发布说明 或 GitHub 上的问题跟踪器以获取完整列表。

贡献者#

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

  • Andy Hayden

  • Chang She (佘畅)

  • Christopher Whelan

  • Damien Garaud

  • Dan Allan

  • Dan Birken

  • Dieter Vandenbussche

  • Dražen Lučanin

  • Gábor Lipták +

  • Jeff Mellen +

  • Jeff Tratner +

  • Jeffrey Tratner +

  • Jonathan deWerd +

  • Joris Van den Bossche +

  • Juraj Niznan +

  • Karmel Allison

  • Kelsey Jordahl

  • Kevin Stone +

  • Kieran O’Mahony

  • Kyle Meyer +

  • Mike Kelly +

  • PKEuS +

  • Patrick O’Brien +

  • Phillip Cloud

  • Richard Höchenberger +

  • Skipper Seabold

  • SleepingPills +

  • Tobias Brandt

  • Tom Farnbauer +

  • TomAugspurger +

  • Trent Hauck +

  • Wes McKinney

  • Wouter Overmeire

  • Yaroslav Halchenko

  • conmai +

  • danielballan +

  • davidshinn +

  • dieterv77

  • duozhang +

  • ejnens +

  • gliptak +

  • jniznan +

  • jreback

  • lexual

  • nipunreddevil +

  • ogiaquino +

  • stonebig +

  • tim smith +

  • timmie

  • y-p