在numpy中创建一个特殊的矩阵

时间:2014-09-15 02:06:10

标签: python numpy

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

您好

对于我的经济学课程,我们假设要创建一个看起来像这样的数组。问题是我是经济学家而不是程序员。我们在python中使用numpy。我们的教授说大学不是为现实世界做准备,而是希望我们学习编程(这是一件好事)。我们不允许使用任何软件包,并且必须提供原始代码。有没有人知道如何制作这个矩阵。我花了几个小时尝试代码和浏览互联网寻求帮助,但都没有成功。

8 个答案:

答案 0 :(得分:5)

这种矩阵称为Toeplitz matrix或恒定对角矩阵。了解这一点会导致您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]])

答案 1 :(得分:4)

以下方法一次填充一个对角线:

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]])

或者你可以做一个班轮:

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

就个人而言,我更喜欢第一个,因为它更容易理解,并且可能更快,因为它不构建所有临时1D阵列。

修改
由于对效率的讨论已经出现,因此进行测试可能是值得的。我还把chthonicdaemon建议的toeplitz方法包括在内的时间(虽然我亲自解释了这个问题,因为它使用了一个包而不是使用原始代码 - 但速度也不是原始问题的重点。任一)。

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

因此,对于小型阵列,第一种方法的速度要快2-3倍,对于较大的阵列,速度要快10-20倍。

答案 2 :(得分:1)

的内容
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]]
"""

答案 3 :(得分:1)

这是一个简化的三对角矩阵。所以它基本上是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)

结果:

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

答案 4 :(得分:0)

如果你关心效率,很难打败这个:

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)

可能会略微超过你的头脑,但那又是一个很好的灵感;)

甚至更好:具有O(n)存储和运行时要求的解决方案,而不是迄今为止发布的所有其他解决方案,即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)

答案 5 :(得分:0)

这是一个老问题,但是一些新输入总是有用的。

我使用list comprehension在python中创建三对角矩阵。

说一个围绕“-2”对称并且两边都有“1”的矩阵:

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

可以使用以下“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)

一个不同的案例(其他几个回答的人已经完全解决了):

             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

可以使用下面显示的单个衬垫制作。

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)

随意修改以满足您的特定需求。这些矩阵在建模物理系统时非常常见,我希望这对某人(除了我)有用。

答案 6 :(得分:0)

您好,因为您的教授要求您不要导入任何外部包,而大多数答案都使用numpy或scipy。 你最好只使用python List来创建2D数组(复合列表),然后用你想要的项目填充它的对角线,找到下面的代码

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']]

答案 7 :(得分:0)

创建波段矩阵

在 wiki 中查看它的定义: https://en.wikipedia.org/wiki/Band_matrix

您可以使用此函数创建带状矩阵,例如带 offset=1 的对角矩阵或带 offset=1三对角 矩阵(您正在询问的) }} 或带有 offset=2

Pentadiagonal 矩阵
def band(size=10, ones=False, low=0, high=100, offset=2):
    shape = (size, size)
    n_matrix = np.random.randint(low, high, shape) if not ones else np.ones(shape,dtype=int)
    n_matrix = np.triu(n_matrix, -1*offset)
    n_matrix = np.tril(n_matrix, offset)
    return n_matrix

在你的情况下,你应该使用这个

rand_tridiagonal = band(size=6,offset=1)
print(rand_tridiagonal)