Найти - Пользователи
Полная версия: аналог ufunc (ну или map) для подмассивов
Начало » Python для новичков » аналог ufunc (ну или map) для подмассивов
1
iezhov
Здравствуйте! Может быть глупый вопрос, но никак не разберусь..
Как написать функцию, которая применяется к массиву numpy не поэлементно, а к подмассивам.
Т.е. есть такой цикл, который работает медленно:

 
for ii in xrange(len(ccc)):
for j in xrange(len(ccc[ii,:,:])):
if ccc[ii,j,0]>0 or ccc[ii,j,1]>0 or ccc[ii,j,2]>0:
ccc[ii,j,0]=255
ccc[ii,j,1]=255
ccc[ii,j,2]=255

Нет ли каких-то других вариантов такой обработки? (идея обработки: графический файл преобразован в массив, и далее, если присутствует “сигнал” хоть в одном канале - устанавливаем точку в белый цвет)
sergeek
import numpy as np
def ff1(ccc):
    for ii in xrange(len(ccc)):
        for j in xrange(len(ccc[ii,:,:])):
          if ccc[ii,j,0]>0 or ccc[ii,j,1]>0 or ccc[ii,j,2]>0:
            ccc[ii,j,0]=255
            ccc[ii,j,1]=255
            ccc[ii,j,2]=255
            
def ff2(ccc):
    for row in ccc:
        for pix in row:
            if pix[0]|pix[1]|pix[2]:
                pix[0]=pix[1]=pix[2]=255
              
ccc1 = np.ndarray([10,20,3],np.ubyte)
ccc2 = ccc1.copy()
%%timeit
ff1(ccc1)
1000 loops, best of 3: 1.65 ms per loop
%%timeit
ff2(ccc2)
10000 loops, best of 3: 137 us per loop
iezhov
Спасибо за ответ!
GaiveR
Вариант sergeek, безусловно, понятнее и правильнее, но существенное падение скорости даёт всего одна строчка:

import numpy as np
def ff1(ccc):
    for ii in xrange(len(ccc)):
        for j in xrange(len(ccc[ii,:,:])):
            if ccc[ii, j, 0] or ccc[ii, j, 1] or ccc[ii, j, 2]: # убрали сравнение с нулём
                ccc[ii, j, 0] = 255
                ccc[ii, j, 1] = 255
                ccc[ii, j, 2] = 255
def ff2(ccc):
    for row in ccc:
        for pix in row:
            if pix[0] | pix[1] | pix[2]:
                pix[0] = pix[1] = pix[2] = 255
ccc1 = np.ndarray([10, 20, 3], np.ubyte)
ccc2 = ccc1.copy()
%%timeit                                
ff1(ccc1)
1000 loops, best of 3: 378 us per loop
%%timeit                                
ff2(ccc2)
1000 loops, best of 3: 507 us per loop

К слову, первый вариант работает чуть быстрее т.к. логические операции(or) - ленивы, а битовые(|) - нет.
iezhov
Я думал медленно из-за xrange, а оно вон как.. Спасибо! В любом случае, с такой скоростью уже вполне замечательно.
sergeek
странно, когда я делал тесты ленивое сравнение было медленее, а теперь наоборот, причем повторил много раз. Можно конечно предположить что тогда ненули расположились ближе к старшим позициям. Но меня смущает вот это
%%timeit
1|1|1
100000000 loops, best of 3: 14.9 ns per loop
%%timeit
0 or 0 or 1
10000000 loops, best of 3: 37.2 ns per loop
%%timeit
0 or 1 or 1
10000000 loops, best of 3: 33.5 ns per loop
%%timeit
1 or 1 or 1
10000000 loops, best of 3: 24.1 ns per loop
даже самый оправданный в плане лени вариант получается медленее
GaiveR
Действительно, для обычных чисел оптимальнее использовать битовые операции.
Но у ТС там np.ubyte:
a = np.ubyte(1)
b = np.ubyte(1)
c = np.ubyte(1)
%%timeit
a | b | c
1000000 loops, best of 3: 640 ns per loop
%%timeit
a or b or c
10000000 loops, best of 3: 90 ns per loop
b = np.ubyte(0)
%%timeit
a or b or c
10000000 loops, best of 3: 166 ns per loop
c = np.ubyte(0)
%%timeit
a or b or c
10000000 loops, best of 3: 168 ns per loop
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB