mga*_*gab 5 python arrays performance numpy
假设我有一个具有有限数量唯一值的数组。说
data = array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])
Run Code Online (Sandbox Code Playgroud)
而且我还有一个参考数组,其中包含在 中找到的所有唯一值data,没有重复且按特定顺序排列。说
reference = array([20, 10, 30])
Run Code Online (Sandbox Code Playgroud)
而且我想创建一个形状相同的数组,而不是data包含reference数组中的索引作为值,其中data找到数组中的每个元素。
换句话说,有data和reference,我想创建一个数组indexes,使得以下内容成立。
data = reference[indexes]
Run Code Online (Sandbox Code Playgroud)
一个次优的计算indexes方法是使用 for 循环,像这样
indexes = np.zeros_like(data, dtype=int)
for i in range(data.size):
indexes[i] = np.where(data[i] == reference)[0]
Run Code Online (Sandbox Code Playgroud)
但我很惊讶没有numpythonic(因此更快!)方法来做到这一点......有什么想法吗?
谢谢!
我们有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])
Run Code Online (Sandbox Code Playgroud)
一会儿,让我们考虑一个排序的版本reference——
In [373]: np.sort(reference)
Out[373]: array([10, 20, 30])
Run Code Online (Sandbox Code Playgroud)
现在,我们可以使用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)
Run Code Online (Sandbox Code Playgroud)
如果我们运行原始代码,预期的输出结果是 -
In [379]: indexes
Out[379]: array([2, 0, 2, 1, 0, 1, 0, 1, 2, 0, 0, 2, 2, 1, 2])
Run Code Online (Sandbox Code Playgroud)
可以看出,searchsorted输出很好,除了0'sin 必须是1s并且1's必须更改为0's。现在,我们已经考虑到计算, 的排序版本reference。因此,要进行0'sto1'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]
Run Code Online (Sandbox Code Playgroud)
运行时测试 -
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
Run Code Online (Sandbox Code Playgroud)
验证结果 -
In [399]: np.array_equal(org_approach(data,reference),vect_approach(data,reference))
Out[399]: True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4097 次 |
| 最近记录: |