1

Is that an easier way to fill a matrix diagonal element by another whole matrix?

b = [1,2,3,4,5,6,7,8,9]
a = np.zeros((9, 9), int)
np.fill_diagonal(a, b)

I expect the result will be

[[1. 0  0  ...........0 0]
 [0. 2. 0  ...........0 0]
 [0. 0. 3. ...  0  0  0 0]
 [0. 0. 0. 4 0  0  0  0 0]
 [0. 0. 0. 0 5  0  0  0 0]
 [0. 0. 0. ...  6  0  0 0]
 [0. 0. 0. ...  0  7  0 0]
 [0. 0. 0. ...  0  0  8 0]
 [0. 0. 0. ...  0  0  0 9]]
rj487
  • 4,476
  • 6
  • 47
  • 88

4 Answers4

5

Your method does work:

import numpy as np

b = [1,2,3,4,5,6,7,8,9]
a = np.zeros((9, 9), int)

np.fill_diagonal(a, b)

An alternative:

a[np.diag_indices_from(a)] = b
iz_
  • 15,923
  • 3
  • 25
  • 40
  • `np.diag_indices(9)` will also work. Might be slightly faster (not that it's slow or anything though). – busybear Mar 02 '19 at 02:06
  • @busybear It's to be flexible and dynamic with the (possibly different) size of `a`. The performance difference is probably minuscule even if there is a difference. – iz_ Mar 02 '19 at 02:09
  • Not really arguing either is better; they are essentially the same. `np.diag_indices` also has a second argument to set the dimensions. Although I do like that it's less characters to type :D – busybear Mar 02 '19 at 02:11
1

Check

a[[np.arange(len(b))]*2]=b
a
Out[163]: 
array([[1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 2, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 3, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 4, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 5, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 6, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 7, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 8, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 9]])
BENY
  • 317,841
  • 20
  • 164
  • 234
  • 1
    Found a couple more ways here! – cs95 Mar 02 '19 at 02:17
  • 1
    @coldspeed nice dude ~ :-) – BENY Mar 02 '19 at 02:18
  • @Wen-Ben: Your suggestion `a[[np.arange(len(b))]*2]` gives me a deprecation warning - "Using a non-tuple sequence for multidimensional indexing is deprecated". One way to avoid the warning is `a[(np.arange(len(b)), np.arange(len(b)))]=b`, or even simpler - `a[(range(len(b)), range(len(b)))]=b` – fountainhead Mar 02 '19 at 04:44
1

That's one of the things numpy.diag does:

a = numpy.diag(b)
user2357112
  • 260,549
  • 28
  • 431
  • 505
1

Just for fun, np.eye with broadcasting.

np.eye(a.shape[0], dtype=int) * b

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

You can also use diagflat, if b's dimensions are > 1D

np.diagflat(b)
# np.diagflat([b])
# np.diagflat(np.array([b]))

array([[1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 2, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 3, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 4, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 5, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 6, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 7, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 8, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 9]])
cs95
  • 379,657
  • 97
  • 704
  • 746