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

这是 0.11.0 的一个主要版本,包含多个新功能、增强功能以及大量的错误修复。

主要亮点包括一致的 I/O API 命名方案、用于读取 html 的例程、将 MultiIndexes 写入 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 dtypes,根据情况返回 np.nannp.inf (GH 3590)。这纠正了一个 numpy 错误,该错误区别对待 integerfloat dtypes。

    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 3596) 恢复此问题 (GH 2893)。

    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 数组,因此如果您需要绘制某些内容,应将其转换为相应的数值 dtype。

  • 为 DataFrame 绘图方法添加 colormap 关键字。它接受 matplotlib colormap 对象(例如 matplotlib.cm.jet)或此类对象的字符串名称(例如 'jet')。 colormap 被采样以选择每列的颜色。请参阅Colormaps(色谱)了解更多信息。 (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] 执行 astypes 操作,除非转换为 object在;对于 timedelta64[ns],只允许转换为 object/int (GH 3425)

  • 对于某些所谓的缩减操作 (GH 3726),datetime64 dtypes 的行为已发生变化。当在 Series 上执行时,以下操作现在会引发 TypeError;当在 DataFrame 上执行时,会返回一个 Series,类似于在例如 slice 对象的 DataFrame 上执行这些操作。

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

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

  • 内部 pandas 类层次结构已发生(轻微)变化。之前的 PandasObject 现在称为 PandasContainer,新的 PandasObject 已成为 PandasContainer 以及 Index, Categorical, GroupBy, SparseListSparseArray(及其基类)的基类。目前,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 并返回 DataFrames,感谢 @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 版本之前通过元组列表写入和读取 MultiIndex 列的行为的兼容性。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
      
  • 在 Python 3 上支持 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 dtype 的 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
    

    或者,与其丢弃不符合条件的组,我们可以返回一个索引相似的对象,其中未通过过滤的组填充有 NaNs。

    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)

  • DatetimeIndexes 在连接操作期间不再尝试转换混合整数索引 (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
    

错误修复#

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

  • fillna 方法现在在 value 参数是列表或元组时引发 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 警告

    • 支持将带有时区的日期型列作为 data_columns (GH 2852)

  • 阐明了对非唯一索引的支持 (GH 3468)。

    • 修复了在 DataFrame 中为重复索引分配新索引会失败的问题 (GH 3468)

    • 修复了使用重复索引构建 DataFrame 的问题

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

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

    • 修复了 to_csv 处理非唯一列的问题 (GH 3495)

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

    • 带有重复索引和空 DataFrame.from_records 将返回正确的帧 (GH 3562)

    • 修复了当重复项跨越 dtypes 时,concat 会生成非唯一列的问题 (GH 3602)

    • 允许对非唯一列进行插入/删除操作 (GH 3679)

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

    • 允许对非唯一列进行插入/删除操作 (GH 3679)

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

    • 带有重复列名的 DataFrame 现在可以使用 DataFrame.itertuples() 方法 (GH 3873)

    • 修复了通过 iloc 进行非唯一索引的 Bug (GH 4017);为 reindex 添加了 takeable 参数以进行基于位置的选择

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

    • 修复了使用 .ix/.loc 进行非唯一索引时的内存分配问题 (GH 4280)

  • DataFrame.from_records 不接受空 recarrays (GH 3682)

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

  • 修复了一个 Bug,即在 to_replace 参数中使用编译后的正则表达式调用 DataFrame.replace 无效的问题 (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 现在如果未传入图形对象,将从当前环境获取

  • 修复了 1xN DataFrame 在遇到 1xN 掩码时会出错的 bug(GH 4071

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

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

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

  • 修复了在 to_datetime 中使用 format 参数时解析微秒的 bug(GH 4152

  • 修复了 PandasAutoDateLocatorinvert_xaxis 不正确地触发 MilliSecondLocator 的 bug(GH 3990

  • 修复了绘图中对于 matplotlib 1.1.1 无效 colormap 未抛出异常的 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