numpy 的一般概念是 “无循环” 我想展示一下它是如何实现的
可以在没有任何(显式)的情况下执行 OP 提出的任务
循环。
我们将使用numpy 的扩展寻址功能
让它以自己的速度处理数据操作细节。
举个例子,我需要一些data 和一个列表,或者
向量,这里命名为persisting,对应于这些索引的索引
要求在修改后的 data 数组中保留的值
我们的程序结束。
import numpy as np
data = np.arange(10)
persisting = [4,8,1,0]
鉴于这些预备,我们可以计算出一个held 数组,它包含
我们想要持久化的所有data 元素,indexing the data
array using the persisting
array
held = data[persisting]
data 数组可以使用全速填充零
数组法
.fill()
最终保存在held 中的元素可以恢复到它们的
原来的地方,再次使用扩展寻址,这次在左边
的任务。
data.fill(0)
data[persisting] = held
print(data) #>>> [0 1 0 0 4 0 0 0 8 0]
上面概述的过程可能会也可能不会比其他程序更快
方法取决于您正在操作的数组的 len()
以及分别有多少是零填充而不是
保持之前的值。如果您的问题是生产问题
考虑对您使用过的各种方法进行基准测试
建议。
基准测试
我已经对接受的答案和我的方法中提出的方法进行了计时。以下是记录我的过程的 IPython 会话记录。
打印的结果是数据数组的长度、索引数组的长度、用于执行这两个函数中的每一个的时间(以秒为单位)(平均超过 7 次重复)。
In [38]: import numpy as np
In [39]: def accepted(A, I):
...: good_elements_indices = I
...: all_elements = A
...: for all_elements_index in range(len(all_elements)):
...: if all_elements_index not in good_elements_indices:
...: A[all_elements_index] = 0.0
...:
In [40]: def alternate(a, i):
...: held = a[i]
...: a.fill(0.0)
...: a[i] = held
...:
In [41]: for length in (100, 10000, 1000000):
...: a = np.arange(length)
...: for remain in (10, 100, 10000, length//2):
...: if remain < length:
...: i = np.random.choice(length, remain)
...: acc_t = %timeit -q -o accepted(a, i)
...: alt_t = %timeit -q -o alternate(a, i)
...: print('%10d, %10d: %e, %e;'%(
...: length, remain, acc_t.average, alt_t.average))
...:
100, 10: 1.506336e-04, 1.126085e-06;
100, 50: 1.663167e-04, 1.385859e-06;
10000, 10: 1.539412e-02, 5.308621e-06;
10000, 100: 2.198021e-02, 6.056105e-06;
10000, 5000: 2.995333e-01, 3.775863e-05;
1000000, 10: 1.524685e+00, 1.596268e-03;
1000000, 100: 2.187460e+00, 1.599069e-03;
1000000, 10000: 7.067548e+01, 1.770094e-03;
^C---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
请注意,我不得不中断计时过程,因为%timeit 计算了七次重复的平均值,这意味着最后一行需要超过 8 分钟才能完成...
我不得不说可以很容易地加快接受的答案,但我认为必须处理循环和测试它会更慢。