Carmoreno
Carmoreno

Reputation: 1319

Special Matrix in Numpy

I want to make a numpy array that looks like this:

m = [1, 1, 1, 0, 0, 0, 0, 0, 0
     0, 0, 0, 1, 1, 1, 0, 0, 0 
     0, 0, 0, 0, 0, 0, 1, 1, 1]

I have seen this answer Make special diagonal matrix in Numpy and I have this:

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

But I want to use a 'for' cicle, How I can fill the diagonal efficiently?

Upvotes: 4

Views: 853

Answers (4)

Sohail Si
Sohail Si

Reputation: 2976

np.tile(np.eye(3, dtype=int)[:,:, np.newaxis], (1,1,3)).reshape(3,-1)

However, @joachim-isaksson's answer is slightly more compact.

Alternative solution (based on LA matrix multiplication dot function):

np.dot(np.eye(3, dtype=int)[:,:, np.newaxis], np.array([[1,1,1],])).reshape(3,-1)

Update: toeplitz() can be useful in building special matrices:

from scipy.linalg import toeplitz (np.abs((toeplitz(np.arange(12),-np.arange(12)))[1:8:3,:9])<2)*1

Upvotes: 2

percusse
percusse

Reputation: 3106

Well, just to complete the series with the obvious alternative, there is also block_diagonal:

 import numpy as np
 import scipy as sp

 sp.linalg.block_diag(*[np.ones((1,3),dtype=int)]*5)

or if you are into that kind of stuff

 sp.linalg.block_diag(*[[1]*3]*5)

Upvotes: 1

Divakar
Divakar

Reputation: 221614

If m denotes the number of 1s in a row and n the number of rows, two approaches could be listed to solve it.

Using np.kron this is straight-forward, like so -

def kron_based(m,n):
    return np.kron(np.eye(n,dtype=int), np.ones(m,dtype=int))

Using zeros initialization and filling would be -

def initialization_based(m,n):
    A = np.zeros((n,n*m),dtype=int)
    A.reshape(n,n,m)[np.eye(n,dtype=bool)] = 1
    return A

Sample run -

In [54]: m = 4 # Number of 1s in a row. Note that this is 3 for your case
    ...: n = 3 # Number of rows
    ...: 

In [55]: initialization_based(m,n)
Out[55]: 
array([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]])

In [56]: kron_based(m,n)
Out[56]: 
array([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]])

Upvotes: 5

Joachim Isaksson
Joachim Isaksson

Reputation: 180977

One way is to simply stretch an identity array horizontally;

> np.repeat(np.identity(3, dtype=int), 3, axis=1)

array([[1, 1, 1, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 1, 1, 1]])

Upvotes: 9

Related Questions