在numpy中创建倾斜/连续移动矩阵的最快方法

在numpy中创建倾斜/连续移动矩阵的最快方法,numpy,optimization,python-3.6,Numpy,Optimization,Python 3.6,我需要创建一个(w,N)-矩阵,如下所示: w//2............N-1,N-1 . \ N-1 . \ N-1 . \ N-1 1...............N-1,N-1 0...................N-1 00..................N-2 . \ N-3 . \ . . \

我需要创建一个(w,N)-矩阵,如下所示:

w//2............N-1,N-1
.             \     N-1
.              \    N-1
.               \   N-1
1...............N-1,N-1
0...................N-1
00..................N-2
. \                 N-3
.  \                .
.   \               .
000000..............N-w//2
这是一个(w,N)矩阵,有一个奇数w。中行是从0到N的范围。对于中行上方的每一行索引,该行将按相同的方法向左移动,对于中行下方的每一行,该行将按相同的方法向右移动

N通常在10^4左右,w通常在10到10^2之间

我想出了两种方法:

from scipy.ndimage import shift
middle = np.arange(0, N)
final = np.vstack(
    [shift(middle, i, mode='nearest') for i in range(-w//2, 0)] + 
    [middle] + 
    [shift(middle, i, mode='nearest') for i in range(1, w//2)] ) 
这需要
0.035
秒才能运行

np.vstack([
        np.maximum(
            0,
            np.minimum(
                N-1,
                np.arange(-step, N-step)
            )
        )
        for step in range(-w//2, w//2)
    ])
这需要
0.021
秒才能运行

np.vstack([
        np.maximum(
            0,
            np.minimum(
                N-1,
                np.arange(-step, N-step)
            )
        )
        for step in range(-w//2, w//2)
    ])
这些数字分别为N=10^3和w=21

我真的很想把这些数字降到尽可能低的水平,最好降到1ms左右

我尝试了多处理,但这并没有真正起到作用,开销太大,无法从并发中获得一些东西。我也知道我可以把这个结果存储在某个地方,但是这需要这个函数的调用者进行重大的更改,所以这将在以后完成

是否有任何数学关系可以表示这样的倾斜/移位操作?我想不出一个,但如果有,numpy可能会利用这个优势击败我的成绩


那么,是的,有什么办法让我的代码更快吗?

用适当的形状和水平值从
0
N
(包括)初始化一个数组

w,N=11,10
arr=np.empty(shape=[w,N],dtype=int)
arr[:]=np.arange(N)
啊
>>>   [[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]]
从每行中减去一个适当的值

arr += np.arange(w).reshape([-1, 1])[::-1] - (1+w//2)
arr

>>>   [[ 5.,  6.,  7.,  8.,  9., 10., 11., 12., 13., 14.],
       [ 4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13.],
       [ 3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.],
       [ 2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11.],
       [ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.],
       [ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.],
       [-1.,  0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.],
       [-2., -1.,  0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.],
       [-3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.,  6.],
       [-4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.],
       [-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.]]
如果值与限制值交叉,则重新为其指定限制值

arr[arr<0] = 0
arr[arr>N-1] = N-1

arr

>>>   [[5., 6., 7., 8., 9., 9., 9., 9., 9., 9.],
       [4., 5., 6., 7., 8., 9., 9., 9., 9., 9.],
       [3., 4., 5., 6., 7., 8., 9., 9., 9., 9.],
       [2., 3., 4., 5., 6., 7., 8., 9., 9., 9.],
       [1., 2., 3., 4., 5., 6., 7., 8., 9., 9.],
       [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
       [0., 0., 1., 2., 3., 4., 5., 6., 7., 8.],
       [0., 0., 0., 1., 2., 3., 4., 5., 6., 7.],
       [0., 0., 0., 0., 1., 2., 3., 4., 5., 6.],
       [0., 0., 0., 0., 0., 1., 2., 3., 4., 5.],
       [0., 0., 0., 0., 0., 0., 1., 2., 3., 4.]]
arr[arrN-1]=N-1
啊
>>>   [[5., 6., 7., 8., 9., 9., 9., 9., 9., 9.],
[4., 5., 6., 7., 8., 9., 9., 9., 9., 9.],
[3., 4., 5., 6., 7., 8., 9., 9., 9., 9.],
[2., 3., 4., 5., 6., 7., 8., 9., 9., 9.],
[1., 2., 3., 4., 5., 6., 7., 8., 9., 9.],
[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],
[0., 0., 1., 2., 3., 4., 5., 6., 7., 8.],
[0., 0., 0., 1., 2., 3., 4., 5., 6., 7.],
[0., 0., 0., 0., 1., 2., 3., 4., 5., 6.],
[0., 0., 0., 0., 0., 1., 2., 3., 4., 5.],
[0., 0., 0., 0., 0., 0., 1., 2., 3., 4.]]
编辑

我试着给脚本计时

import timeit

script = '''
w, N   = 21, 10**3
arr    = np.empty(shape= [w, N], dtype= int)
arr[:] = np.arange(N)
arr   += np.arange(w).reshape([-1, 1])[::-1] - (1+w//2)

arr[arr<0] = 0
arr[arr>N-1] = N-1
'''

time = timeit.timeit(script, number= 100000, setup= 'import numpy as np') / 100000

time

>>> 0.00019059010320999733    # 0.19 ms
import timeit
脚本=“”
w、 N=21,10**3
arr=np.empty(shape=[w,N],dtype=int)
arr[:]=np.arange(N)
arr+=np.arange(w).重塑([-1,1])[::-1]-(1+w//2)
arr[arrN-1]=N-1
'''
time=timeit.timeit(脚本,编号=100000,安装程序='importnumpyasnp')/100000
时间
>>>0.0001905901032099733#0.19毫秒

一个非常好的方法。我希望它比实际移动数组更快。@TlsChris我已经对脚本进行了基准测试。另外,如果我的回答有帮助,请点击“向上投票”按钮旁边的“勾号”接受我的回答。我已经向上投票了,但无法接受,因为我没有问这个问题。您的方法很容易理解和维护。@TlsChris oops my bad:py您的解决方案速度稍慢,平均
0.022
秒,但我确实同意,它看起来很适合维护。