让我们说我有一个具有有限数量的唯一值的数组。说
data = array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])
我还有一个参考数组,其中包含data
中找到的所有唯一值,没有重复且按特定顺序排列。说
reference = array([20, 10, 30])
我想创建一个形状与data
相同的数组,其中包含reference
数组中索引data
数组中每个元素的索引值。
换句话说,拥有data
和reference
,我想创建一个数组indexes
,以便以下成立。
data = reference[indexes]
计算indexes
的次优方法是使用for循环,如此
indexes = np.zeros_like(data, dtype=int)
for i in range(data.size):
indexes[i] = np.where(data[i] == reference)[0]
但是我很惊讶没有 numpythonic (因而更快!)的方式来做这个......有什么想法吗?
谢谢!
答案 0 :(得分:4)
我们将data
和reference
作为 -
In [375]: data
Out[375]: array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])
In [376]: reference
Out[376]: array([20, 10, 30])
请稍等一下,让我们考虑reference
-
In [373]: np.sort(reference)
Out[373]: array([10, 20, 30])
现在,我们可以使用np.searchsorted
找出此排序版本中每个data
元素的位置,如下所示 -
In [378]: np.searchsorted(np.sort(reference), data, side='left')
Out[378]: array([2, 1, 2, 0, 1, 0, 1, 0, 2, 1, 1, 2, 2, 0, 2], dtype=int64)
如果我们运行原始代码,预期输出结果为 -
In [379]: indexes
Out[379]: array([2, 0, 2, 1, 0, 1, 0, 1, 2, 0, 0, 2, 2, 1, 2])
可以看出,searchsorted
输出正常,但其中的0's
必须为1s
且1's
必须更改为0's
。现在,我们已经计算了reference
的排序版本。因此,要执行0's
到1's
,反之亦然,我们需要引入用于排序reference
的索引,即np.argsort(reference)
。这基本上是用于矢量化无循环或无字典方法!所以,最终的实现看起来像这样 -
# Get sorting indices for reference
sort_idx = np.argsort(reference)
# Sort reference and get searchsorted indices for data in reference
pos = np.searchsorted(reference[sort_idx], data, side='left')
# Change pos indices based on sorted indices for reference
out = np.argsort(reference)[pos]
运行时测试 -
In [396]: data = np.random.randint(0,30000,150000)
...: reference = np.unique(data)
...: reference = reference[np.random.permutation(reference.size)]
...:
...:
...: def org_approach(data,reference):
...: indexes = np.zeros_like(data, dtype=int)
...: for i in range(data.size):
...: indexes[i] = np.where(data[i] == reference)[0]
...: return indexes
...:
...: def vect_approach(data,reference):
...: sort_idx = np.argsort(reference)
...: pos = np.searchsorted(reference[sort_idx], data, side='left')
...: return sort_idx[pos]
...:
In [397]: %timeit org_approach(data,reference)
1 loops, best of 3: 9.86 s per loop
In [398]: %timeit vect_approach(data,reference)
10 loops, best of 3: 32.4 ms per loop
验证结果 -
In [399]: np.array_equal(org_approach(data,reference),vect_approach(data,reference))
Out[399]: True
答案 1 :(得分:1)
您必须遍历数据一次才能将数据值映射到索引上。最快的方法是在字典中查找值索引。因此,您需要首先从值到索引创建字典。
这是一个完整的例子:
import numpy
data = numpy.array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])
reference = numpy.array([20, 10, 30])
reference_index = dict((value, index) for index, value in enumerate(reference))
indexes = [reference_index[value] for value in data]
assert numpy.all(data == reference[indexes])
这将比numpy.where
方法更快,因为numpy.where
将执行线性O(n)搜索,而字典方法使用哈希表在O(1)时间内查找索引。
答案 2 :(得分:0)
import numpy as np
data = np.array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])
reference = {20:0, 10:1, 30:2}
indexes = np.zeros_like(data, dtype=int)
for i in xrange(data.size):
indexes[i] = reference[data[i]]
字典查找速度明显加快。 xrange
的使用也有所帮助。
使用timeit:
原文:4.01297836938
此版本:1.30972428591