背景
我有许多数值消息代码存储在NumPy数组中,需要快速将它们转换为字符串。我在性能方面遇到了一些问题,希望了解为什么会出现这种情况以及如何快速处理。
一些基准测试
I - 简单的方法
import numpy as np
# dictionary to use as the lookup dictionary
lookupdict = {
1: "val1",
2: "val2",
27: "val3",
35: "val4",
59: "val5" }
# some test data
arr = np.random.choice(lookupdict.keys(), 1000000)
# create a list of words looked up
res = [ lookupdict[k] for k in arr ]
字典查询需要我咖啡休息时间中的大部分时间,758毫秒。(我也尝试过 res = map(lookupdict.get, arr)
但那更糟糕。)
II - 没有 NumPy
import random
# dictionary to use as the lookup dictionary
lookupdict = {
1: "val1",
2: "val2",
27: "val3",
35: "val4",
59: "val5" }
# some test data
arr = [ random.choice(lookupdict.keys()) for _ in range(1000000) ]
# create a list of words looked up
res = [ lookupdict[k] for k in arr ]
时间结果相比之前变化了很多,现在为76毫秒!
需要注意的是我只对查找时间感兴趣。随机生成只是为了创建一些测试数据。它花费了多少时间并不重要。这里给出的所有基准结果仅针对100万次查找。
III - 将NumPy数组转换为列表
我最初的猜想是这与列表与数组的问题有关。但是,通过修改使用列表的NumPy版本:
res = [ lookupdict[k] for k in list(arr) ]
我得到了778毫秒的时间,其中大约110毫秒用于转换列表,570毫秒用于查找。因此,查找速度略快,但总时间相同。
IV - 从np.int32
转换为int
类型
由于唯一的其他区别似乎是数据类型(np.int32
vs. int
),因此我尝试了即时转换类型。这有点愚蠢,因为可能dict也会这样做:
res = [ lookupdict[int(k)] for k in arr ]
然而,这似乎有些有趣,因为时间降至266毫秒。看起来,几乎但不完全相同的数据类型会对字典查找产生恶劣影响,而字典代码在转换方面效率不高。
V - 将字典键转换为np.int32
为了测试这一点,我修改了NumPy版本,使用与字典键和查找完全相同的数据类型:
import numpy as np
# dictionary to use as the lookup dictionary
lookupdict = {
np.int32(1): "val1",
np.int32(2): "val2",
np.int32(27): "val3",
np.int32(35): "val4",
np.int32(59): "val5" }
# some test data
arr = np.random.choice(lookupdict.keys(), 1000000)
# create a list of words looked up
res = [ lookupdict[k] for k in arr ]
这个时间提高到了177毫秒。虽然这是一个不小的提升,但仍然远远落后于76毫秒。
VI - 将数组转换为使用int
对象
import numpy as np
# dictionary to use as the lookup dictionary
lookupdict = {
1: "val1",
2: "val2",
27: "val3",
35: "val4",
59: "val5" }
# some test data
arr = np.array([ random.choice(lookupdict.keys()) for _ in range(1000000) ],
dtype='object')
# create a list of words looked up
res = [ lookupdict[k] for k in arr ]
这个结果给出了86毫秒,已经非常接近本机Python的76毫秒。
结果概述
- 使用
int
作为字典键,在使用int
进行索引时(本地Python):76毫秒。 - 使用
int
作为字典键,在使用int
对象进行索引时(NumPy):86毫秒。 - 使用
np.int32
作为字典键,在使用np.int32
进行索引时:177毫秒。 - 使用
int
作为字典键,在使用np.int32
进行索引时:758毫秒。
问题
为什么?我该怎么做才能使字典查找尽可能快?我的输入数据是一个NumPy数组,因此到目前为止最好的选择(最快但难看)是将字典键转换为np.int32
。(不幸的是,字典键可能分布在大范围的数字上,因此逐个数组进行索引不是可行的替代方案。虽然它会很快,只需要10毫秒。)