版本 0.10.0 (2012年12月17日)#

这是继 0.9.1 之后的一个主要版本,包含许多新特性和增强功能,以及大量错误修复。还有一些重要的 API 变更,pandas 的长期用户应密切关注。

文件解析新特性#

分隔符文件解析引擎(即 read_csvread_table 的核心)已从头重写,现在解析时只使用一小部分内存,并且在大多数用例中速度提高 40% 或更多(某些情况下速度更快)。

还有许多新特性

  • 通过 encoding 选项大大改进了 Unicode 处理。

  • 列过滤 (usecols)

  • Dtype 规范 (dtype 参数)

  • 能够指定字符串被识别为 True/False

  • 能够生成 NumPy 记录数组 (as_recarray)

  • 高性能的 delim_whitespace 选项

  • 小数格式(例如欧洲格式)规范

  • 更方便的 CSV 方言选项:escapechar, lineterminator, quotechar 等。

  • 对实践中遇到的许多异常文件类型提供了更稳健的处理

API 变更#

弃用了 DataFrame BINOP TimeSeries 特殊情况行为

DataFrame 和 Series 之间的二元操作默认行为始终是按 DataFrame 的列对齐并沿行广播,**除了** DataFrame 包含时间序列的特殊情况。由于现在每个二元运算符都有方法允许您指定如何广播,我们正在逐步淘汰这种特殊情况(Python 之禅:*特殊情况不足以打破规则*)。我说的就是这个

In [1]: import pandas as pd

In [2]: df = pd.DataFrame(np.random.randn(6, 4), index=pd.date_range("1/1/2000", periods=6))

In [3]: df
Out[3]: 
                   0         1         2         3
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804
2000-01-04  0.721555 -0.706771 -1.039575  0.271860
2000-01-05 -0.424972  0.567020  0.276232 -1.087401
2000-01-06 -0.673690  0.113648 -1.478427  0.524988

# deprecated now
In [4]: df - df[0]
Out[4]: 
             0   1  ...  2000-01-05 00:00:00  2000-01-06 00:00:00
2000-01-01 NaN NaN  ...                  NaN                  NaN
2000-01-02 NaN NaN  ...                  NaN                  NaN
2000-01-03 NaN NaN  ...                  NaN                  NaN
2000-01-04 NaN NaN  ...                  NaN                  NaN
2000-01-05 NaN NaN  ...                  NaN                  NaN
2000-01-06 NaN NaN  ...                  NaN                  NaN

[6 rows x 10 columns]

# Change your code to
In [5]: df.sub(df[0], axis=0)  # align on axis 0 (rows)
Out[5]: 
              0         1         2         3
2000-01-01  0.0 -0.751976 -1.978171 -1.604745
2000-01-02  0.0 -1.385327 -1.092903 -2.256348
2000-01-03  0.0 -1.242720  0.366920  1.933653
2000-01-04  0.0 -1.428326 -1.761130 -0.449695
2000-01-05  0.0  0.991993  0.701204 -0.662428
2000-01-06  0.0  0.787338 -0.804737  1.198677

在 0.10.x 系列中,您将收到弃用警告,并且弃用的功能将在 0.11 或更高版本中移除。

修改了 resample 默认行为

时间序列 resample 对每日 (D) 及更高频率的默认分箱行为已更改为 closed='left', label='left'。较低频率不受影响。之前的默认设置给用户带来了很多困惑,特别是将数据重采样到每日频率时(它用区间的结束来标记聚合组:即第二天)。

In [1]: dates = pd.date_range('1/1/2000', '1/5/2000', freq='4h')

In [2]: series = pd.Series(np.arange(len(dates)), index=dates)

In [3]: series
Out[3]:
2000-01-01 00:00:00     0
2000-01-01 04:00:00     1
2000-01-01 08:00:00     2
2000-01-01 12:00:00     3
2000-01-01 16:00:00     4
2000-01-01 20:00:00     5
2000-01-02 00:00:00     6
2000-01-02 04:00:00     7
2000-01-02 08:00:00     8
2000-01-02 12:00:00     9
2000-01-02 16:00:00    10
2000-01-02 20:00:00    11
2000-01-03 00:00:00    12
2000-01-03 04:00:00    13
2000-01-03 08:00:00    14
2000-01-03 12:00:00    15
2000-01-03 16:00:00    16
2000-01-03 20:00:00    17
2000-01-04 00:00:00    18
2000-01-04 04:00:00    19
2000-01-04 08:00:00    20
2000-01-04 12:00:00    21
2000-01-04 16:00:00    22
2000-01-04 20:00:00    23
2000-01-05 00:00:00    24
Freq: 4H, dtype: int64

In [4]: series.resample('D', how='sum')
Out[4]:
2000-01-01     15
2000-01-02     51
2000-01-03     87
2000-01-04    123
2000-01-05     24
Freq: D, dtype: int64

In [5]: # old behavior
In [6]: series.resample('D', how='sum', closed='right', label='right')
Out[6]:
2000-01-01      0
2000-01-02     21
2000-01-03     57
2000-01-04     93
2000-01-05    129
Freq: D, dtype: int64
  • 无穷大和负无穷大不再被 isnullnotnull 视为 NA。它们曾被视为 NA 是早期 pandas 的遗留问题。可以通过 mode.use_inf_as_null 选项全局重新启用此行为。

In [6]: s = pd.Series([1.5, np.inf, 3.4, -np.inf])

In [7]: pd.isnull(s)
Out[7]:
0    False
1    False
2    False
3    False
Length: 4, dtype: bool

In [8]: s.fillna(0)
Out[8]:
0    1.500000
1         inf
2    3.400000
3        -inf
Length: 4, dtype: float64

In [9]: pd.set_option('use_inf_as_null', True)

In [10]: pd.isnull(s)
Out[10]:
0    False
1     True
2    False
3     True
Length: 4, dtype: bool

In [11]: s.fillna(0)
Out[11]:
0    1.5
1    0.0
2    3.4
3    0.0
Length: 4, dtype: float64

In [12]: pd.reset_option('use_inf_as_null')
  • 带有 inplace 选项的方法现在都返回 None,而不是调用对象。例如,像 df = df.fillna(0, inplace=True) 这样的代码可能不再起作用。要修复,只需删除不必要的变量赋值。

  • pandas.merge 默认不再对分组键进行排序 (sort=False)。这样做是出于性能考虑:分组键排序通常是计算中比较耗时的部分之一,而且通常是不必要的。

  • 没有头部的文件的默认列名已更改为整数 0N - 1。这与没有指定列的 DataFrame 构造函数保持一致。v0.9.0 的行为(列名 X0, X1, …)可以通过指定 prefix='X' 来重现。

In [6]: import io

In [7]: data = """
  ...: a,b,c
  ...: 1,Yes,2
  ...: 3,No,4
  ...: """
  ...:

In [8]: print(data)

    a,b,c
    1,Yes,2
    3,No,4

In [9]: pd.read_csv(io.StringIO(data), header=None)
Out[9]:
       0    1  2
0      a    b  c
1      1  Yes  2
2      3   No  4

In [10]: pd.read_csv(io.StringIO(data), header=None, prefix="X")
Out[10]:
        X0   X1 X2
0       a    b  c
1       1  Yes  2
2       3   No  4
  • 'Yes''No' 这样的值默认不被解释为布尔值,尽管这可以通过新的 true_valuesfalse_values 参数来控制

In [4]: print(data)

    a,b,c
    1,Yes,2
    3,No,4

In [5]: pd.read_csv(io.StringIO(data))
Out[5]:
       a    b  c
0      1  Yes  2
1      3   No  4

In [6]: pd.read_csv(io.StringIO(data), true_values=["Yes"], false_values=["No"])
Out[6]:
       a      b  c
0      1   True  2
1      3  False  4
  • 如果将转换器函数生成的非字符串值通过 na_values 参数传入,文件解析器不会将其识别为 NA。最好改用 replace 函数进行后处理。

  • 在 Series 或 DataFrame 上不带参数调用 fillna 不再是有效代码。您必须指定一个填充值或一个插值方法

In [6]: s = pd.Series([np.nan, 1.0, 2.0, np.nan, 4])

In [7]: s
Out[7]: 
0    NaN
1    1.0
2    2.0
3    NaN
4    4.0
dtype: float64

In [8]: s.fillna(0)
Out[8]: 
0    0.0
1    1.0
2    2.0
3    0.0
4    4.0
dtype: float64

In [9]: s.fillna(method="pad")
Out[9]: 
0    NaN
1    1.0
2    2.0
3    2.0
4    4.0
dtype: float64

添加了便捷方法 ffillbfill

In [10]: s.ffill()
Out[10]: 
0    NaN
1    1.0
2    2.0
3    2.0
4    4.0
dtype: float64
  • Series.apply 现在将对应用函数返回的值进行操作,该值本身是一个 Series,并可能将结果提升为 DataFrame

    In [11]: def f(x):
       ....:     return pd.Series([x, x ** 2], index=["x", "x^2"])
       ....: 
    
    In [12]: s = pd.Series(np.random.rand(5))
    
    In [13]: s
    Out[13]: 
    0    0.340445
    1    0.984729
    2    0.919540
    3    0.037772
    4    0.861549
    dtype: float64
    
    In [14]: s.apply(f)
    Out[14]: 
              x       x^2
    0  0.340445  0.115903
    1  0.984729  0.969691
    2  0.919540  0.845555
    3  0.037772  0.001427
    4  0.861549  0.742267
    
  • 用于处理 pandas 选项的新 API 函数 (GH 2097)

    • get_option / set_option - 获取/设置选项的值。接受部分名称。 - reset_option - 将一个或多个选项重置为其默认值。接受部分名称。 - describe_option - 打印一个或多个选项的描述。在不带参数调用时,打印所有注册的选项。

    注意:set_printoptions / reset_printoptions 现已弃用(但仍可工作),打印选项现在位于“display.XYZ”下。例如

    In [15]: pd.get_option("display.max_rows")
    Out[15]: 15
    
  • to_string() 方法现在总是返回 unicode 字符串 (GH 2224)。

新特性#

宽幅 DataFrame 打印#

pandas 现在默认将字符串表示形式拆分到多行,而不是打印摘要信息

In [16]: wide_frame = pd.DataFrame(np.random.randn(5, 16))

In [17]: wide_frame
Out[17]: 
         0         1         2   ...        13        14        15
0 -0.548702  1.467327 -1.015962  ...  1.669052  1.037882 -1.705775
1 -0.919854 -0.042379  1.247642  ...  1.956030  0.017587 -0.016692
2 -0.575247  0.254161 -1.143704  ...  1.211526  0.268520  0.024580
3 -1.577585  0.396823 -0.105381  ...  0.593616  0.884345  1.591431
4  0.141809  0.220390  0.435589  ... -0.392670  0.007207  1.928123

[5 rows x 16 columns]

可以通过 ‘expand_frame_repr’ 打印选项实现打印摘要信息的旧行为

In [18]: pd.set_option("expand_frame_repr", False)

In [19]: wide_frame
Out[19]: 
         0         1         2         3         4         5         6         7         8         9         10        11        12        13        14        15
0 -0.548702  1.467327 -1.015962 -0.483075  1.637550 -1.217659 -0.291519 -1.745505 -0.263952  0.991460 -0.919069  0.266046 -0.709661  1.669052  1.037882 -1.705775
1 -0.919854 -0.042379  1.247642 -0.009920  0.290213  0.495767  0.362949  1.548106 -1.131345 -0.089329  0.337863 -0.945867 -0.932132  1.956030  0.017587 -0.016692
2 -0.575247  0.254161 -1.143704  0.215897  1.193555 -0.077118 -0.408530 -0.862495  1.346061  1.511763  1.627081 -0.990582 -0.441652  1.211526  0.268520  0.024580
3 -1.577585  0.396823 -0.105381 -0.532532  1.453749  1.208843 -0.080952 -0.264610 -0.727965 -0.589346  0.339969 -0.693205 -0.339355  0.593616  0.884345  1.591431
4  0.141809  0.220390  0.435589  0.192451 -0.096701  0.803351  1.715071 -0.708758 -1.202872 -1.814470  1.018601 -0.595447  1.395433 -0.392670  0.007207  1.928123

每行的宽度可以通过 ‘line_width’ 更改(默认为 80)

pd.set_option("line_width", 40)

wide_frame

更新了 PyTables 支持#

PyTables Table 格式的文档和一些 API 增强功能。以下是部分内容预览。

In [41]: store = pd.HDFStore('store.h5')

In [42]: df = pd.DataFrame(np.random.randn(8, 3),
   ....:                   index=pd.date_range('1/1/2000', periods=8),
   ....:                   columns=['A', 'B', 'C'])

In [43]: df
Out[43]:
                   A         B         C
2000-01-01 -2.036047  0.000830 -0.955697
2000-01-02 -0.898872 -0.725411  0.059904
2000-01-03 -0.449644  1.082900 -1.221265
2000-01-04  0.361078  1.330704  0.855932
2000-01-05 -1.216718  1.488887  0.018993
2000-01-06 -0.877046  0.045976  0.437274
2000-01-07 -0.567182 -0.888657 -0.556383
2000-01-08  0.655457  1.117949 -2.782376

[8 rows x 3 columns]

# appending data frames
In [44]: df1 = df[0:4]

In [45]: df2 = df[4:]

In [46]: store.append('df', df1)

In [47]: store.append('df', df2)

In [48]: store
Out[48]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df            frame_table  (typ->appendable,nrows->8,ncols->3,indexers->[index])

# selecting the entire store
In [49]: store.select('df')
Out[49]:
                   A         B         C
2000-01-01 -2.036047  0.000830 -0.955697
2000-01-02 -0.898872 -0.725411  0.059904
2000-01-03 -0.449644  1.082900 -1.221265
2000-01-04  0.361078  1.330704  0.855932
2000-01-05 -1.216718  1.488887  0.018993
2000-01-06 -0.877046  0.045976  0.437274
2000-01-07 -0.567182 -0.888657 -0.556383
2000-01-08  0.655457  1.117949 -2.782376

[8 rows x 3 columns]
In [50]: wp = pd.Panel(np.random.randn(2, 5, 4), items=['Item1', 'Item2'],
   ....:               major_axis=pd.date_range('1/1/2000', periods=5),
   ....:               minor_axis=['A', 'B', 'C', 'D'])

In [51]: wp
Out[51]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

# storing a panel
In [52]: store.append('wp', wp)

# selecting via A QUERY
In [53]: store.select('wp', [pd.Term('major_axis>20000102'),
   ....:                     pd.Term('minor_axis', '=', ['A', 'B'])])
   ....:
Out[53]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 2 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to B

# removing data from tables
In [54]: store.remove('wp', pd.Term('major_axis>20000103'))
Out[54]: 8

In [55]: store.select('wp')
Out[55]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-03 00:00:00
Minor_axis axis: A to D

# deleting a store
In [56]: del store['df']

In [57]: store
Out[57]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/wp            wide_table   (typ->appendable,nrows->12,ncols->2,indexers->[major_axis,minor_axis])

增强功能

  • 添加了对分层键的支持

    In [58]: store.put('foo/bar/bah', df)
    
    In [59]: store.append('food/orange', df)
    
    In [60]: store.append('food/apple', df)
    
    In [61]: store
    Out[61]:
    <class 'pandas.io.pytables.HDFStore'>
    File path: store.h5
    /foo/bar/bah            frame        (shape->[8,3])
    /food/apple             frame_table  (typ->appendable,nrows->8,ncols->3,indexers->[index])
    /food/orange            frame_table  (typ->appendable,nrows->8,ncols->3,indexers->[index])
    /wp                     wide_table   (typ->appendable,nrows->12,ncols->2,indexers->[major_axis,minor_axis])
    
    # remove all nodes under this level
    In [62]: store.remove('food')
    
    In [63]: store
    Out[63]:
    <class 'pandas.io.pytables.HDFStore'>
    File path: store.h5
    /foo/bar/bah            frame        (shape->[8,3])
    /wp                     wide_table   (typ->appendable,nrows->12,ncols->2,indexers->[major_axis,minor_axis])
    
  • 添加了混合 dtype 支持!

    In [64]: df['string'] = 'string'
    
    In [65]: df['int'] = 1
    
    In [66]: store.append('df', df)
    
    In [67]: df1 = store.select('df')
    
    In [68]: df1
    Out[68]:
                       A         B         C  string  int
    2000-01-01 -2.036047  0.000830 -0.955697  string    1
    2000-01-02 -0.898872 -0.725411  0.059904  string    1
    2000-01-03 -0.449644  1.082900 -1.221265  string    1
    2000-01-04  0.361078  1.330704  0.855932  string    1
    2000-01-05 -1.216718  1.488887  0.018993  string    1
    2000-01-06 -0.877046  0.045976  0.437274  string    1
    2000-01-07 -0.567182 -0.888657 -0.556383  string    1
    2000-01-08  0.655457  1.117949 -2.782376  string    1
    
    [8 rows x 5 columns]
    
    In [69]: df1.get_dtype_counts()
    Out[69]:
    float64    3
    int64      1
    object     1
    dtype: int64
    
  • 表写入性能改进

  • 支持任意索引的维度

  • SparseSeries 现在有了 density 属性 (GH 2384)

  • 使 Series.str.strip/lstrip/rstrip 方法能够接受输入参数来去除任意字符 (GH 2411)

  • melt 中实现 value_vars 以限制值仅限于某些列,并将 melt 添加到 pandas 命名空间 (GH 2412)

错误修复

  • 添加了指定 where 条件的 Term 方法 (GH 1996)。

  • del store['df'] 现在调用 store.remove('df') 来删除存储

  • 连续行的删除比以前快得多

  • 在创建表时可以指定 min_itemsize 参数,以强制索引列具有最小大小(以前的实现会根据第一次附加来设置列大小)

  • 通过 create_table_index 支持索引(需要 PyTables >= 2.3)(GH 698)。

  • 如果表未首先通过 put 创建,则在存储上附加会失败

  • 修复了加载 pickle 化的 dataframe 后属性丢失的问题 (GH2431)

  • select 和 remove 的微小更改:仅当同时提供了 where (且不为 None) 时才需要表

兼容性

0.10 版本的 HDFStore 向后兼容,可以读取使用先前版本 pandas 创建的表,但是,使用先前(未记录)方法学的查询词不受支持。您必须读取整个文件并使用新格式写出,才能利用这些更新。

N 维面板 (实验性)#

添加了对 Panel4D 的实验性支持以及用于创建 N 维命名面板的工厂函数。以下是部分内容预览。

In [58]: p4d = Panel4D(np.random.randn(2, 2, 5, 4),
  ....:       labels=['Label1','Label2'],
  ....:       items=['Item1', 'Item2'],
  ....:       major_axis=date_range('1/1/2000', periods=5),
  ....:       minor_axis=['A', 'B', 'C', 'D'])
  ....:

In [59]: p4d
Out[59]:
<class 'pandas.core.panelnd.Panel4D'>
Dimensions: 2 (labels) x 2 (items) x 5 (major_axis) x 4 (minor_axis)
Labels axis: Label1 to Label2
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

有关完整列表,请参阅完整发布说明或 GitHub 上的问题跟踪器。

贡献者#

共有 26 位贡献者为本次发布提交了补丁。名字旁带有“+”的人是首次贡献补丁。

  • A. Flaxman +

  • Abraham Flaxman

  • Adam Obeng +

  • Brenda Moon +

  • Chang She

  • Chris Mulligan +

  • Dieter Vandenbussche

  • Donald Curtis +

  • Jay Bourque +

  • Jeff Reback +

  • Justin C Johnson +

  • K.-Michael Aye

  • Keith Hughitt +

  • Ken Van Haren +

  • Laurent Gautier +

  • Luke Lee +

  • Martin Blais

  • Tobias Brandt +

  • Wes McKinney

  • Wouter Overmeire

  • alex arsenovic +

  • jreback +

  • locojaydev +

  • timmie

  • y-p

  • zach powers +