我尝试使用numpy.fill_diagonal函数用2D数组的值填充3D NumPy数组。这两个数组具有相同的行数和列数。但是,它会导致错误ValueError: All dimensions of input must be of equal length
下面是一个例子,我试图做什么,我期望有
A = [[[0 1 1 1]
[1 0 1 1]
[1 1 0 1]
[1 1 1 0]]
[[0 1 1 1]
[1 0 1 1]
[1 1 0 1]
[1 1 1 0]]]
B = [[1 4 2 3]
[3 1 4 2]]
# Actual array shapes
A.shape (35,4,4)
B.shape (35,4)
numpy.fill_diagonal(A, B)
Expected result:
[[[1 1 1 1]
[1 4 1 1]
[1 1 2 1]
[1 1 1 3]]
[[3 1 1 1]
[1 1 1 1]
[1 1 4 1]
[1 1 1 2]]]
字符串
我已尝试将2D阵列重塑为3D形状,如下所示
numpy.fill_diagonal(A, B[:,:,numpy.newaxis])
型
但我还是得到了同样的错误
2条答案
按热度按时间0s7z1bwu1#
fill_diagonal
介绍了如何使用diag_indices
。具体来说,np.diag_indices(3,ndim=3)
为它设置的3个diag值生成3d索引。让我们来看看2D索引:
字符串
然后使用3D数组:
型
选择(3,3)块。然后用a(3,3)设置它们:
型
这就是你想要的对角线填充模式。
仔细阅读
fill_diagonal
等函数的文档。如果有令人困惑的部分,请查看它是用Python编写的,这样您就可以更好地了解它在做什么。8nuwlpux2#
另一种方法,没有花哨的索引,但与大步发挥。
字符串
棘手的部分显然是
DiagA=...
行。但它值得理解,因为当你理解它的作用时,它经常会有帮助。这是创建A的视图(因此与A的数据相同),形状以B的形状开始(因此3,3)。和使用给定步幅访问其元素。ND数组
arr
的步幅是元组(s1,s2,...,sN),例如元素arr[i1,i2,...,iN]
的地址是arr[0,0,...0]
+i1*s1+i2*s2+...+iN*sN
的地址。所以
A
的跨距(s1,s2,s3)是这样的:A[i,j,k]
的地址是第一个元素A[0,0,0]
+i*s1+j*s2+k*s3
的地址。而(s1 ′,s2 ′)视图
DiagA
的跨距如DiagA[i,j]
的地址是DiagA[0,0]
+s1'*i+s2'*j
的地址。在这里,我调整了步幅,使s1'=s1
和s2'=s2+s3
。所以Diag[i,j]
的地址是Diag[0,0]
+s1*i+s2*j+s3*j
的地址。这种情况发生,因为它是相同的数据(相同的[0...0]
元素,也是A[i,j,j]
的地址。所以
DiagA[i,j]
只是A[i,j,j]
的视图。这个视图是读写的。所以我可以用
DiagA[:]=B
来修改那些A[i,j,j]
。它的美妙之处在于,它不需要任何成本(当然,
DiagA[:]=B
的成本是在另一个2D数组上复制2D数组的成本)。但是DiagA
的创建本身并没有花费任何成本。没有内存,也没有CPU(或几乎如此)。这只是步幅的一个调整,元数据的一个或两个变化,仅此而已。Tbh,它需要真正的大数组才值得。Hpaulj的方法对于3x3x3数组快两倍。对于100x100x100阵列,情况大致相同。只有使用200x200x200阵列,我的方法才能达到更快的速度(90 μs vs 120 μs)。当你仔细想想,这两个都是非常快的,考虑到我们谈论的是8000000个元素的数组。因为两者,本质上只是处理它们的40000个元素的副本)