【问题标题】:Creating a special matrix in numpy在 numpy 中创建一个特殊的矩阵
【发布时间】:2014-11-08 11:59:29
【问题描述】:
[a b c       ] 
[  a b c     ]
[    a b c   ]
[      a b c ]

你好

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

【问题讨论】:

  • 空白元素是什么类型的?这与经济学有什么关系?
  • 空白为 0。我们正在编写自己的 hodrick prescott 过滤器

标签: python numpy


【解决方案1】:

创建波段矩阵

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

您可以使用此功能创建带状矩阵,例如使用offset=1 的对角矩阵或使用offset=1三对角 矩阵(您所询问的)或 五角形 矩阵与offset=2

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)

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      我使用列表推导在 python 中创建三对角矩阵。

      假设一个围绕“-2”对称且两边各有一个“1”的矩阵:

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

      这可以使用以下“一个衬里”来创建:

      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)
      

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

      【讨论】:

        【解决方案4】:

        如果你关心效率,这是很难超越的:

        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】:

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

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

          就个人而言,我更喜欢第一个,因为它更容易理解并且可能更快,因为它不会构建所有临时的一维数组。

          编辑:
          由于出现了关于效率的讨论,因此运行测试可能是值得的。我还包括了 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 倍。

          【讨论】:

          • 我喜欢一个班轮。我不认为它会更慢,因为数组切片也很昂贵。
          • @xavier:切片很便宜,因为它只是对数据的不同视图,而不是副本,尽管很难说对于如此小的数组来说哪个会胜出(例如,视图可能大于数据)。 docs.scipy.org/doc/numpy/glossary.html#term-view
          • 我什至会犹豫是否要添加一个衬里,因为它会加强糟糕的 numpy 代码。如图np.roll 必须为每一行分配两个新的一维数组,为 vstack 分配一个二维数组,最后将所有一维数组复制到二维数组上。
          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            这种矩阵称为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]])
            

            【讨论】:

              【解决方案8】:

              类似的东西

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

              【讨论】:

                猜你喜欢
                • 2016-05-22
                • 1970-01-01
                • 1970-01-01
                • 2021-12-11
                • 2014-02-09
                • 2013-08-04
                • 1970-01-01
                • 2011-08-17
                • 2016-02-08
                相关资源
                最近更新 更多