Почему эта операция с массивами такая медленная? - PullRequest
0 голосов
/ 06 апреля 2011

Я новичок в Python и пытаюсь усреднить два двумерных массива NumPy с формой (1024,1024).Делать это так быстро:

newImage = (image1 + image2) / 2

Но теперь у изображений есть «маска», которая делает недействительными определенные элементы, если они установлены на ноль.Это означает, что если один из элементов равен нулю, результирующий элемент также должен быть равен нулю.Моё тривиальное решение:

newImage = numpy.zeros( (1024,1024) , dtype=numpy.int16 )

for y in xrange(newImage.shape[0]):
   for x in xrange(newImage.shape[1]):
      val1 = image1[y][x]  
      val2 = image2[y][x]                            
      if val1!=0 and val2!=0:               
         newImage[y][x] = (val1 + val2) / 2

Но это действительно медленно.Я не рассчитывал время, но, похоже, он медленнее в 100 раз.

Я также пытался использовать лямбда-оператор и "map", но это не возвращает массив NumPy.

Ответы [ 4 ]

8 голосов
/ 06 апреля 2011

Попробуйте это:

newImage = numpy.where(np.logical_and(image1, image2), (image1 + image2) / 2, 0)

Если ни один из image1 и image2 не равен нулю, возьмите их среднее, в противном случае ноль.

2 голосов
/ 06 апреля 2011

Циклы с собственным кодом Python, как правило, намного медленнее, чем при использовании встроенных инструментов, использующих быстрые циклы Си.Я не знаком с NumPy;Вы можете использовать map() для преобразования двух ваших входных массивов в выходные?Если так, то это должно быть быстрее.

1 голос
/ 06 апреля 2011

Явные циклы for вообще неэффективны в Python, не только для операций numpy. К счастью, есть более быстрые способы решения нашей проблемы. Если память не проблема, это решение довольно хорошо:

import numpy as np
new_image = np.zeros((1024, 1024), dtype=np.int16)
valid = (image1!=0) & (image2!=0)
new_image[valid] = (image1+image2)[valid]

Другое решение, использующее замаскированные массивы, которые не создают копии массивов (они представляют виды оригинала image1/2:

m1 = np.ma.masked_equal(image1, 0)
m2 = np.ma.masked_equal(image2, 0)
new_image = (m1+m2).filled(0)

Обновление: Первое решение кажется в 3 раза быстрее второго для массивов с около 1000 ненулевых записей.

0 голосов
/ 09 июля 2014

операция доступа к массиву в лучшем случае кажется медленной. Я не вижу никакой причины для этого. Вы можете ясно увидеть это, построив простой пример:

    import numpy
    # numpy version
    def at(s,n):
      t1=time.time()
      a=numpy.zeros(s,dtype=numpy.int32)
      for i in range(n):
        a[i%s]=n
      t2=time.time()
      return t2-t1
    # native version
    def an(s,n):
      t1=time.time()
      a=[(i) for i in range(s)]
      for i in range(n):
        a[i%s]=n
      t2=time.time()
      return t2-t1

    # test
    [at(100000,1000000),an(100000,1000000)]

Результат: [0.21972250938415527, 0.15950298309326172]

...