Есть ли более быстрый, более "питонический" подход, который дал бы мне тот же результат?
Возможно, это зависит от того, могут ли ваши операции быть векторизованы и выполнены в c-слое(т.е. важно знать, что блок # Do stuff...
на самом деле для вашего конкретного случая).Вы можете, по крайней мере, получить данные с помощью среза и причудливой индексации вместо цикла (и в одну строку):
import numpy as np
img = np.arange(30000).reshape(100, 100, 3)
pane_step, center = 20, 10
field_size = 5
rs = []
gs = []
bs = []
# Original code
for i in range(0, field_size * pane_step, pane_step):
for j in range(0, field_size * pane_step, pane_step):
r, g, b, = img[i + center, center + j, :]
rs.append(r)
gs.append(g)
bs.append(b)
# You want center (i = 0) to field_size * pane_step + center (i=field_size * pane_step) going by pane_step for the first dim
# Same for second dim
# Use fancy indexing and slice notation instead of doing one ind at a time
r_fancy, g_fancy, b_fancy = img[center:center+pane_step*field_size:pane_step, center:center+pane_step*field_size:pane_step, :].T
r_fancy_list = [x for x in r_fancy.T.reshape(-1)]
g_fancy_list = [x for x in g_fancy.T.reshape(-1)]
b_fancy_list = [x for x in b_fancy.T.reshape(-1)]
# Same data, just a different "shape" and orientation (you could transpose the result right away)
assert r_fancy_list == rs
assert g_fancy_list == gs
assert b_fancy_list == bs
Давайте сделаем это просто и представим, что вы просто хотите возвести в квадрат значение каждого пикселя и сохранитьрезультат (я сомневаюсь, что вы действительно хотите это сделать, это просто для того, чтобы показать, что если ваша операция векторизована, это будет быстрее):
import numpy as np
# Original code with squaring
def square_em():
img = np.arange(30000).reshape(100, 100, 3)
pane_step, center = 20, 10
field_size = 5
rs = []
gs = []
bs = []
for i in range(0, field_size * pane_step, pane_step):
for j in range(0, field_size * pane_step, pane_step):
r, g, b, = img[i + center, center + j, :]
# Doing stuff...?
rs.append(r**2)
gs.append(g**2)
bs.append(b**2)
return rs, gs, bs
# Vectorized squaring
def square_em_vec():
img = np.arange(30000).reshape(100, 100, 3)
pane_step, center = 20, 10
field_size = 5
# Scroll over, tacked on a **2 to the end...
r, g, b = img[center:center+pane_step*field_size:pane_step, center:center+pane_step*field_size:pane_step, :].T ** 2
return r.T, g.T, b.T
Я поместил это в файл с именем test.py и буду использоватьIPython REPL для таймингов (просто потому, что это удобно, вы можете использовать cProfile
или что-то тоже):
In [1]: from test import square_em, square_em_vec
In [2]: %timeit square_em()
10000 loops, best of 3: 83.9 µs per loop
In [3]: %timeit square_em_vec()
The slowest run took 5.00 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 32.8 µs per loop
HTH.