【问题标题】:Fast 2-dimensional array (matrix) in Python without C extensions没有 C 扩展的 Python 中的快速二维数组(矩阵)
【发布时间】:2012-03-18 10:30:11
【问题描述】:

我需要为可使用 Python 2.7 扩展的应用程序编写插件。它需要执行一个相当复杂的动态算法,该算法适用于整数的矩形矩阵。

该应用程序附带的默认 Python 安装不包括像 numpy 这样的数字库,所以很遗憾我只能使用 Python stdlib 来实现它。

我尝试了几种不同的方法来表示内存中的矩阵:

values = defaultdict(int)
values = [[0 for _ in range(width)] for _ in range(height)]
values = [0] * (width * height)   # access like values[j*width + i] later
values = [[0] * width for _ in range(height)]

dict 方法只是为了完整性,实际上它的性能并不好,因为每个元素都被访问了。

根据我的测量,最后一个似乎是构建和访问速度最快的。但是,令我惊讶的是没有内置矩阵功能。从目前我对 Python 的了解来看,如果你在 stdlib 中没有发现一些明显的功能,最可能的原因是你看的不够仔细。

所以我想知道这是否可以进一步优化。例如使用array 模块或其他一些我不知道的功能。

【问题讨论】:

  • 你确定瓶颈是数据结构的选择吗?
  • @Sven:是的,该算法基本上只是对矩阵中的值进行相应的比较和修改。将 a 从一个元组索引的字典切换到一个列表列表给了我大约 50% 的性能。分析(使用kernprof)表明大部分时间都需要使用从矩阵中获取和设置值。

标签: python python-2.7 matrix python-2.x


【解决方案1】:

array 模块在矩阵变大时可能会更快,因为它可以更紧凑地打包值;它可以与values[j*width + i] 约定一起使用。但是不,Python 标准库中没有多维数组,这可能是因为 (a) Numpy 已经有效地填补了这一领域,并且 (b) 如果性能不是最重要的,你总是可以制作一个列表列表。

最快的选项实际上取决于算法。当您处理的矩阵非常稀疏时,基于dict 的方法实际上可能是最快的(在 DP 算法中它们通常不是,至少在我看到的矩阵中不是)。

【讨论】:

  • 感谢您的澄清。实际上array 在这种情况下似乎比简单的[0]*(width*height) 还要慢一些,所以这也不是一个选择。我想它一定很慢,然后:) 也许我会选择使用 numpy,所以用户可以选择。我想这可能是一个很好的解决方案。
  • 我发现array 通常比使用列表要慢——这里有一些simple example timimngs。我什至没想到它会更快——它只是使用更少的内存。
  • @Sven:是的,我也是这么想的。
【解决方案2】:

您可以使用默认字典并使用 2 元组作为索引,或者实现自定义类并实现 __getitem____setitem__ 方法来处理 2 元组作为索引并将结果存储在 Python数组:

from array import array
class Array2D(object):
    def __init__(self, w, h):
        self.data = array("f", [0] * w * h)
        self.width = w
    def __getitem__(self, index):
        return self.data[index[1] * self.width + index[0]]
    def __setitem__(self, index, value):
          self.data[index[1] * self.width + index[0]] = value

或者,使用默认字典,您可能会获得更好的性能:

>>> from collections import defaultdict
>>> d = defaultdict(lambda : 0)
>>> d[0,0]
0
>>> d[0,0] = 2.5
>>> d[0,0]
2.5
>>> 

【讨论】:

  • 这两种方法都包含在我的问题中,并评论说简单的[[0] * width for _ in range(height)] 实际上更快。我也提到过,每一项都是实际访问的,所以字典方案的空间优势也被抹杀了。
【解决方案3】:

这可能会有所帮助:

arr=[*map(lambda a: [a]*cols,[0]*rows)]

这将创建一个 2D(行 x 列)零矩阵

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 2020-08-25
    • 2021-07-18
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    相关资源
    最近更新 更多