在2D numpy数组中对角插入元素的最快方法是什么?

时间:2016-01-06 18:29:02

标签: python numpy matrix diagonal

假设我们有一个2D numpy数组,如:

matrix = [[0, 1, 2, 3],
          [4, 0, 5, 6],
          [7, 8, 0, 9],
          [10, 11, 12, 0]]

我想在对角线插入一个值0,使其变为:

$title = new Comment("{$mysidia->input->get("user")}'s Cats");
$title->setBold(TRUE);
$title->setHeading(2);
$document->add($title);
$adoptTable = new TableBuilder("otheradopttable", 640);
$adoptTable->setAlign(new Align("center", "middle"));
$adoptTable->buildHeaders("Image", "Name", "Breed", "Play");
$stmt = $mysidia->db->select("owned_adoptables", array("aid"), "owner = '{$mysidia->input->get("user")}'");
while($id = $stmt->fetchColumn()){
    $adopt = new OwnedAdoptable($id);
    $cells = new LinkedList;
    $cells->add(new TCell(new Comment("<img src='{$adopt->getImage()}'/>")));
    $cells->add(new TCell("{$adopt->getName()}"));
    $cells->add(new TCell("{$adopt->getDescription()}"));
    $cells->add(new TCell(new Comment("<a href='http://catisserie.mysidiahost.com/levelup/click/{$adopt->getAdoptID()}'>Play</a>")));
    $adoptTable->buildRow($cells);
}
$document->add($adoptTable);

最快的方法是什么?

6 个答案:

答案 0 :(得分:3)

创建一个新的更大的矩阵,剩下的空间为零。将原始矩阵复制到子矩阵,剪辑和重塑:

matrix = numpy.array([[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9],
          [10, 11, 12]])

matrix_new = numpy.zeros((4,5))
matrix_new[:-1,1:] = matrix.reshape(3,4)
matrix_new = matrix_new.reshape(-1)[:-4].reshape(4,4)

或以更一般化的形式:

matrix = numpy.array([[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9],
          [10, 11, 12]])

d = matrix.shape[0]
assert matrix.shape[1] == d - 1
matrix_new = numpy.ndarray((d, d+1), dtype=matrix.dtype)
matrix_new[:,0] = 0
matrix_new[:-1,1:] = matrix.reshape((d-1, d))
matrix_new = matrix_new.reshape(-1)[:-d].reshape(d,d)

答案 1 :(得分:3)

这是一种方式(但我不能保证这是最快的方式):

In [62]: a
Out[62]: 
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

In [63]: b = np.zeros((a.shape[0], a.shape[1]+1), dtype=a.dtype)

In [64]: i = np.arange(b.shape[0])

In [65]: j = np.arange(b.shape[1])

In [66]: b[np.not_equal.outer(i, j)] = a.ravel()  # or a.flat, if a is C-contiguous

In [67]: b
Out[67]: 
array([[ 0,  1,  2,  3],
       [ 4,  0,  5,  6],
       [ 7,  8,  0,  9],
       [10, 11, 12,  0]])

适用于任何二维数组a

In [72]: a
Out[72]: 
array([[17, 18, 15, 19, 12],
       [16, 14, 11, 16, 17],
       [19, 11, 16, 11, 14]])

In [73]: b = np.zeros((a.shape[0], a.shape[1]+1), dtype=a.dtype)

In [74]: i = np.arange(b.shape[0])

In [75]: j = np.arange(b.shape[1])

In [76]: b[np.not_equal.outer(i, j)] = a.flat

In [77]: b
Out[77]: 
array([[ 0, 17, 18, 15, 19, 12],
       [16,  0, 14, 11, 16, 17],
       [19, 11,  0, 16, 11, 14]])

它有效,但我认为@Daniel的答案是要走的路。

答案 2 :(得分:1)

另一种方法,可能更慢,有追加和重塑

import numpy as np

mat = np.array(range(1,13)).reshape(4,3)
mat

array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

z=np.zeros((3,1), dtype=mat.dtype)
m3=np.append(z,mat.reshape(3,4),1)
np.append(m3,0).reshape(4,4)

array([[ 0,  1,  2,  3],
       [ 4,  0,  5,  6],
       [ 7,  8,  0,  9],
       [10, 11, 12,  0]])

答案 3 :(得分:1)

看起来你正在使用下三角形和上三角形阵列并用零对角线将它们分开。这个序列就是这样:

In [54]: A=np.arange(1,13).reshape(4,3)

目标数组,还有一列

In [55]: B=np.zeros((A.shape[0],A.shape[1]+1),dtype=A.dtype)

复制下三部分(没有对角线)

In [56]: B[:,:-1]+=np.tril(A,-1)

复制上三部分

In [57]: B[:,1:]+=np.triu(A,0)

In [58]: B
Out[58]: 
array([[ 0,  1,  2,  3],
       [ 4,  0,  5,  6],
       [ 7,  8,  0,  9],
       [10, 11, 12,  0]])

有一些np.tril_indices...函数,但它们只适用于方阵。因此,它们无法与A一起使用。

答案 4 :(得分:1)

假设你有一个p x q numpy 2d数组A,这里有一个样本,(p,q)为(3,4):

In []: A = np.arange(1,13).reshape(4,3)
In []: A
Out[]: 
array([[ 1,  2,  3],
      [ 4,  5,  6],
      [ 7,  8,  9],
      [10, 11, 12]])

Step 1:

要插入零的对角线,需要制作一个形状为p x q + 1的新的2d数组。

在此之前,我们创建一个二维数组,其列索引值为非对角元素,用于新的2d数组,如下所示

In []: columnIndexArray = np.delete(np.meshgrid(np.arange(q+1), np.arange(p))[0], np.arange(0, p * (q+1), q+2)).reshape(p,q)

以上输出如下:

In []: columnIndexArray
Out[]: 
array([[1, 2, 3],
      [0, 2, 3],
      [0, 1, 3],
      [0, 1, 2]])

Step 2:

现在像这样构造p x q + 1 2d的零数组

In []: B = np.zeros((p,q+1))

In []: B
Out[]: 
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

Step 3:

现在使用A

中的值指定非对角元素
In []: B[np.arange(p)[:,None], columnIndexArray] = A

In []: B
Out[]: 
array([[  0.,   1.,   2.,   3.],
      [  4.,   0.,   5.,   6.],
      [  7.,   8.,   0.,   9.],
      [ 10.,  11.,  12.,   0.]])

Note: 为了使你的代码动态,用A.shape [0]和q分别用A.shape [1]替换p。

答案 5 :(得分:0)

同样,我不知道它有多快,但您可以尝试使用numpy.lib.stride_tricks.as_strided

import numpy as np
as_strided = np.lib.stride_tricks.as_strided

matrix = (np.arange(12)+1).reshape((4,3))

n, m = matrix.shape
t = matrix.reshape((m, n))
t = np.hstack((np.array([[0]*m]).T, t))
t = np.vstack((t, [0]*(n+1)))
q = as_strided(t, (n,n), (t.itemsize*n, 8))
print(q)

输出:

[[ 0  1  2  3]
 [ 4  0  5  6]
 [ 7  8  0  9]
 [10 11 12  0]]

也就是说,用零填充重新形成的阵列左下角,并将左手零点放在对角线上。不幸的是,在(n+1,n)数组的情况下,你需要最后一行零来获得输出矩阵的最终零(因为例如5 * 3 = 15比一个小于4 * 4 = 16)。如果你从一个方阵开始,你可以不用这个。