我有一个数据帧,有两列,超过十万个元素。
In [43]: df.head(10)
Out[43]:
localtime ref
4 2014-04-02 12:00:00.273537 139058754703810577
5 2014-04-02 12:00:02.223501 139058754703810576
6 2014-04-02 12:00:03.518817 139058754703810576
7 2014-04-02 12:00:03.572082 139058754703810576
8 2014-04-02 12:00:03.572444 139058754703810576
9 2014-04-02 12:00:03.572571 139058754703810576
10 2014-04-02 12:00:03.573320 139058754703810576
11 2014-04-02 12:00:09.278517 139058754703810576
14 2014-04-02 12:00:20.942802 139058754703810577
15 2014-04-02 12:01:13.410607 139058754703810576
[10 rows x 2 columns]
In [44]: df.dtypes
Out[44]:
localtime datetime64[ns]
ref int64
dtype: object
In [45]: len(df)
Out[45]: 111743
In [46]: g = df.groupby('ref')
如果我请求组中的最后一个元素,函数就会卡住!
In [47]: %timeit g.last()
我在6分钟后结束了它的运行;
top
显示整个时间CPU占用率达到100%。如果我明确请求
localtime
列,这样至少可以返回结果,虽然对于数量如此之少的元素来说,它仍然似乎非常慢。In [48]: %timeit g['localtime'].last()
1 loops, best of 3: 4.6 s per loop
我是否漏掉了什么?这里使用的是pandas 0.13.1。
这个问题出现在datetime64
类型中。假设我直接从文件中读取:
In [1]: import pandas as pd
In [2]: df = pd.read_csv('so.csv')
In [3]: df.dtypes
Out[3]:
localtime object
ref int64
dtype: object
In [4]: %timeit df.groupby('ref').last()
10 loops, best of 3: 28.1 ms per loop
object
类型可以正常工作。但是,如果我强制转换我的时间戳,一切都会失控:
In [5]: df.localtime = pd.to_datetime(df.localtime)
In [6]: df.dtypes
Out[6]:
localtime datetime64[ns]
ref int64
dtype: object
In [7]: %timeit df.groupby('ref').last()
情节变得扑朔迷离。
使用Jeff的建议进行无数据文件复制:
In [70]: rng = pd.date_range('20130101',periods=20,freq='s')
In [71]: df = pd.DataFrame(dict(timestamp = rng.take(np.random.randint(0,20,size=100000)), value = np.random.randint(0,100,size=100000)*1000000))
In [72]: %timeit df.groupby('value').last()
1 loops, best of 3: 332 ms per loop
然而,如果我改变随机整数的范围,问题会再次出现!
In [73]: df = pd.DataFrame(dict(timestamp = rng.take(np.random.randint(0,20,size=100000)), value = np.random.randint(0,100000,size=100000)*1000))
In [74]: %timeit df.groupby('value').last()
我只是增加了第二个
randint()
的high
参数,这意味着groupby()
将具有更大的长度。这样可以在没有数据文件的情况下重现我的错误。请注意,如果我放弃使用
datetime64
类型,则没有问题:In [12]: df = pd.DataFrame(dict(timestamp = np.random.randint(0,20,size=100000), value = np.random.randint(0,100000,size=100000)*1000))
In [13]: %timeit df.groupby('value').last()
100 loops, best of 3: 14.4 ms per loop
所以罪魁祸首在于对
datetime64
进行last()
的缩放。