如何快速访问numpy数组,就像访问pandas数据框一样。

7
我对几种访问 DataFrame 数据的方式进行了比较。以下是结果。使用 get_value 方法访问 DataFrame 是最快的方法。我在这个 post 上得到了这个方法。
令我惊讶的是,通过 get_value 访问比通过底层 numpy 对象 df.values 访问更快。

问题

我的问题是,有没有一种方法可以像使用 get_value 一样快速地访问 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微秒

%%timeit
df.values[2, 2]

最慢的运行时间比最快的运行时间慢了5.42倍。这可能意味着一个中间结果正在被缓存。 100000次循环,3次中最好的表现:每个循环8.02微秒。
%%timeit
df.iat[2, 2]

最慢的运行时间比最快的时间长了4.96倍。这可能意味着中间结果被缓存了。 100000次循环,3次中取最佳:每次循环9.85微秒。
%%timeit
df.get_value(2, 2)

最慢的运行时间比最快的时间长了19.29倍。这可能意味着中间结果正在被缓存。 100000次循环,3次中取最好:每次循环3.57微秒。

谁曾经对这个问题点了踩,我很希望能够得到一些反馈意见。谢谢。 - piRSquared
如果您的瓶颈是单元素访问,那么您应该一次访问多个元素。 - Eric
另外,您可能需要检查x = df.values;%timeit x [2,2]是否给出类似的结果 - 也许values不是属性而是property - Eric
1个回答

3
iloc是非常通用的,可以接受切片、列表以及简单的整数。在上述情况中,如果您使用简单的整数索引,pandas首先确定它是有效的整数,然后将请求转换为iat索引,因此速度会慢得多。 iat最终会解析为对get_value的调用,因此直接调用get_value自然会更快。 get_value本身已缓存,因此微基准测试(micro-benchmarks)可能无法反映实际代码的性能。

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慢;也许您的特定测试偏爱ix,但其他测试可能会支持iloc,只是因为需要识别索引作为标量索引的顺序不同。

除了提供非常好的答案之外,我还想感谢您提供了良好的技巧来将缓存与性能检查解耦。运行 df 创建作为基准,然后进行从头创建 df 的测试非常适用于确定在实时代码中使用每种方法的时间。 - piRSquared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接