其他有关pandas的话题

这里是另外一些可能在你的数据旅程中用得着的有关pandas的话题。

整数索引

操作由整数索引的pandas对象常常会让新手抓狂,因为它们跟内置的Python数据结构(如列表和元组)在索引语义上有些不同。例如,你可能认为下面这段代码不会产生一个错误:

  1. ser = Series(np.arange(3.))
  2. ser[-1]

在这种情况下,虽然pandas会“求助于”整数索引,但没有哪种方法(至少我就不知道)能够既不引入任何bug又安全有效地解决该问题。这里,我们有一个含有0、1、2的索引,但是很难推断出用户想要什么(基于标签或位置的索引):

  1. In [288]: ser
  2. Out[288]:
  3. 0 0
  4. 1 1
  5. 2 2

相反,对于一个非整数索引,就没有这样的歧义:

  1. In [289]: ser2 = Series(np.arange(3.), index=['a', 'b', 'c'])
  2.  
  3. In [290]: ser2[-1]
  4. Out[290]: 2.0

为了保持良好的一致性,如果你的轴索引含有索引器,那么根据整数进行数据选取的操作将总是面向标签的。这也包括用ix进行切片:

  1. In [291]: ser.ix[:1]
  2. Out[291]:
  3. 0 0
  4. 1 1

如果你需要可靠的、不考虑索引类型的、基于位置的索引,可以使用Series 的iget_value方法和DataFrame的irow和icol方法:

  1. In [292]: ser3 = Series(range(3), index=[-5, 1, 3])
  2.  
  3. In [293]: ser3.iget_value(2)
  4. Out[293]: 2
  5.  
  6. In [294]: frame = DataFrame(np.arange(6).reshape(3, 2), index=[2, 0, 1])
  7. In [295]: frame.irow(0)
  8. Out[295]:
  9. 0 0
  10. 1 1
  11. Name: 2

面板数据

pandas有一个Panel数据结构(不是本书的主要内容),你可以将其看做一个三维版的DataFrame。pandas的大部分开发工作都集中在表格型数据的操作上,因为这些数据更常见,而且层次化索引也使得多数情况下没必要使用真正的N维数组。

你可以用一个由DataFrame对象组成的字典或一个三维ndarray来创建Panel对象:

  1. import pandas.io.data as web
  2.  
  3. pdata = pd.Panel(dict((stk, web.get_data_yahoo(stk, '1/1/2009', '6/1/2012'))
  4. for stk in ['AAPL', 'GOOG', 'MSFT', 'DELL']))

Panel中的每一项(类似于DataFrame的列)都是一个DataFrame:

  1. In [297]: pdata
  2. Out[297]:
  3. <class 'pandas.core.panel.Panel'>
  4. Dimensions: 4 (items) x 861 (major) x 6 (minor)
  5. Items: AAPL to MSFT
  6. Major axis: 2009-01-02 00:00:00 to 2012-06-01 00:00:00
  7. Minor axis: Open to Adj Close
  8.  
  9. In [298]: pdata = pdata.swapaxes('items', 'minor')
  10. In [299]: pdata['Adj Close']
  11. Out[299]:
  12. <class 'pandas.core.frame.DataFrame'>
  13. DatetimeIndex: 861 entries, 2009-01-02 00:00:00 to 2012-06-01 00:00:00
  14. Data columns:
  15. AAPL 861 non-null values
  16. DELL 861 non-null values
  17. GOOG 861 non-null values
  18. MSFT 861 non-null values
  19. dtypes: float64(4)

基于ix的标签索引被推广到了三个维度,因此我们可以选取指定日期或日期范围的所有数据,如下所示:

  1. In [300]: pdata.ix[:, '6/1/2012', :]
  2. Out[300]:
  3. Open High Low Close Volume Adj Close
  4. AAPL 569.16 572.65 560.52 560.99 18606700 560.99
  5. DELL 12.15 12.30 12.05 12.07 19396700 12.07
  6. GOOG 571.79 572.65 568.35 570.98 3057900 570.98
  7. MSFT 28.76 28.96 28.44 28.45 56634300 28.45
  8.  
  9. In [301]: pdata.ix['Adj Close', '5/22/2012':, :]
  10. Out[301]:
  11. AAPL DELL GOOG MSFT
  12. Date
  13. 2012-05-22 556.97 15.08 600.80 29.76
  14. 2012-05-23 570.56 12.49 609.46 29.11
  15. 2012-05-24 565.32 12.45 603.66 29.07
  16. 2012-05-25 562.29 12.46 591.53 29.06
  17. 2012-05-29 572.27 12.66 594.34 29.56
  18. 2012-05-30 579.17 12.56 588.23 29.34
  19. 2012-05-31 577.73 12.33 580.86 29.19
  20. 2012-06-01 560.99 12.07 570.98 28.45

另一个用于呈现面板数据(尤其是对拟合统计模型)的办法是“堆积式的”DataFrame形式:

  1. In [302]: stacked = pdata.ix[:, '5/30/2012':, :].to_frame()
  2.  
  3. In [303]: stacked
  4. Out[303]:
  5. Open High Low Close Volume Adj Close
  6. major minor
  7. 2012-05-30 AAPL 569.20 579.99 566.56 579.17 18908200 579.17
  8. DELL 12.59 12.70 12.46 12.56 19787800 12.56
  9. GOOG 588.16 591.90 583.53 588.23 1906700 588.23
  10. MSFT 29.35 29.48 29.12 29.34 41585500 29.34
  11. 2012-05-31 AAPL 580.74 581.50 571.46 577.73 17559800 577.73
  12. DELL 12.53 12.54 12.33 12.33 19955500 12.33
  13. GOOG 588.72 590.00 579.00 580.86 2968300 580.86
  14. MSFT 29.30 29.42 28.94 29.19 39134000 29.19
  15. 2012-06-01 AAPL 569.16 572.65 560.52 560.99 18606700 560.99
  16. DELL 12.15 12.30 12.05 12.07 19396700 12.07
  17. GOOG 571.79 572.65 568.35 570.98 3057900 570.98
  18. MSFT 28.76 28.96 28.44 28.45 56634300 28.45

DataFrame有一个相应的to_panel方法,它是to_frame的逆运算:

  1. In [304]: stacked.to_panel()
  2. Out[304]:
  3. <class 'pandas.core.panel.Panel'>
  4. Dimensions: 6 (items) x 3 (major) x 4 (minor)
  5. Items: Open to Adj Close
  6. Major axis: 2012-05-30 00:00:00 to 2012-06-01 00:00:00
  7. Minor axis: AAPL to MSFT