【问题标题】:how to effectively loop over matrix elements?如何有效地循环矩阵元素?
【发布时间】:2015-02-19 15:19:50
【问题描述】:

我必须遍历一个 800 000* 800 000 矩阵。我试图通过简单的循环来做到这一点,但这花了我很多时间。如何快速循环?

for in in xrange(800000):
   for j in xrange(800000):
      print i,j

通常,我使用 OpenCV 读取图像,然后我需要遍历每个像素,以便执行一些计算并与像素邻居的某些特征的值进行比较。当我运行一个循环时,我觉得它需要超过 2 天才能完成。

其实我想实现我自己版本的GrowCut算法。作者声称使用像我这样的计算机在不到 4 分钟的时间内执行该算法。但是,循环 1200*1100 矩阵需要很长时间(我测试过)。我怎样才能快速阅读它们?

【问题讨论】:

  • 你在这里比较的是什么语言?你将无法用 python 击败 C 速度。不管你怎么努力:)
  • 您也可以尝试隔离一段代码,其中循环处于某种独立状态(即使您必须删除一些操作)。 Python 循环的工作速度几乎变慢,但它也可能表明您的代码存在问题。也许循环超过阈值的像素可以帮助(使用np.where)等......
  • @ljetibo 我绝对需要读取每个像素的 RGB 值并将它们与该像素的邻居的值进行比较(如果需要,请查看我提供的链接......那个人编程了它在 Python 中也是如此,但是运行时出现错误)
  • 试试这个链接,它列出了所有(默认)包:docs.continuum.io/anaconda/pkg-docs.html Numba 包括在内。另外,我知道我的 (OSX) Anaconda 发行版中有它。
  • 对于 OpenCV,我个人看过这里:binstar.org/search?q=opencv(binstar 是一个分享 anaconda 包的地方)但也有这个:*.com/questions/23119413/… 根据我的记忆,OpenCV 在 Windows 上安装比在 OSX 上容易得多所以你会有几个选择。

标签: python arrays loops numpy matrix


【解决方案1】:

对于高性能数组循环,您可以使用Cython。你可以使用 Python 的大部分语法,使用 C 的性能提升很多。它还兼容NumPy

Iterating over arrays with Cython.

【讨论】:

  • 这更像是一个评论,而不是问题的真正答案:)
【解决方案2】:

您可以考虑使用内置的 bytearray 类型而不是 python 列表。

您可以创建一个大小为 1200 * 1300 * 4 的字节数组来表示您的矩阵。 元素 i, j 将位于 i * 1200 * 4 + j * 4 (假设像素大小为 4 字节)

进一步看,我发现您可以在 python 中使用数组来有效地存储几乎任何东西。如上所述,您可以轻松计算指数。

“Numeric Python 扩展 (NumPy) 定义了另一种数组类型;有关 Numerical Python 的更多信息,请参阅http://www.numpy.org/。”

【讨论】:

  • 谢谢。我真的需要逐个元素循环矩阵元素(鉴于 GrowCut 算法的性质)
【解决方案3】:

这是一个可能的优化,但同样,这将取决于系统和其他当前正在运行的进程等...以及您在内部进行的计算。

import time
import numpy as np
test = np.ones((1200, 1100))

测试 1:

def loops():
    start = time.clock()
    for i in range(1200):
        for j in range(1100):
            a = test[i,j]
    print(time.clock()-start)
    return a

>>> loops()
1.433313120652599
1.0

所以你看到循环只有 1.5 秒。在里面添加计算会大大延长这个时间,但你的循环是最不担心的。如果不提供 您的 代码,我对此无话可说。

替代方法是:

def loops():
    start = time.clock()
    for row in test:
        for element in row:
            a = element
    print(time.clock()-start)
    return a

>>> loops()
0.714938339920252
1.0

请注意这个样本有多小(仅 1 次测试),但有一半时间表明可能有增强功能?您还避免了使用a= 的需要,并且可以跳过分配一个应该减少几微秒的新变量。

显示你的代码,我相信还有其他可以做的。

这是win7 Intel i5 Dual Core Python3.4

【讨论】:

  • 快速查看算法链接显示 4 个嵌套循环;也许这就是为什么OP的时间比你的时间长得多?
  • @tom10:期望这个模拟测试甚至接近 OPs 问题是不现实的。然而,它确实表明带有in 语句的循环似乎具有更快的查找时间。我相信不是他的循环导致他出现问题,而是他在内部进行的计算。但是我不熟悉 GrowCut。如果没有解释和他的确切代码,我无能为力。
  • @tom10 没关系,但据我所知,他可能在任何内部循环上犯了一个简单的错误(我无法从他发布的代码中理解)并且可以运行它超过必要的。如果他使用range 而不是xrange,如果他使用的是旧python,他实际上是在创建整个列表。 xrange 是一个更快的迭代器。他本可以编写自己的生成器,等等……我无法优化我看不到的东西。
  • 非常感谢。与我的情况相比如此之快。你能解释一下你做了什么吗?
  • 当然,但我最初赞成,因为自己运行循环会在时间上设置合理的下限,但看看 GrowCut 算法,我意识到你的测试并不真正相关。如果您运行四个嵌套循环,恕我直言,至少它可能会偏离两倍或十倍,但不是 2 的 power,即在这种情况下可能是数百万。 (但我确实希望,有一种方法可以在不投反对票的情况下删除我的赞成票。)