用于生成 NumPy 矩阵的矢量化解决方案
Vectorized solution for generating NumPy matrix
我正在寻找一些内置的 NumPy 模块或一些矢量化方法来通过 n
矩阵为 n>1
获得这样的 n
。这里唯一的关键是给定行的最后一个元素作为下一行的第一个元素。
n = 2
# array([[1, 2],
# [2, 3]])
n = 3
# array([[1, 2, 3],
# [3, 4, 5],
# [5, 6, 7]])
n = 4
# array([[1, 2, 3, 4],
# [4, 5, 6, 7],
# [7, 8, 9, 10],
# [10, 11, 12, 13]])
我尝试 使用列表解析。也可以用扩展的 for 循环语法编写相同的内容。
import numpy as np
n = 4
arr = np.array([[(n-1)*j+i for i in range(1, n+1)] for j in range(n)])
# array([[ 1, 2, 3, 4],
# [ 4, 5, 6, 7],
# [ 7, 8, 9, 10],
# [10, 11, 12, 13]])
方法 #1
我们可以利用 np.lib.stride_tricks.as_strided
based scikit-image's view_as_windows
to get sliding windows. .
此外,它接受一个 step
参数,这非常适合这个问题。因此,实施将是 -
from skimage.util.shape import view_as_windows
def ranged_mat(n):
r = np.arange(1,n*(n-1)+2)
return view_as_windows(r,n,step=n-1)
样品运行 -
In [270]: ranged_mat(2)
Out[270]:
array([[1, 2],
[2, 3]])
In [271]: ranged_mat(3)
Out[271]:
array([[1, 2, 3],
[3, 4, 5],
[5, 6, 7]])
In [272]: ranged_mat(4)
Out[272]:
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10],
[10, 11, 12, 13]])
方法 #2
另一个 outer-broadcasted-addition
-
def ranged_mat_v2(n):
r = np.arange(n)
return (n-1)*r[:,None]+r+1
方法 #3
我们还可以使用支持multi-core处理的numexpr
module,从而在大型n's
-
上获得更好的效率
import numexpr as ne
def ranged_mat_v3(n):
r = np.arange(n)
r2d = (n-1)*r[:,None]
return ne.evaluate('r2d+r+1')
利用切片为我们提供了更多 memory-efficient -
def ranged_mat_v4(n):
r = np.arange(n+1)
r0 = r[1:]
r1 = r[:-1,None]*(n-1)
return ne.evaluate('r0+r1')
计时 -
In [423]: %timeit ranged_mat(10000)
273 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [424]: %timeit ranged_mat_v2(10000)
316 ms ± 2.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [425]: %timeit ranged_mat_v3(10000)
176 ms ± 85.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [426]: %timeit ranged_mat_v4(10000)
154 ms ± 82.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
还有np.fromfunction如下。 docs here
def func(n):
return np.fromfunction(lambda r,c: (n-1)*r+1+c, shape=(n,n))
它需要一个根据索引值计算数组的函数。
如果你想让事情变得简单(并且有点可读性),应该这样做:
def ranged_mat(n):
out = np.arange(1, n ** 2 + 1).reshape(n, n)
out -= np.arange(n).reshape(n, 1)
return out
只需构建从 1 到 n² 的所有数字,将它们重新整形为所需的块形状,然后从每一行中减去行号。
这与 Divakar 的 ranged_mat_v2
相同,但我喜欢明确显示中间数组形状。不是每个人都是 NumPy 广播规则的专家。
为此我们可以使用 NumPy strides
:
def as_strides(n):
m = n**2 - (n-1)
a = np.arange(1, m+1)
s = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(n,n), strides=((n-1)*s,s))
as_strides(2)
rray([[1, 2],
[2, 3]])
as_strides(3)
array([[1, 2, 3],
[3, 4, 5],
[5, 6, 7]])
as_strides(4)
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10],
[10, 11, 12, 13]])
我正在寻找一些内置的 NumPy 模块或一些矢量化方法来通过 n
矩阵为 n>1
获得这样的 n
。这里唯一的关键是给定行的最后一个元素作为下一行的第一个元素。
n = 2
# array([[1, 2],
# [2, 3]])
n = 3
# array([[1, 2, 3],
# [3, 4, 5],
# [5, 6, 7]])
n = 4
# array([[1, 2, 3, 4],
# [4, 5, 6, 7],
# [7, 8, 9, 10],
# [10, 11, 12, 13]])
我尝试 使用列表解析。也可以用扩展的 for 循环语法编写相同的内容。
import numpy as np
n = 4
arr = np.array([[(n-1)*j+i for i in range(1, n+1)] for j in range(n)])
# array([[ 1, 2, 3, 4],
# [ 4, 5, 6, 7],
# [ 7, 8, 9, 10],
# [10, 11, 12, 13]])
方法 #1
我们可以利用 np.lib.stride_tricks.as_strided
based scikit-image's view_as_windows
to get sliding windows.
此外,它接受一个 step
参数,这非常适合这个问题。因此,实施将是 -
from skimage.util.shape import view_as_windows
def ranged_mat(n):
r = np.arange(1,n*(n-1)+2)
return view_as_windows(r,n,step=n-1)
样品运行 -
In [270]: ranged_mat(2)
Out[270]:
array([[1, 2],
[2, 3]])
In [271]: ranged_mat(3)
Out[271]:
array([[1, 2, 3],
[3, 4, 5],
[5, 6, 7]])
In [272]: ranged_mat(4)
Out[272]:
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10],
[10, 11, 12, 13]])
方法 #2
另一个 outer-broadcasted-addition
-
def ranged_mat_v2(n):
r = np.arange(n)
return (n-1)*r[:,None]+r+1
方法 #3
我们还可以使用支持multi-core处理的numexpr
module,从而在大型n's
-
import numexpr as ne
def ranged_mat_v3(n):
r = np.arange(n)
r2d = (n-1)*r[:,None]
return ne.evaluate('r2d+r+1')
利用切片为我们提供了更多 memory-efficient -
def ranged_mat_v4(n):
r = np.arange(n+1)
r0 = r[1:]
r1 = r[:-1,None]*(n-1)
return ne.evaluate('r0+r1')
计时 -
In [423]: %timeit ranged_mat(10000)
273 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [424]: %timeit ranged_mat_v2(10000)
316 ms ± 2.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [425]: %timeit ranged_mat_v3(10000)
176 ms ± 85.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [426]: %timeit ranged_mat_v4(10000)
154 ms ± 82.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
还有np.fromfunction如下。 docs here
def func(n):
return np.fromfunction(lambda r,c: (n-1)*r+1+c, shape=(n,n))
它需要一个根据索引值计算数组的函数。
如果你想让事情变得简单(并且有点可读性),应该这样做:
def ranged_mat(n):
out = np.arange(1, n ** 2 + 1).reshape(n, n)
out -= np.arange(n).reshape(n, 1)
return out
只需构建从 1 到 n² 的所有数字,将它们重新整形为所需的块形状,然后从每一行中减去行号。
这与 Divakar 的 ranged_mat_v2
相同,但我喜欢明确显示中间数组形状。不是每个人都是 NumPy 广播规则的专家。
为此我们可以使用 NumPy strides
:
def as_strides(n):
m = n**2 - (n-1)
a = np.arange(1, m+1)
s = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(n,n), strides=((n-1)*s,s))
as_strides(2)
rray([[1, 2],
[2, 3]])
as_strides(3)
array([[1, 2, 3],
[3, 4, 5],
[5, 6, 7]])
as_strides(4)
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10],
[10, 11, 12, 13]])