如何像熊猫数据帧一样快速地访问numpy数组



我对访问DataFrame中数据的几种方法进行了比较。请参阅下面的结果。最快的访问是在DataFrame上使用get_value方法。我在这篇帖子中提到了这一点。

令我惊讶的是,通过get_value的访问比通过底层numpy对象df.values的访问更快。

问题

我的问题是,有没有一种方法可以像我通过get_value访问pandas数据帧一样快速地访问numpy数组的元素?

设置

import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(16).reshape(4, 4))

测试

%%timeit
df.iloc[2, 2]

10000个环路,3个最佳值:每个环路108µs

%%timeit
df.values[2, 2]

最慢的跑步时间是最快的5.42倍。这可能意味着正在缓存一个中间结果。100000个环路,3个最佳:每个环路8.02µs

%%timeit
df.iat[2, 2]

最慢的跑步时间是最快的跑步时间的4.96倍。这可能意味着正在缓存一个中间结果。100000个环路,3个最佳:每个环路9.85µs

%%timeit
df.get_value(2, 2)

最慢的跑步时间是最快的跑步时间的19.29倍。这可能意味着正在缓存一个中间结果。100000个环路,3个最佳:每个环路3.57µs

iloc非常通用,接受切片和列表以及简单整数。在上面的例子中,如果您有简单的整数索引,panda首先确定它是一个有效的整数,然后它将请求转换为iat索引,所以很明显它会慢得多。iat最终解析为对get_value的调用,因此对get_value的直接调用自然会很快。get_value本身是缓存的,所以像这样的微基准测试可能无法反映实际代码中的性能。

df.values确实返回ndarray,但仅在检查它是单个连续块之后。这需要一些查找和测试,所以它比从缓存中检索值慢一点。

我们可以通过每次创建一个新的数据帧来击败缓存。这表明values访问器是最快的,至少对于统一类型的数据:

In [111]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4))
10000 loops, best of 3: 186 µs per loop
In [112]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4)); df.values[2,2]
1000 loops, best of 3: 200 µs per loop
In [113]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4)); df.get_value(2,2)
1000 loops, best of 3: 309 µs per loop
In [114]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4)); df.iat[2,2]
1000 loops, best of 3: 308 µs per loop
In [115]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4)); df.iloc[2,2]
1000 loops, best of 3: 420 µs per loop
In [116]: %timeit df = pd.DataFrame(np.arange(16).reshape(4, 4)); df.ix[2,2]
1000 loops, best of 3: 316 µs per loop

该代码声称ix是最通用的,因此理论上应该比iloc慢;您的特定测试可能支持CCD_ 17,但其他测试可能仅因为将索引标识为标量索引所需的测试顺序而支持iloc

最新更新