我想用构造对称矩阵。
r=np.arange(0,11)
k=np.zeros((11,11))
for i in r:
k[i]=np.arange(i,i-11,-1)
如何摆脱for循环以更有效地构建矩阵?
答案 0 :(得分:1)
您可以这样做:
k = np.arange(0, 11)[:, np.newaxis] + np.arange(0, -11, -1)
print(k)
输出:
[[ 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10]
[ 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9]
[ 2 1 0 -1 -2 -3 -4 -5 -6 -7 -8]
[ 3 2 1 0 -1 -2 -3 -4 -5 -6 -7]
[ 4 3 2 1 0 -1 -2 -3 -4 -5 -6]
[ 5 4 3 2 1 0 -1 -2 -3 -4 -5]
[ 6 5 4 3 2 1 0 -1 -2 -3 -4]
[ 7 6 5 4 3 2 1 0 -1 -2 -3]
[ 8 7 6 5 4 3 2 1 0 -1 -2]
[ 9 8 7 6 5 4 3 2 1 0 -1]
[ 10 9 8 7 6 5 4 3 2 1 0]]
但是请注意,此矩阵不是对称的,而是antisymmetric。
另一个获得相同结果但使用更少内存的高级选项是创建一个数字从10到-10的数组,并在每一行上“滚动”遍历:
import numpy as np
def make_matrix(n):
r = np.arange(n, -(n + 1), -1)
s, = r.strides
m = np.ndarray(shape=(n + 1, n + 1),
dtype=r.dtype,
buffer=r.data,
offset=s * n,
strides=(-s, s),
order='C')
# Avoid writing since it is not a contiguous array
m.flags.writeable = False
return m
print(make_matrix(10))
# Same output
这仅占用第一个数组的内存,而不是连续矩阵的二次大小。
编辑:
如果要创建对称矩阵,则可以采用绝对值:
k = np.abs(np.arange(0, 11)[:, np.newaxis] + np.arange(0, -11, -1))
或者您可以像上面那样稍微修改上面的功能:
import numpy as np
def make_matrix(n):
a = np.arange(n + 1)
r = np.concatenate([a[::-1], a[1:]])
s, = r.strides
m = np.ndarray(shape=(n + 1, n + 1),
dtype=r.dtype,
buffer=r.data,
offset=s * n,
strides=(-s, s),
order='C')
m.flags.writeable = False
return m
print(make_matrix(10))
输出:
[[ 0 1 2 3 4 5 6 7 8 9 10]
[ 1 0 1 2 3 4 5 6 7 8 9]
[ 2 1 0 1 2 3 4 5 6 7 8]
[ 3 2 1 0 1 2 3 4 5 6 7]
[ 4 3 2 1 0 1 2 3 4 5 6]
[ 5 4 3 2 1 0 1 2 3 4 5]
[ 6 5 4 3 2 1 0 1 2 3 4]
[ 7 6 5 4 3 2 1 0 1 2 3]
[ 8 7 6 5 4 3 2 1 0 1 2]
[ 9 8 7 6 5 4 3 2 1 0 1]
[10 9 8 7 6 5 4 3 2 1 0]]
关于性能,在这种情况下,您可以进行连续和不连续两种测试:
import numpy as np
def make_matrix_cont(n):
return np.abs(np.arange(0, n + 1)[:, np.newaxis] + np.arange(0, -(n + 1), -1))
def make_matrix_noncont(n):
a = np.arange(n + 1)
r = np.concatenate([a[::-1], a[1:]])
s, = r.strides
m = np.ndarray(shape=(n + 1, n + 1), dtype=r.dtype, buffer=r.data, offset=s * n, strides=(-s, s), order='C')
m.flags.writeable = False
return m
n = 1000
k_cont = make_matrix_cont(n)
k_noncont = make_matrix_noncont(n)
print(np.all(k_cont == k_noncont))
# True
%timeit make_matrix_cont(n)
# 3.48 ms ± 42.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit make_matrix_noncont(n)
# 5.2 µs ± 11.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit k_cont.sum()
# 317 µs ± 4.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit k_noncont.sum()
# 370 µs ± 1.59 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit k_cont @ k_cont
# 313 ms ± 3.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit k_noncont @ k_noncont
# 417 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
因此,除了占用更少的空间外,非连续矩阵的创建也要快得多,但是将其元素求和要慢一些,而矩阵乘法要多一些。
答案 1 :(得分:0)
您可以在一个衬里中创建阵列。
np.fromfunction(lambda r,c: r-c, (11,11))
结果:
array([[ 0., -1., -2., -3., -4., -5., -6., -7., -8., -9., -10.],
[ 1., 0., -1., -2., -3., -4., -5., -6., -7., -8., -9.],
[ 2., 1., 0., -1., -2., -3., -4., -5., -6., -7., -8.],
[ 3., 2., 1., 0., -1., -2., -3., -4., -5., -6., -7.],
[ 4., 3., 2., 1., 0., -1., -2., -3., -4., -5., -6.],
[ 5., 4., 3., 2., 1., 0., -1., -2., -3., -4., -5.],
[ 6., 5., 4., 3., 2., 1., 0., -1., -2., -3., -4.],
[ 7., 6., 5., 4., 3., 2., 1., 0., -1., -2., -3.],
[ 8., 7., 6., 5., 4., 3., 2., 1., 0., -1., -2.],
[ 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., -1.],
[ 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]])
数组中的每个单元格是行号减去列号。第一个参数是一个以行和列为参数的函数。第二个是所需的形状。