如何在Python中加快数组生成速度?

6

我想我需要使用numpy或其他库来快速填充这些数组,但我对它不是很了解。目前,在四核英特尔PC上,此操作大约需要1秒钟的时间,但我需要尽可能快地完成它。非常感谢任何帮助。谢谢!

import cv

class TestClass:

  def __init__(self):

    w = 960
    h = 540

    self.offx = cv.CreateMat(h, w, cv.CV_32FC1)
    self.offy = cv.CreateMat(h, w, cv.CV_32FC1)

    for y in range(h):
      for x in range(w):
        self.offx[y,x] = x
        self.offy[y,x] = y
6个回答

8

我的八年老旧的电脑能够在127毫秒内创建一个与您的矩阵大小相同的列表。


(这句话是在比较两台电脑的速度,说作者的电脑虽然老旧但仍然能够完成同样的任务,并且用时非常短)
C:\Documents and Settings\gdk\Desktop>python -m timeit "[[x for x in range(960)]
 for y in range(540)]"
10 loops, best of 3: 127 msec per loop

我不知道cv模块是什么以及它如何创建矩阵。但也许这就是代码运行缓慢的原因。
Numpy可能更快。创建一个由(Python int)1组成的数组:
C:\Documents and Settings\gdk\Desktop>python -m timeit -s "from numpy import one
s" "ones((960, 540), int)"
100 loops, best of 3: 6.54 msec per loop

您可以比较使用不同模块创建矩阵的时间,以确定是否有更改的好处:timeit模块


尽管您的回答解决了时间问题,但并没有完全做到原始问题中的代码所做的事情。因此,您的比较是有偏见的。另外,您发布的两个代码执行不同的操作,因此比较是不公平的。 - Dat Chu
当然,我的代码与问题的代码不同。我也没有说OP应该使用我的代码。我提供的示例是为了展示如何计时创建大型矩阵对象的不同方法。我的最后一句话告诉OP计时不同的方法,以便他可以决定是否改变 - 在他有证据表明另一种方法更快或更有效之前,他不应该进行更改。 - Gary Kerr

1

在Numpy中完成与OpenCV Python相同操作的代码如下:

import numpy as np
offsetx, offsety = np.meshgrid(range(960),range(540))

如果你正在使用Python,考虑学习numpy的不同函数将会极大地帮助你。OpenCV函数也可以直接与numpy数组一起使用。虽然在Python中,numpy的语法比OpenCV好得多。
这是我在我的i7上测试的两个版本的时间。
time python test.py

real    0m0.654s 
user    0m0.640s
sys 0m0.010s

我的版本:

time python test2.py

real    0m0.075s
user    0m0.060s
sys 0m0.020s

1
你正在生成50万个整数,并在此过程中创建超过一百万个引用。如果它只需要1秒钟,我会很高兴。
如果你经常这样做,你应该考虑缓存结果的方法。
此外,在像这样的情况下,使用四核处理器并没有帮助,因为你正在执行一个串行操作,每次只能在一个核心上执行(即使你对其进行了线程化,由于全局解释器锁定,CPython也只能同时执行一个纯Python线程)。

5
为什么这被标记为解决方案?它根本没有回答问题,最多是误导--在Python中创建一百万个整数和一百万个引用不需要接近1秒钟的时间(在典型PC上)。 - Glenn Maynard

0

我没有完全理解你想要实现什么。但是这里有两个具体的例子和基准测试,可能会对你有所帮助。它们都做同样的事情,用红色填充960x540的图像(数组)。

slow.py使用for循环来填充数组

import cv2
import numpy as np

width, height = 960, 540
image = np.zeros((height, width, 3), np.uint8)
# Fill array with red
for y in range(height):
    for x in range(width):
        image[y, x] = (0, 0, 255)

cv2.imwrite('red.jpg', image)

运行时间

$ time python slow.py
real    0m2.240s
user    0m2.172s
sys 0m0.040s

fast.py 使用 numpy 填充数组

import cv2
import numpy as np

width, height = 960, 540    
image = np.zeros((height, width, 3), np.uint8)
# Fill array with red
image[:] = (0, 0, 255)
cv2.imwrite('red.jpg', image)

运行时间

$ time python fast.py
real    0m0.134s
user    0m0.084s
sys 0m0.024s

使用numpy而不是for循环,速度快了近17倍


0

如果您正在多次创建相同的矩阵,则使用cv.SetData()进行初始化可能会更快。


0

嗯,你至少可以使用xrange而不是range。range会创建所有这些数字的完整列表。xrange逐个生成它们。由于你一次只使用一个数字,所以不需要它们的列表。


我认为现代Python解释器会自动将“for range(...)”更改为“for xrange(...)”。因此,这只是理论上的优化,或者只适用于一些简单(不太智能)的解释器。 - Tomasz Wysocki
在 Python 2.x(包括刚发布的 2.7 版本)中,内置函数 range 仍然返回列表,因此使用 xrange 是一种优化方式。在 Python 3 中,range 返回一个 range 对象,这是一个可迭代对象,类似于 Python 2 中的 xrange 返回的对象。 - Ned Deily
我的Python 2.6.1计时显示range花费了4.70秒,而xrange只需要2.29秒。我使用的代码是for i in range(1000000): pass,同样适用于xrange。使用timeit并设置number=100。 - Ponkadoodle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接