Nær*_*een 10 python arrays optimization performance numpy
使用numpy数组,我想执行此操作:
x[1],...,x[n-1]到x[0],...,x[n-2](左移位),x[n-1] = newvalue.对于先进先出队列(仅倒置)pop(),这类似于a push(newvalue).
一个天真的实现是:x[:-1] = x[1:]; x[-1] = newvalue.
使用的另一个实现np.concatenate更慢:np.concatenate((x[1:], np.array(newvalue).reshape(1,)), axis=0).
有最快的方法吗?
L C*_* Co 15
我知道我迟到了,这个问题已经得到了满意的回答,但我只是面临着类似的情况,用于记录流数据的缓冲区。
您提到“先进后出”是一个堆栈,但您的示例演示了一个队列,因此我将分享一个不需要复制即可将新项目排队的队列解决方案。(您最终需要使用 numpy.roll 进行一份副本,以将最终数组传递给另一个函数。)
您可以使用带有指针的循环数组来跟踪尾部的位置(您将在队列中添加新项目的位置)。
如果你从这个数组开始:
x[0], x[1], x[2], x[3], x[4], x[5]
/\
tail
Run Code Online (Sandbox Code Playgroud)
如果您想删除 x[0] 并添加 x[6],您可以使用最初为数组分配的内存来完成此操作,而无需复制
x[6], x[1], x[2], x[3], x[4], x[5]
/\
tail
Run Code Online (Sandbox Code Playgroud)
等等...
x[6], x[7], x[2], x[3], x[4], x[5]
/\
tail
Run Code Online (Sandbox Code Playgroud)
每次入队时,都会将尾部向右移动一位。您可以使用模数来很好地进行此包装:new_tail = (old_tail + 1) % length。
找到队列的头部总是在尾部之后的一个位置。这可以使用相同的公式找到:head = (tail + 1) % length。
head
\/
x[6], x[7], x[2], x[3], x[4], x[5]
/\
tail
Run Code Online (Sandbox Code Playgroud)
这是我为此循环缓冲区/数组创建的类的示例:
x[0], x[1], x[2], x[3], x[4], x[5]
/\
tail
Run Code Online (Sandbox Code Playgroud)
当您必须将大量项目放入队列而不需要传递数组副本时,这比切片快几个数量级。
访问项目和替换项目的时间复杂度为 O(1)。入队和查看都是 O(1)。复制数组需要 O(n) 时间。
基准测试结果:
(thermal_venv) PS X:\win10\repos\thermal> python -m timeit -s "import benchmark_circular_buffer as bcb" "bcb.slice_and_copy()"
10 loops, best of 5: 36.7 msec per loop
(thermal_venv) PS X:\win10\repos\thermal> python -m timeit -s "import benchmark_circular_buffer as bcb" "bcb.circular_buffer()"
200000 loops, best of 5: 1.04 usec per loop
(thermal_venv) PS X:\win10\repos\thermal> python -m timeit -s "import benchmark_circular_buffer as bcb" "bcb.slice_and_copy_assignemnt()"
2 loops, best of 5: 166 msec per loop
(thermal_venv) PS X:\win10\repos\thermal> python -m timeit -r 5 -n 4 -s "import benchmark_circular_buffer as bcb" "bcb.slice_and_copy_assignemnt()"
4 loops, best of 5: 159 msec per loop
(thermal_venv) PS X:\win10\repos\thermal> python -m timeit -r 5 -n 4 -s "import benchmark_circular_buffer as bcb" "bcb.circular_buffer_assignment()"
4 loops, best of 5: 511 msec per loop
Run Code Online (Sandbox Code Playgroud)
我的 GitHub 上有一个测试脚本和一个处理 2D 数组的实现
Nær*_*een 10
经过一些实验,很明显:
nparray(numpy数组)来说,最简单快捷的方法就是切片和复制.所以解决方案是:x[:-1] = x[1:]; x[-1] = newvalue.
这是一个小基准:
>>> x = np.random.randint(0, 1e6, 10**8); newvalue = -100
>>> %timeit x[:-1] = x[1:]; x[-1] = newvalue
1000 loops, best of 3: 73.6 ms per loop
>>> %timeit np.concatenate((x[1:], np.array(newvalue).reshape(1,)), axis=0)
1 loop, best of 3: 339 ms per loop
Run Code Online (Sandbox Code Playgroud)
但是,如果您不需要快速访问数组中的所有值,而只需要快速访问第一个或最后一个值,则使用a deque更智能.
| 归档时间: |
|
| 查看次数: |
6559 次 |
| 最近记录: |