Creating a custom matrix in numpy

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

      

Hello

For my economics course, we have to create an array that looks like this. The problem is that I am an economist, not a programmer. We are using numpy in python. Our professor says college doesn't prepare us for the real world and wants us to learn programming (which is good). We cannot use any packages and must come up with original code. Does anyone know how to make this matrix. I spent several hours trying codes and browsing the internet looking for help and they were unsuccessful.

+3


source to share


7 replies


The method below fills in one diagonal at a time:

import numpy as np
x = np.zeros((4, 6), dtype=np.int)
for i, v in enumerate((6,7,8)):
    np.fill_diagonal(x[:,i:], v)

array([[6, 7, 8, 0, 0, 0],
       [0, 6, 7, 8, 0, 0],
       [0, 0, 6, 7, 8, 0],
       [0, 0, 0, 6, 7, 8]])

      

or you can make one liner:

x = [6,7,8,0,0,0]
y = np.vstack([np.roll(x,i) for i in range(4)])

      



Personally, I prefer the first one as it is easier to understand and probably faster as it doesn't create all 1D temporary arrays.

Edit:
Since a discussion of efficiency came to mind, it would be wise to run a test. I also included time in the method toeplitz

suggested by chthonicdaemon (although I personally interpreted the question to rule out this approach as it uses the package and doesn't use the source code - also, although speed is not the original question either).

import numpy as np
import timeit
import scipy.linalg as sl

def a(m, n):    
    x = np.zeros((m, m), dtype=np.int)
    for i, v in enumerate((6,7,8)):
        np.fill_diagonal(x[:,i:], v)

def b(m, n):
    x = np.zeros((n,))
    x[:3] = vals
    y = np.vstack([np.roll(x,i) for i in range(m)])

def c(m, n):
    x = np.zeros((n,))
    x[:3] = vals
    y = np.zeros((m,))
    y[0] = vals[0]
    r = sl.toeplitz(y, x)
    return r

m, n = 4, 6
print timeit.timeit("a(m,n)", "from __main__ import np, a, b, m, n", number=1000)
print timeit.timeit("b(m,n)", "from __main__ import np, a, b, m, n", number=1000)
print timeit.timeit("c(m,n)", "from __main__ import np, c, sl, m, n", number=1000)

m, n = 1000, 1006
print timeit.timeit("a(m,n)", "from __main__ import np, a, b, m, n", number=1000)
print timeit.timeit("b(m,n)", "from __main__ import np, a, b, m, n", number=1000)
print timeit.timeit("c(m,n)", "from __main__ import np, c, sl, m, n", number=100)

# which gives:
0.03525209  # fill_diagonal
0.07554483  # vstack
0.07058787  # toeplitz

0.18803215  # fill_diagonal
2.58780789  # vstack
1.57608604  # toeplitz

      

So, the first method is about 2-3x faster for small arrays and 10-20x faster for large arrays.

+4


source


This matrix is ​​called the Toeplitz matrix or constant diagonal matrix. Knowing this will lead you to scipy.linalg.toeplitz

:



import scipy.linalg
scipy.linalg.toeplitz([1, 0, 0, 0], [1, 2, 3, 0, 0, 0])

=>

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

      

+4


source


Something along the lines

import numpy as np
def createArray(theinput,rotations) :
    l = [theinput]
    for i in range(1,rotations) :
        l.append(l[i-1][:])
        l[i].insert(0,l[i].pop())
    return np.array(l)

print(createArray([1,2,3,0,0,0],4))
"""
[[1 2 3 0 0 0]
 [0 1 2 3 0 0]
 [0 0 1 2 3 0]
 [0 0 0 1 2 3]]
"""

      

+1


source


This is a simplified tridiagonal matrix. So this is this question

def tridiag(a, b, c, k1=-1, k2=0, k3=1):
    return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)

a = [1, 1]; b = [2, 2, 2]; c = [3, 3]
A = tridiag(a, b, c)
print(A)

      

Result:

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

      

+1


source


If you care about efficiency, this is hard to beat:

import numpy as np

def create_matrix(diags, n):
    diags = np.asarray(diags)
    m = np.zeros((n,n+len(diags)-1), diags.dtype)
    s = m.strides
    v = np.lib.index_tricks.as_strided(
        m,
        (len(diags),n),
        (s[1],sum(s)))
    v[:] = diags[:,None]
    return m

print create_matrix(['a','b','c'], 8)

      

Maybe a little overhead, but again this is good inspiration;)

Or even better: a solution that has both O (n) and runtime requirements, not all the other solutions posted so far that are O (n ^ 2)

import numpy as np

def create_matrix(diags, n):
    diags = np.asarray(diags)
    b = np.zeros(len(diags)+n*2, diags.dtype)
    b[n:][:len(diags)] = diags
    s = b.strides[0]
    v = np.lib.index_tricks.as_strided(
        b[n:],
        (n,n+len(diags)-1),
        (-s,s))
    return v

print create_matrix(np.arange(1,4), 8)

      

0


source


This is an old question, but some new data can always be helpful.

I am creating tridiagonal matrices in python using a list comprehension.

Let's say a matrix that is symmetrical around "-2" and has "1" on both sides:

           -2   1   0
Tsym(3) =>  1  -2   1 
            0   1  -2

      

This can be created using the following "one liner":

Tsym = lambda n: [ [ 1 if (i+1==j or i-1==j) else -2 if j==i else 0 for i in xrange(n) ] for j in xrange(n)] # Symmetric tridiagonal matrix (1,-2,1)

In another case (which some of the other people in charge have resolved perfectly fine):

             1   2   3   0   0   0 
Tgen(4,6) => 0   1   2   3   0   0
             0   0   1   2   3   0
             0   0   0   1   2   3

      

Can be done using one liner shown below.

Tgen = lambda n,m: [ [ 1 if i==j else 2 if i==j+1 else 3 if i==j+2 else 0 for i in xrange(m) ] for j in xrange(n)] # General tridiagonal matrix  (1,2,3)

      

Feel free to modify to suit your specific needs. These matrices are very common when simulating physical systems, and I hope this is useful to someone (other than me).

0


source


Hi, since your professor asked you not to import an external package while most of the answers are using numpy or scipy. You are better off using just python List to create a 2D array (compound list) and then fill it with diagonals with the elements you want find the code below

def create_matrix(rows = 4, cols = 6):
    mat = [[0 for col in range(cols)] for row in range(rows)] # create a mtrix filled with zeros of size(4,6) 
    for row in range(len(mat)): # gives number of lists in the main list, 
        for col in range(len(mat[0])): # gives number of items in sub-list 0, but all sublists have the same length
            if row == col:
                mat[row][col] = "a"
            if col == row+1:
                mat[row][col] = "b"
            if col == row+2:
                mat[row][col] = "c"
    return mat

create_matrix(4, 6)

      

[['a', 'b', 'c', 0, 0, 0],

[0, 'a', 'b', 'c', 0, 0],

[0, 0, 'a', 'b', 'c', 0],

[0, 0, 0, 'a', 'b', 'c']]

0


source







All Articles