нажать цикл для numpy

Можно ли сделать следующий цикл for быстрее, переместив его в numpy?

ri = numpy.zeros((R.shape[0],R.shape[2]))
for i in range(R.shape[0]):
    ri[i, :] = R[i, indices[i], :]

Это относится к моему предыдущему вопросу: если столбец полностью nan , что должно было ускорить этот бит:

bestepsilons = numpy.zeros((R.shape[0]))
for i in range(R.shape[0]):
    bestindex = numpy.nanargmin(R[i,:])
    if(numpy.isnan(bestindex)):
        bestepsilons[i]=numpy.nan
    else:
        bestepsilons[i]=epsilon[bestindex]

и решил (сам) как:

bestepsilons1 = numpy.zeros(R.shape[0])+numpy.nan
d0 = numpy.nanmin(R, axis=1) # places where the best index is not a nan
bestepsilons1[~numpy.isnan(d0)] = epsilon[numpy.nanargmin(R[~numpy.isnan(d0),:], axis=1)]

Но теперь более сложный случай:

bestepsilons = numpy.zeros((R.shape[0]))
for i in range(R.shape[0]):
    bestindex = numpy.nanargmin(R[i,indices[i],:])
    if(numpy.isnan(bestindex)):
        bestepsilons[i]=numpy.nan
    else:
        bestepsilons[i]=epsilon[bestindex]

И теперь этот трюк, чтобы показать места, где лучший индекс не является наном, больше не работает с этим аргументом оси.


person usethedeathstar    schedule 13.03.2014    source источник


Ответы (2)


Можно нажать его на numpy, но будет ли это быстрее, будет зависеть от размеров ваших массивов. Надеюсь, есть более элегантное решение, но это работает:

ii = np.arange(R.shape[0]) * R.shape[1] + indices
ri = R.reshape(-1, R.shape[2])[ii]

Вот пара временных тестов:

def f1(R, indices):
    ri = numpy.zeros((R.shape[0],R.shape[2]))
    for i in range(R.shape[0]):
        ri[i, :] = R[i, indices[i], :]
    return ri

def f2(R, indices):
    ii = np.arange(R.shape[0]) * R.shape[1] + indices
    return R.reshape(-1, R.shape[2])[ii]

Меньший R:

In [25]: R = np.random.rand(30, 40, 50)
In [26]: indices = np.random.choice(range(R.shape[1]), R.shape[0], replace=True) 
In [27]: %timeit(f1(R, indices))
10000 loops, best of 3: 61.4 us per loop
In [28]: %timeit(f2(R, indices))
10000 loops, best of 3: 21.9 us per loop

Большой R:

In [29]: R = np.random.rand(300, 400, 500)
In [30]: indices = np.random.choice(range(R.shape[1]), R.shape[0], replace=True) 
In [31]: %timeit(f1(R, indices))
1000 loops, best of 3: 713 us per loop
In [32]: %timeit(f2(R, indices))
1000 loops, best of 3: 1.23 ms per loop

In [33]: np.all(f1(R, indices) == f2(R, indices))
Out[33]: True
person bogatron    schedule 13.03.2014

Найдено, что это быстрее примерно на 10%:

d1 = numpy.arange(R.shape[0])[:,None]
d2 = indices[numpy.arange(R.shape[0])][:,None]
d3 = numpy.arange(R.shape[2])[None,:]
ri = R[d1,d2,d3]

bestepsilons = numpy.zeros(R.shape[0])+numpy.nan
d0 = numpy.nanmin(ri, axis=1) # places where the best index is not a nan
bestepsilons[~numpy.isnan(d0)] = epsilon[numpy.nanargmin(ri[~numpy.isnan(d0),:], axis=1)]

Но это с R, определенным как:

R = (self.VVm[:,None,None]-VVs[None,:,:])**2 + (self.HHm[:,None,None]-HHs[None,:,:])**2 

и я обнаружил, что если я определю R по-другому, это значительно ускорит загрузку:

ti = indices[numpy.arange(len(VVm))]
R1 = (VVm[:,None]-VVs[ti,:])**2+(HHm[:,None]-HHs[ti,:])**2
d0 = numpy.nanmin(R1, axis=1) # places where the best index is not a nan
bestepsilons2[~numpy.isnan(d0)] = epsilon[numpy.nanargmin(R1[~numpy.isnan(d0),:], axis=1)]

Таким образом, ему не нужно делать 3D R, а делать это непосредственно в 2D (получает ускорение в 4 раза).

person usethedeathstar    schedule 13.03.2014