15 votes

Créer une matrice diagonale spéciale dans Numpy

J'essaie de créer un tableau numpy qui ressemble à ceci :

[a b c       ]
[  a b c     ]
[    a b c   ]
[      a b c ] 

Il s'agit donc de mettre à jour la diagonale principale et les deux diagonales situées au-dessus.

Quel serait le moyen le plus efficace de le faire ?

23voto

Saullo Castro Points 12260

Vous pouvez utiliser np.indices pour obtenir les indices de votre tableau et ensuite assigner les valeurs où vous voulez.

a = np.zeros((5,10))
i,j = np.indices(a.shape)

i,j sont les indices de ligne et de colonne, respectivement.

a[i==j] = 1.
a[i==j-1] = 2.
a[i==j-2] = 3.

aura pour résultat :

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

8voto

ali_m Points 7185

Il s'agit d'un exemple de Matrice Toeplitz - vous pouvez le construire en utilisant scipy.linalg.toeplitz :

import numpy as np
from scipy.linalg import toeplitz

first_row = np.array([1, 2, 3, 0, 0, 0])
first_col = np.array([1, 0, 0, 0])

print(toeplitz(first_col, first_row))
# [[1 2 3 0 0 0]
#  [0 1 2 3 0 0]
#  [0 0 1 2 3 0]
#  [0 0 0 1 2 3]]

4voto

unutbu Points 222216
import numpy as np

def using_tile_and_stride():
    arr = np.tile(np.array([10,20,30,0,0,0], dtype='float'), (4,1))
    row_stride, col_stride = arr.strides
    arr.strides = row_stride-col_stride, col_stride
    return arr

In [108]: using_tile_and_stride()
Out[108]: 
array([[ 10.,  20.,  30.,   0.,   0.,   0.],
       [  0.,  10.,  20.,  30.,   0.,   0.],
       [  0.,   0.,  10.,  20.,  30.,   0.],
       [  0.,   0.,   0.,  10.,  20.,  30.]])

D'autres solutions, plus lentes, existent :

import numpy as np

import numpy.lib.stride_tricks as stride

def using_put():
    arr = np.zeros((4,6), dtype='float')
    a, b, c = 10, 20, 30
    nrows, ncols = arr.shape
    ind = (np.arange(3) + np.arange(0,(ncols+1)*nrows,ncols+1)[:,np.newaxis]).ravel()
    arr.put(ind, [a, b, c])
    return arr

def using_strides():
    return np.flipud(stride.as_strided(
        np.array([0, 0, 0, 10, 20, 30, 0, 0, 0], dtype='float'), 
        shape=(4, 6), strides = (8, 8)))

Si vous utilisez using_tile_and_stride Notez que le tableau n'est approprié que pour la lecture seule. Sinon, si vous essayez de modifier le tableau, vous pourriez être surpris de voir que plusieurs emplacements du tableau changent simultanément :

In [32]: arr = using_tile_and_stride()

In [33]: arr[0, -1] = 100

In [34]: arr
Out[34]: 
array([[  10.,   20.,   30.,    0.,  100.],
       [ 100.,   10.,   20.,   30.,    0.],
       [   0.,    0.,   10.,   20.,   30.],
       [  30.,    0.,    0.,   10.,   20.]])

Vous pouvez contourner ce problème en renvoyant np.ascontiguousarray(arr) au lieu de simplement arr mais alors using_tile_and_stride serait plus lent que using_put . Donc si vous avez l'intention de modifier le tableau, using_put serait un meilleur choix.

1voto

Je ne peux pas encore commenter, mais je veux signaler que la réponse d'ali_m est de loin la plus efficace car scipy prend soin des choses pour vous.

Par exemple, avec une matrice de taille n,m = 1200 en ajoutant à plusieurs reprises np.diag() les appels prennent ~6.14s La réponse de Saullo G. P. Castro est la suivante ~7.7s et scipy.linalg.toeplitz(np.arange(N), np.arange(N)) prend 1.57ms .

0voto

IanH Points 1587

En utilisant ma réponse à cette question : changer les valeurs de la diagonale d'une matrice en numpy vous pouvez faire des coupes délicates pour obtenir une vue de chaque diagonale, puis faire le travail. Dans ce cas, ce serait juste :

import numpy as np
A = np.zeros((4,6))
# main diagonal
A.flat[:A.shape[1]**2:A.shape[1]+1] = a
# first superdiagonal
A.flat[1:max(0,A.shape[1]-1)*A.shape[1]:A.shape[1]+1] = b
# second superdiagonal
A.flat[2:max(0,A.shape[1]-2)*A.shape[1]:A.shape[1]+1] = c

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X