【问题标题】:efficient way of padding an array填充数组的有效方法
【发布时间】:2021-06-03 19:39:13
【问题描述】:

我想知道是否有一种有效的方法可以在 python 中填充数组,而不使用numpy.pad()

我知道一种使用嵌套 for 循环的方法,但我想知道是否有更快的方法?

输入:

row padding on top- 2
column padding from left - 1
1 2 3
4 5 6
7 8 9

输出

0 0 0 0
0 0 0 0
0 1 2 3
0 4 5 6
0 7 8 9

我做了什么

y = [[1,2,3],[4,5,6],[7,8,9]]

topPadding = 2
leftPadding = 1
noOfRows = len(y)+topPadding
noOfCols = len(y)+leftPadding

x = [[0 for i in range(noOfCols)] for j in range(noOfRows)]

for i in range(topPadding,noOfRows):
    for j in range(leftPadding,noOfCols):
        x[i][j] = y[i-topPadding][j-leftPadding]
    print()
        
print(x)

输出

[[0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 2, 3], [0, 4, 5, 6], [0, 7, 8, 9]]

【问题讨论】:

  • 是 numpy.pad 太慢了吗?
  • 我正在尝试构建一个在存储方面没有很多资源的平台上运行的算法,因此 NumPy 会很重,出于同样的原因我不想使用任何外部库,所以我正在尝试构建替代方案
  • 这是有道理的。但是当没有什么可比的(即你已经尝试过的)时,要求一种“更快的方法”有点开放式
  • 我试过了,创建一个全新的数组并一个一个地复制元素,时间复杂度是O(n^2),这是我能做到的最好的吗?
  • 我建议您将该代码作为可运行示例包含在此问题中。

标签: python padding


【解决方案1】:

使用list 连接和重复运算符的解决方案:

def concat(x, top, left):
    n = len(x[0])
    return [[0]*(n + left - len(row)) + row for row in [[]]*top + x]

以下是使用嵌套的for 循环解决方案与我在10000x10000 随机数字矩阵上的串联解决方案的一些非常基本的计时结果:

nested: 122.26 s
concat: 5.66 s

以及测试代码:

import timeit
from random import randint


def concat(x, top, left):
    n = len(x[0])
    return [[0]*(n + left - len(row)) + row for row in [[]]*top + x]


def nested(x, topPadding, leftPadding):
    noOfRows = len(x)+topPadding
    noOfCols = len(x)+leftPadding

    z = [[0 for i in range(noOfCols)] for j in range(noOfRows)]

    for i in range(topPadding,noOfRows):
        for j in range(leftPadding,noOfCols):
            z[i][j] = x[i-topPadding][j-leftPadding]

    return z


test = [[randint(0, 9) for _ in range(10000)] for _ in range(10000)]

t1 = timeit.timeit(
    "nested(test, 4, 2)",
    number=10,
    globals=globals()
)

t2 = timeit.timeit(
    "concat(test, 4, 2)",
    number=10,
    globals=globals()
)

print(nested(test, 4, 2) == concat(test, 4, 2))
print(f"nested: {t1:.2f} s")
print(f"concat: {t2:.2f} s")

完整输出:

True
nested: 122.26 s
concat: 5.66 s

您输入所需高度和宽度的修改版本:

def concat(x, h, w):
    H = h - len(x)
    return [[0]*(w - len(row)) + row for row in [[]]*H + x]

另一个允许向北、南、东和西填充的版本:

def nsew_concat(x, N, S, E, W):
    """Pad x with zeros to the north, south, east, and west."""
    k = len(x[0])
    stack = [[]]*N + x + [[]]*S
    return [([0]*W + [0]*(k - len(row)) + row + [0]*E) for row in stack]

【讨论】:

    【解决方案2】:

    这适用于任何(非空)矩形矩阵,但不适用于锯齿状数组(其中每一行的长度不同)。

    def pad_matrix(matrix, element=0, *, left=0, top=0):
        full_width = left + len(matrix[0])
        e = [element]
        return [
            *(e * full_width for i in range(top)),
            *(e * left + row for row in matrix),
        ]
    

    这是一个允许在所有四个边上填充的版本:

    def pad_matrix(matrix, element=0, *, left=0, top=0, right=0, bottom=0):
        full_width = left + len(matrix[0]) + right
        e = [element]
        return [
            *(e * full_width for i in range(top)),
            *(e * left + row + e * right for row in matrix),
            *(e * full_width for i in range(bottom)),
        ]
    

    用法类似于pad_matrix(matrix, left=1, top=2)。

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2015-07-19
      • 2022-12-18
      • 2011-04-19
      • 1970-01-01
      • 2019-09-03
      • 2012-04-01
      • 1970-01-01
      • 2018-03-24
      相关资源
      最近更新 更多