我有一个包含两列和一十多万个元素的DataFrame。
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
我有什么遗失的东西吗?这是大熊猫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()
我只是增加了第二个high
的{{1}}参数,这意味着randint()
的长度更长。这会在没有数据文件的情况下重现我的错误。
请注意,如果我放弃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
上的last()
缩放。
答案 0 :(得分:4)
一定是奇怪的事情......在0.13.1(和主人)中看起来不错。发布您的文件的链接,我会看看。
In [3]: rng = date_range('20130101',periods=20,freq='s')
In [4]: df = DataFrame(dict(timestamp = rng.take(np.random.randint(0,20,size=100000)), value = np.random.randint(0,100,size=100000)*1000000))
In [5]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 100000 entries, 0 to 99999
Data columns (total 2 columns):
timestamp 100000 non-null datetime64[ns]
value 100000 non-null int64
dtypes: datetime64[ns](1), int64(1)
In [6]: %timeit df.groupby('value')['timestamp'].last()
100 loops, best of 3: 9.07 ms per loop
In [7]: %timeit df.groupby('value')['timestamp'].tail(1)
100 loops, best of 3: 16.3 ms per loop
好的,这是解释:
使用np.random.randint(0,100,size=100000)
作为值,创建100个组,
虽然np.random.randint(0,100000,size=100000)
创造了更多(在我的例子中)
63000)左右。
.last
(&lt; 0.14)implicity执行最后一个non-nan
值。这个na测试并不便宜,因此缩放性能很差(并且在每个组的python空间中完成)。
tail(1)
(&lt; 0.14)不检查这个,所以perf更好(并使用cython路由来获得结果)。
在0.14中这些将是相同的(即使你这样做:nth(-1,dropna='any')
将复制last
在这里做的事情,这样做是为了获得更好的性能。 (感谢@Andy Hayden)。
底线是在&lt;中使用tail(1)
0.14。