numpy.take можно применять в 2 измерениях с помощью
np.take(np.take(T,ix,axis=0), iy,axis=1 )
Я протестировал шаблон дискретного двумерного лапласиана
ΔT = T[ix-1,iy] + T[ix+1, iy] + T[ix,iy-1] + T[ix,iy+1] - 4 * T[ix,iy]
с 2 схемами взятия и обычной схемой numpy.array. Функции p и q введены для более компактного написания кода и обращаются к оси 0 и 1 в другом порядке. Это код:
nx = 300; ny= 300
T = np.arange(nx*ny).reshape(nx, ny)
ix = np.linspace(1,nx-2,nx-2,dtype=int)
iy = np.linspace(1,ny-2,ny-2,dtype=int)
#------------------------------------------------------------
def p(Φ,kx,ky):
return np.take(np.take(Φ,ky,axis=1), kx,axis=0 )
#------------------------------------------------------------
def q(Φ,kx,ky):
return np.take(np.take(Φ,kx,axis=0), ky,axis=1 )
#------------------------------------------------------------
%timeit ΔT_n = T[0:nx-2,1:ny-1] + T[2:nx,1:ny-1] + T[1:nx-1,0:ny-2] + T[1:nx-1,2:ny] - 4.0 * T[1:nx-1,1:ny-1]
%timeit ΔT_t = p(T,ix-1,iy) + p(T,ix+1,iy) + p(T,ix,iy-1) + p(T,ix,iy+1) - 4.0 * p(T,ix,iy)
%timeit ΔT_t = q(T,ix-1,iy) + q(T,ix+1,iy) + q(T,ix,iy-1) + q(T,ix,iy+1) - 4.0 * q(T,ix,iy)
.
1000 loops, best of 3: 944 µs per loop
100 loops, best of 3: 3.11 ms per loop
100 loops, best of 3: 2.02 ms per loop
Результаты кажутся очевидными:
- обычная арифметика индекса numpy быстрее всего
- схема взятия q занимает на 100 % больше времени (= C-заказ?)
- схема взятия p занимает на 200% больше времени (= Fortran-упорядочивание?)
Даже одномерный пример руководства по scipy указывает, что numpy.take работает быстро:
a = np.array([4, 3, 5, 7, 6, 8])
indices = [0, 1, 4]
%timeit np.take(a, indices)
%timeit a[indices]
.
The slowest run took 6.58 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 4.32 µs per loop
The slowest run took 7.34 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 3.87 µs per loop
У кого-нибудь есть опыт, как сделать numpy.take быстро? Это был бы гибкий и привлекательный способ написания бережливого кода, быстрый в написании кода и
также считается быстрым в исполнении. Спасибо за некоторые подсказки, чтобы улучшить мой подход!
np.ix_
:T[np.ix_(ix,iy)]
? - person Divakar   schedule 25.07.2017np.take
немного быстрее, чем нотация индексации. Но преимущество достаточно маленькое, чтобы обернуть его в вызов функции, как вы это делаете, может разрушить его. stackoverflow.com/ вопросы/44487889/ - person hpaulj   schedule 25.07.2017np.ix_
(но пропустил его из-за краткости в моем вопросе): в моих тестахnp.ix_
был медленнее, чем лучший np.take - person pyano   schedule 25.07.2017ix
иiy
всегда следовать такому шаблону постоянного размера шага в своих индексах? - person Divakar   schedule 25.07.2017T[0:nx-2,1:ny-1]
— это представление (базовая индексация с 2 срезами).p(T,ix-1,iy)
— это копия, индексация с двумя массивами. Суммы будут, конечно, копией.take
может быть быстрее, чем прямое "причудливое" индексирование,T[ix-1,:][:,iy]
- person hpaulj   schedule 25.07.2017np.ix_
, добавив в мой код выше следующее:from numpy import ix_ as q; ΔT_ix_ = T[q(ix-1,iy)] + T[q(ix+1,iy)] + T[q(ix,iy-1)] + T[q(ix,iy+1)] - 4.0 * T[q(ix,iy)]
- person pyano   schedule 25.07.2017T[ix-1,iy]
не дает желаемого результата. - person pyano   schedule 25.07.2017ix
иiy
обычно не слишком дикие. Но есть большие массивы. - person pyano   schedule 25.07.2017T[(ix-1)[:,None], iy]
или пустьix_
сделает это за вас. - person hpaulj   schedule 25.07.2017slicing
: T[ix_start:ix_end:ix_stepsize,..]`. - person Divakar   schedule 25.07.2017