其他有关pandas的话题
这里是另外一些可能在你的数据旅程中用得着的有关pandas的话题。
整数索引
操作由整数索引的pandas对象常常会让新手抓狂,因为它们跟内置的Python数据结构(如列表和元组)在索引语义上有些不同。例如,你可能认为下面这段代码不会产生一个错误:
- ser = Series(np.arange(3.))
- ser[-1]
在这种情况下,虽然pandas会“求助于”整数索引,但没有哪种方法(至少我就不知道)能够既不引入任何bug又安全有效地解决该问题。这里,我们有一个含有0、1、2的索引,但是很难推断出用户想要什么(基于标签或位置的索引):
- In [288]: ser
- Out[288]:
- 0 0
- 1 1
- 2 2
相反,对于一个非整数索引,就没有这样的歧义:
- In [289]: ser2 = Series(np.arange(3.), index=['a', 'b', 'c'])
- In [290]: ser2[-1]
- Out[290]: 2.0
为了保持良好的一致性,如果你的轴索引含有索引器,那么根据整数进行数据选取的操作将总是面向标签的。这也包括用ix进行切片:
- In [291]: ser.ix[:1]
- Out[291]:
- 0 0
- 1 1
如果你需要可靠的、不考虑索引类型的、基于位置的索引,可以使用Series 的iget_value方法和DataFrame的irow和icol方法:
- In [292]: ser3 = Series(range(3), index=[-5, 1, 3])
- In [293]: ser3.iget_value(2)
- Out[293]: 2
- In [294]: frame = DataFrame(np.arange(6).reshape(3, 2), index=[2, 0, 1])
- In [295]: frame.irow(0)
- Out[295]:
- 0 0
- 1 1
- Name: 2
面板数据
pandas有一个Panel数据结构(不是本书的主要内容),你可以将其看做一个三维版的DataFrame。pandas的大部分开发工作都集中在表格型数据的操作上,因为这些数据更常见,而且层次化索引也使得多数情况下没必要使用真正的N维数组。
你可以用一个由DataFrame对象组成的字典或一个三维ndarray来创建Panel对象:
- import pandas.io.data as web
- pdata = pd.Panel(dict((stk, web.get_data_yahoo(stk, '1/1/2009', '6/1/2012'))
- for stk in ['AAPL', 'GOOG', 'MSFT', 'DELL']))
Panel中的每一项(类似于DataFrame的列)都是一个DataFrame:
- In [297]: pdata
- Out[297]:
- <class 'pandas.core.panel.Panel'>
- Dimensions: 4 (items) x 861 (major) x 6 (minor)
- Items: AAPL to MSFT
- Major axis: 2009-01-02 00:00:00 to 2012-06-01 00:00:00
- Minor axis: Open to Adj Close
- In [298]: pdata = pdata.swapaxes('items', 'minor')
- In [299]: pdata['Adj Close']
- Out[299]:
- <class 'pandas.core.frame.DataFrame'>
- DatetimeIndex: 861 entries, 2009-01-02 00:00:00 to 2012-06-01 00:00:00
- Data columns:
- AAPL 861 non-null values
- DELL 861 non-null values
- GOOG 861 non-null values
- MSFT 861 non-null values
- dtypes: float64(4)
基于ix的标签索引被推广到了三个维度,因此我们可以选取指定日期或日期范围的所有数据,如下所示:
- In [300]: pdata.ix[:, '6/1/2012', :]
- Out[300]:
- Open High Low Close Volume Adj Close
- AAPL 569.16 572.65 560.52 560.99 18606700 560.99
- DELL 12.15 12.30 12.05 12.07 19396700 12.07
- GOOG 571.79 572.65 568.35 570.98 3057900 570.98
- MSFT 28.76 28.96 28.44 28.45 56634300 28.45
- In [301]: pdata.ix['Adj Close', '5/22/2012':, :]
- Out[301]:
- AAPL DELL GOOG MSFT
- Date
- 2012-05-22 556.97 15.08 600.80 29.76
- 2012-05-23 570.56 12.49 609.46 29.11
- 2012-05-24 565.32 12.45 603.66 29.07
- 2012-05-25 562.29 12.46 591.53 29.06
- 2012-05-29 572.27 12.66 594.34 29.56
- 2012-05-30 579.17 12.56 588.23 29.34
- 2012-05-31 577.73 12.33 580.86 29.19
- 2012-06-01 560.99 12.07 570.98 28.45
另一个用于呈现面板数据(尤其是对拟合统计模型)的办法是“堆积式的”DataFrame形式:
- In [302]: stacked = pdata.ix[:, '5/30/2012':, :].to_frame()
- In [303]: stacked
- Out[303]:
- Open High Low Close Volume Adj Close
- major minor
- 2012-05-30 AAPL 569.20 579.99 566.56 579.17 18908200 579.17
- DELL 12.59 12.70 12.46 12.56 19787800 12.56
- GOOG 588.16 591.90 583.53 588.23 1906700 588.23
- MSFT 29.35 29.48 29.12 29.34 41585500 29.34
- 2012-05-31 AAPL 580.74 581.50 571.46 577.73 17559800 577.73
- DELL 12.53 12.54 12.33 12.33 19955500 12.33
- GOOG 588.72 590.00 579.00 580.86 2968300 580.86
- MSFT 29.30 29.42 28.94 29.19 39134000 29.19
- 2012-06-01 AAPL 569.16 572.65 560.52 560.99 18606700 560.99
- DELL 12.15 12.30 12.05 12.07 19396700 12.07
- GOOG 571.79 572.65 568.35 570.98 3057900 570.98
- MSFT 28.76 28.96 28.44 28.45 56634300 28.45
DataFrame有一个相应的to_panel方法,它是to_frame的逆运算:
- In [304]: stacked.to_panel()
- Out[304]:
- <class 'pandas.core.panel.Panel'>
- Dimensions: 6 (items) x 3 (major) x 4 (minor)
- Items: Open to Adj Close
- Major axis: 2012-05-30 00:00:00 to 2012-06-01 00:00:00
- Minor axis: AAPL to MSFT