numpy 多维度连续对角线值

zc0qhyus  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(99)

在投影之后,我需要在1D数组的基础上创建一个具有连续对角线值的multidim数组,例如用一个多维恒等数组进行乘法运算以下只是该概念的一个小示例。由于来自投影结果的真实的数据将比以下12个值大得多,因此我需要一种有效的数据处理方法。(投影问题:原始的“紧凑”轴不能再使用,但数据值仍然相同)
输入:

>>> a=np.arange(1,13)
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])

>>>a.shape
(12,)

字符串
所需输出:

array([[[ 1.,  0.,  0.,  0.],
        [ 0.,  2.,  0.,  0.],
        [ 0.,  0.,  3.,  0.],
        [ 0.,  0.,  0.,  4.]],

       [[ 5.,  0.,  0.,  0.],
        [ 0.,  6.,  0.,  0.],
        [ 0.,  0.,  7.,  0.],
        [ 0.,  0.,  0.,  8.]],

       [[ 9.,  0.,  0.,  0.],
        [ 0., 10.,  0.,  0.],
        [ 0.,  0., 11.,  0.],
        [ 0.,  0.,  0., 12.]]])
shape: (3, 4, 4)


我无法找到一个解决方案,试图使用以下单位矩阵:

>>> np.tile(np.identity(4),(3,1)).reshape(3,4,4)
array([[[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.],
        [0., 0., 0., 1.]],

       [[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.],
        [0., 0., 0., 1.]],

       [[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.],
        [0., 0., 0., 1.]]])

w3nuxt5m

w3nuxt5m1#

虽然有像np.diag这样的函数来制作对角线,但它们都是针对2d的。
下面的代码有点绕圈子,但应该可以快速工作:

res=np.eye(4)[None].repeat(3,axis=0)
res[np.nonzero(res)]=np.arange(1,13)

repr(res) 
array([[[ 1.,  0.,  0.,  0.],
        [ 0.,  2.,  0.,  0.],
        [ 0.,  0.,  3.,  0.],
        [ 0.,  0.,  0.,  4.]],

       [[ 5.,  0.,  0.,  0.],
        [ 0.,  6.,  0.,  0.],
        [ 0.,  0.,  7.,  0.],
        [ 0.,  0.,  0.,  8.]],

       [[ 9.,  0.,  0.,  0.],
        [ 0., 10.,  0.,  0.],
        [ 0.,  0., 11.,  0.],
        [ 0.,  0.,  0., 12.]]])

字符串
另一个是一个有点疯狂的猜测,但工作:

In [123]: arr = np.diag(np.arange(1,13))
In [124]: arr.shape
Out[124]: (12, 12)
In [125]: arr.reshape(3,4,3,4)[np.arange(3),:,np.arange(3),:]
Out[125]: 
array([[[ 1,  0,  0,  0],
        [ 0,  2,  0,  0],
        [ 0,  0,  3,  0],
        [ 0,  0,  0,  4]],

       [[ 5,  0,  0,  0],
        [ 0,  6,  0,  0],
        [ 0,  0,  7,  0],
        [ 0,  0,  0,  8]],

       [[ 9,  0,  0,  0],
        [ 0, 10,  0,  0],
        [ 0,  0, 11,  0],
        [ 0,  0,  0, 12]]])
In [126]: _.shape
Out[126]: (3, 4, 4)


像这样混合基本和高级索引可以产生意想不到的形状,但这里是我希望的作品。
我尝试了flat索引和stride_tricks,但没有任何进展。问题的一部分在于这不是一条真正的对角线。
另一种方法-创建目标数组,并索引一个(3,4)块:

In [134]: res = np.zeros((3,4,4))
In [135]: res[np.arange(3)[:,None], np.arange(4), np.arange(4)] 
= np.arange(1,13).reshape(3,4)

a5g8bdjr

a5g8bdjr2#

只是添加我的。因为我想看看我是否可以使用strides_trick:D去某个地方

def mydiag(d, n, p):
    padded = np.zeros((n*p,n+1))
    padded[:,0]=d
    s1,s2=padded.strides
    return np.lib.stride_tricks.as_strided(padded, shape=(p,n,n), strides=(s1*n,s1-s2,s2))

字符串
说明:如果你看一下展平的结果,你得到的是对角线值,由n个零分隔(n是每个方阵的大小,p是方阵的个数)。因此n×p=len(d))。除了当我们改变“平面”,其中对角线值是连续的。
所以我用这些对角线值和中间的n 0构建一个数组(我可以用np.pad来做,但它比只填充np.zeros要慢)。
然后,我调整strides,使它为每个矩阵的每一行移动一个元素。
4x 3案例的一些时序
| - |方法学|定时||hpaulj的第一个|15.84 μs||hpaulj的第二个|16.27 μs||hpaulj的第三|11.44 μs||杰瑞德的|25.87 μs||我的|17.74 μs| Mine | 17.74 μs |
所以很明显,对于3x 4的情况,这不是很有趣。
对大案子来说更有意思
| 方法| method |
| --| ------------ |
| 602毫秒| 602 ms |
| 崩溃(内存)| crashes (memory) |
| 192毫秒| 192 ms |
| 347毫秒| 347 ms |
| 168毫秒| 168 ms |
尽管如此,即使这种情况下,它不是粉碎hpaulj的第三,这似乎是有最好的时机或几乎如此,无论是在小的和大的情况下。在某些运行中,时间是颠倒的。所以对我来说,这甚至不是一个明显的胜利,对于大案子。无论如何,这不是一个O(...)的差异。显然,数据的大小越大,差异就越可以忽略不计,因为过了一段时间,对于两种方法来说,它只是n×p值的副本。
但是,好吧,它是一种使用as_strided的方法,它并不比其他方法更差,时间方面。
(我不认为我们可以使用as_strided,同时避免在这里花费我的时间,即创建填充矩阵:无论如何,我们需要从某个地方得到这些0,因为as_strided只能重新安排数据的迭代方式,但不能创建这些0。当然,它可以“复制”它们,但也不能不复制非零)

rqqzpn5f

rqqzpn5f3#

利用你开始的内容,我们可以将每个内部数组与所需的值相乘。要做到这一点,我们需要将乘法数组整形为兼容的形状。

import numpy as np

a = np.tile(np.identity(4),(3,1)).reshape(3,4,4)
b = np.arange(1,13).reshape(a.shape[:2])[:,None,:]
a *= b
print(a)

字符串
输出量:

[[[ 1.  0.  0.  0.]
  [ 0.  2.  0.  0.]
  [ 0.  0.  3.  0.]
  [ 0.  0.  0.  4.]]

 [[ 5.  0.  0.  0.]
  [ 0.  6.  0.  0.]
  [ 0.  0.  7.  0.]
  [ 0.  0.  0.  8.]]

 [[ 9.  0.  0.  0.]
  [ 0. 10.  0.  0.]
  [ 0.  0. 11.  0.]
  [ 0.  0.  0. 12.]]]

相关问题