性能和内存使用方面的注意事项

Timestamp和Period都是以64位整数表示的(即NumPy的datetime64数据类型)。也就是说,对于每个数据点,其时间戳需要占用8字节的内存。因此,含有一百万个float64数据点的时间序列需要占用大约16MB的内存空间。由于pandas会尽量在多个时间序列之间共享索引,所以创建现有时间序列的视图不会占用更多内存译注11。此外,低频率索引(日以上)会被存放在一个中心缓存中,所以任何固定频率的索引都是该日期缓存的视图。所以,如果你有一个很大的低频率时间序列,索引所占用的内存空间将不会很大。

性能方面,pandas对数据对齐(两个不同索引的ts1+ts2的幕后工作)和重采样运算进行了高度优化。下面这个例子将一亿个数据点聚合为OHLC:

  1. In [582]: rng = pd.date_range('1/1/2000', periods=10000000, freq='10ms')
  2.  
  3. In [583]: ts = Series(np.random.randn(len(rng)), index=rng)
  4.  
  5. In [584]: ts
  6. Out[584]:
  7. 2000-01-01 00:00:00 -1.402235
  8. 2000-01-01 00:00:00.010000 2.424667
  9. 2000-01-01 00:00:00.020000 -1.956042
  10. 2000-01-01 00:00:00.030000 -0.897339
  11. ...
  12. 2000-01-02 03:46:39.960000 0.495530
  13. 2000-01-02 03:46:39.970000 0.574766
  14. 2000-01-02 03:46:39.980000 1.348374
  15. 2000-01-02 03:46:39.990000 0.665034
  16. Freq: 10L, Length: 10000000
  17.  
  18. In [585]: ts.resample('15min', how='ohlc')
  19. Out[585]:
  20. <class 'pandas.core.frame.DataFrame'>
  21. DatetimeIndex: 113 entries, 2000-01-01 00:00:00 to 2000-01-02 04:00:00
  22. Freq: 15T
  23. Data columns:
  24. open 113 non-null values
  25. high 113 non-null values
  26. low 113 non-null values
  27. close 113 non-null values
  28. dtypes: float64(4)
  29.  
  30. In [586]: %timeit ts.resample('15min', how='ohlc')
  31. 10 loops, best of 3: 61.1 ms per loop

运行时间跟聚合结果的相对大小有一定关系,越高频率的聚合所耗费的时间越多:

  1. In [587]: rng = pd.date_range('1/1/2000', periods=10000000, freq='1s')
  2.  
  3. In [588]: ts = Series(np.random.randn(len(rng)), index=rng)
  4.  
  5. In [589]: %timeit ts.resample('15s', how='ohlc')
  6. 1 loops, best of 3: 88.2 ms per loop

可能在你阅读本书的时候,这些算法的性能已经大为改进了。比如说,目前并没有对规则频率之间的转换做任何优化,但这肯定是要做的。

译注11:原文就是这么表达的。我感到很不解,既然是视图,当然不会占用多少内容,毕竟就是比单个指针大点的东西而已。结合上下文来看,估计说的只是索引的问题。