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

这是从 0.11.0 版本以来的一个重大发布,包括几个新功能和增强功能,以及大量错误修复。

亮点包括一致的 I/O API 命名方案、读取 html 的例程、将 MultiIndexes 写入 csv 文件、读取和写入 STATA 数据文件、读取和写入 JSON 格式文件、Python 3 支持 HDFStore、通过 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 和 DataFrames 上的模数和整数除法,使其与 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
    
  • 当使用基于标签的索引器掩码(例如布尔序列)进行布尔索引时,即使带有整数标签,也会在 iloc 上引发。由于 iloc 纯粹是基于位置的,序列上的标签无法对齐 (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] 进行 astype 转换,除非转换为 object,以及 timedelta64[ns] 转换为 object/int (GH 3425)

  • datetime64 数据类型的行为在某些所谓的归约操作(GH 3726)方面已经改变。以下操作在 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 以及 IndexCategoricalGroupBySparseListSparseArray (以及它们的基类)的基类。目前, 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]: import io
    
    In [12]: df = pd.DataFrame({"a": range(3), "b": list("abc")})
    
    In [13]: print(df)
       a  b
    0  0  a
    1  1  b
    2  2  c
    
    In [14]: html = df.to_html()
    
    In [15]: alist = pd.read_html(io.StringIO(html), index_col=0)
    
    In [16]: print(df == alist[0])
          a     b
    0  True  True
    1  True  True
    2  True  True
    

    注意,这里的 alist 是一个 Python 列表,因此 pd.read_html()DataFrame.to_html() 不是互逆的。

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

    警告

    你可能需要安装一个较旧版本的 BeautifulSoup4,查看安装文档

  • 添加了用于读写 Stata 文件的模块:pandas.io.stata (GH 1512) 可通过 read_stata 顶级函数进行读取,以及通过 to_stata DataFrame 方法进行写入,查看文档

  • 添加了用于读写json格式文件的模块:pandas.io.json 可通过 read_json 顶级函数进行读取,以及 to_json DataFrame 方法进行写入,查看文档 各种问题 (GH 1226, GH 3804, GH 3876, GH 3867, GH 1305)

  • MultiIndex 列支持读取和写入 csv 格式文件

    • 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 [17]: mi_idx = pd.MultiIndex.from_arrays([[1, 2, 3, 4], list("abcd")], names=list("ab"))
      
      In [18]: mi_col = pd.MultiIndex.from_arrays([[1, 2], list("ab")], names=list("cd"))
      
      In [19]: df = pd.DataFrame(np.ones((4, 2)), index=mi_idx, columns=mi_col)
      
      In [20]: df.to_csv("mi.csv")
      
      In [21]: 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 [22]: pd.read_csv("mi.csv", header=[0, 1, 2, 3], index_col=[0, 1])
      Out[22]: 
      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() 现在允许在包含对象数据类型的 Series 上使用正则表达式。请参阅常规文档中的示例部分 通过字符串表达式替换

    例如,你可以这样做

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

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

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

    In [25]: df.replace(".", np.nan)
    Out[25]: 
         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 [26]: sf = pd.Series([1, 1, 2, 3, 3, 3])
    
    In [27]: sf.groupby(sf).filter(lambda x: x.sum() > 2)
    Out[27]: 
    3    3
    4    3
    5    3
    dtype: int64
    

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

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

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

    或者,我们可以返回一个类似索引的对象,而不是丢弃违规的组,其中未通过过滤器的组用 NaNs 填充。

    In [30]: dff.groupby("B").filter(lambda x: len(x) > 2, dropna=False)
    Out[30]: 
         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

  • read_html 现在在未找到表格且检测到 BeautifulSoup==4.2.0 时会引发 (GH 4214)

实验性功能#

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

    备注

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

    In [31]: from pandas.tseries.offsets import CustomBusinessDay
    
    In [32]: from datetime import datetime
    
    # As an interesting example, let's look at Egypt where
    # a Friday-Saturday weekend is observed.
    In [33]: weekmask_egypt = "Sun Mon Tue Wed Thu"
    
    # They also observe International Workers' Day so let's
    # add that for a couple of years
    In [34]: holidays = ["2012-05-01", datetime(2013, 5, 1), np.datetime64("2014-05-01")]
    
    In [35]: bday_egypt = CustomBusinessDay(holidays=holidays, weekmask=weekmask_egypt)
    
    In [36]: dt = datetime(2013, 4, 30)
    
    In [37]: print(dt + 2 * bday_egypt)
    2013-05-05 00:00:00
    
    In [38]: dts = pd.date_range(dt, periods=5, freq=bday_egypt)
    
    In [39]: 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),但它们会尝试将对象数组转换为数值数组(如果可能的话),这样你仍然可以绘制,例如,一个包含浮点数的对象数组。这发生在任何绘图之前,从而消除了任何虚假的绘图出现。

  • 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,其他所有元素都是 NaN。这里因为 'slow' 是最长的字符串,并且没有其他字符串具有相同的长度,所以产生的 Series 中只有 'w' 是非空字符串。

  • HDFStore

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

    • 如果你尝试用与现有频率不同的频率追加索引,或者尝试用与现有名称不同的名称追加索引,将会发出 AttributeConflictWarning 警告。

    • 支持带有时区的类似日期的列为数据列 (GH 2852)

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

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

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

    • ref_locs 支持允许多个数据类型之间的重复索引,允许 iget 支持始终找到索引(即使在不同数据类型之间)(GH 2194)

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

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

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

    • 使用空的 DataFrame.from_records 重复索引将返回正确的框架 (GH 3562)

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

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

    • 通过 loc 和朋友们使用切片进行非唯一索引已修复 (GH 3659)

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

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

    • DataFrame.itertuples() 现在可以处理具有重复列名的数据框 (GH 3873)

    • 通过 iloc 进行非唯一索引的错误 (GH 4017);为 reindex 添加了 takeable 参数以进行基于位置的取值

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

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

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

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

  • 修复了一个 DataFrame.replaceto_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 掩码时会出错的问题 (GH 4071)

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

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

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

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

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

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

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

  • 修复了索引切片未携带名称属性的错误 (GH 4226)

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

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

  • 修复了 get_data_famafrench 未使用正确文件边缘的错误 (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