【问题标题】:What's a pythonic way to generate an array with a diagonal edge?生成具有对角线边缘的数组的pythonic方法是什么?
【发布时间】:2020-03-16 06:48:08
【问题描述】:

我通过使用两个 for 循环创建了一个对角线边缘的数组,但我想知道是否有更简单的方法可以做到这一点,例如使用列表推导:

im_diag = np.zeros((im_size, im_size), dtype=np.int8)

for x in range(im_size):
    for y in range(im_size):
        if x+y >= im_size:
            im_diag[x,y] = 1

输出(im_size = 5):

>>> im_size
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1],
       [0, 0, 0, 1, 1],
       [0, 0, 1, 1, 1],
       [0, 1, 1, 1, 1]], dtype=int8)

【问题讨论】:

    标签: python numpy for-loop list-comprehension numpy-ndarray


    【解决方案1】:

    通常在使用 numpy 时,使用向量化方法要好得多,随着所需数组大小的增加,这将比使用循环和列表理解的方法快得多。

    >>> np.flip(np.tril(np.ones((5,5)), k=-1), 1)
    array([[0., 0., 0., 0., 0.],
           [0., 0., 0., 0., 1.],
           [0., 0., 0., 1., 1.],
           [0., 0., 1., 1., 1.],
           [0., 1., 1., 1., 1.]])
    

    np.ones 创建1s 的数组,

    np.tril 创建下三角阵列

    np.flip 水平翻转数组

    与其他答案的时间比较:

    如图所示,使用n>=10,numpy 方法速度更快,随着 n 变大,这种方法往往比列表理解解决方案快 10 倍左右。

    要重现的代码:

    import perfplot
    import numpy as np
    
    def cdjb(n):
        return np.flip(np.tril(np.ones((n,n)), k=-1), 1)
    
    def displayname(n):
        return [[int(j > i) for j in range(n)] for i in range(n)][::-1]
    
    def MikeMajara(n):
        return [[1 if i+j >= n else 0 for i in range(n)] for j in range(n)]
    
    perfplot.show(
        setup=lambda n: n,
        n_range=[2**k for k in range(14)],
        kernels=[
            cdjb,displayname,MikeMajara
            ],
        xlabel='Size of Array',
        )
    

    【讨论】:

    • 在那种情况下,我会说那应该是你答案的一部分。对于(特别是对于学习者)来说,没有一见钟情的明显方式。我还要说缺点是可读性,因为问题中没有提到效率或大数组维度,但仍然使用和链接库的 高级 函数。出于这个原因,恕我直言,最好的方法是 OPs 帖子,除非效率受到威胁。
    • @MikeMajara 我添加了时间比较图。您的列表理解解决方案比另一个更快,(+1)但 numpy 仍然会在 n 大于 10 时击败两者。
    【解决方案2】:

    使用列表理解(不需要numpy):

    n = 5
    [[int(j > i) for j in range(n)] for i in range(n)][::-1]
    

    给予

    [[0, 0, 0, 0, 0],
     [0, 0, 0, 0, 1],
     [0, 0, 0, 1, 1],
     [0, 0, 1, 1, 1],
     [0, 1, 1, 1, 1]]
    

    其中[::-1] 只是反转外部列表。

    【讨论】:

      【解决方案3】:

      如果您正在寻找理解列表,这可能是您的解决方案:

      [[1 if i+j >= im_size else 0 for i in range(im_size)] for j in range(im_size)]
      

      但复杂的理解列表更难阅读/理解。而且不可读的代码不是pythonic。所以考虑一下。

      【讨论】:

        猜你喜欢
        • 2017-04-09
        • 1970-01-01
        • 2018-06-08
        • 2011-04-21
        • 2021-12-08
        • 2011-09-23
        • 1970-01-01
        • 2015-09-01
        • 1970-01-01
        相关资源
        最近更新 更多