У меня есть вопрос о том, как вычислить расстояния в NumPy так быстро, как это возможно,более эффективный способ вычисления расстояния в numpy?
def getR1(VVm,VVs,HHm,HHs):
t0=time.time()
R=VVs.flatten()[numpy.newaxis,:]-VVm.flatten()[:,numpy.newaxis]
R*=R
R1=HHs.flatten()[numpy.newaxis,:]-HHm.flatten()[:,numpy.newaxis]
R1*=R1
R+=R1
del R1
print "R1\t",time.time()-t0, R.shape, #11.7576191425 (108225, 10500)
print numpy.max(R) #4176.26290975
# uses 17.5Gb ram
return R
def getR2(VVm,VVs,HHm,HHs):
t0=time.time()
precomputed_flat = numpy.column_stack((VVs.flatten(), HHs.flatten()))
measured_flat = numpy.column_stack((VVm.flatten(), HHm.flatten()))
deltas = precomputed_flat[None,:,:] - measured_flat[:, None, :]
#print time.time()-t0, deltas.shape # 5.861109972 (108225, 10500, 2)
R = numpy.einsum('ijk,ijk->ij', deltas, deltas)
print "R2\t",time.time()-t0,R.shape, #14.5291359425 (108225, 10500)
print numpy.max(R) #4176.26290975
# uses 26Gb ram
return R
def getR3(VVm,VVs,HHm,HHs):
from numpy.core.umath_tests import inner1d
t0=time.time()
precomputed_flat = numpy.column_stack((VVs.flatten(), HHs.flatten()))
measured_flat = numpy.column_stack((VVm.flatten(), HHm.flatten()))
deltas = precomputed_flat[None,:,:] - measured_flat[:, None, :]
#print time.time()-t0, deltas.shape # 5.861109972 (108225, 10500, 2)
R = inner1d(deltas, deltas)
print "R3\t",time.time()-t0, R.shape, #12.6972110271 (108225, 10500)
print numpy.max(R) #4176.26290975
#Uses 26Gb
return R
def getR4(VVm,VVs,HHm,HHs):
from scipy.spatial.distance import cdist
t0=time.time()
precomputed_flat = numpy.column_stack((VVs.flatten(), HHs.flatten()))
measured_flat = numpy.column_stack((VVm.flatten(), HHm.flatten()))
R=spdist.cdist(precomputed_flat,measured_flat, 'sqeuclidean') #.T
print "R4\t",time.time()-t0, R.shape, #17.7022118568 (108225, 10500)
print numpy.max(R) #4176.26290975
# uses 9 Gb ram
return R
def getR5(VVm,VVs,HHm,HHs):
from scipy.spatial.distance import cdist
t0=time.time()
precomputed_flat = numpy.column_stack((VVs.flatten(), HHs.flatten()))
measured_flat = numpy.column_stack((VVm.flatten(), HHm.flatten()))
R=spdist.cdist(precomputed_flat,measured_flat, 'euclidean') #.T
print "R5\t",time.time()-t0, R.shape, #15.6070930958 (108225, 10500)
print numpy.max(R) #64.6240118667
# uses only 9 Gb ram
return R
def getR6(VVm,VVs,HHm,HHs):
from scipy.weave import blitz
t0=time.time()
R=VVs.flatten()[numpy.newaxis,:]-VVm.flatten()[:,numpy.newaxis]
blitz("R=R*R") # R*=R
R1=HHs.flatten()[numpy.newaxis,:]-HHm.flatten()[:,numpy.newaxis]
blitz("R1=R1*R1") # R1*=R1
blitz("R=R+R1") # R+=R1
del R1
print "R6\t",time.time()-t0, R.shape, #11.7576191425 (108225, 10500)
print numpy.max(R) #4176.26290975
return R
результаты в следующих случаях:
R1 11.7737319469 (108225, 10500) 4909.66881791
R2 15.1279799938 (108225, 10500) 4909.66881791
R3 12.7408981323 (108225, 10500) 4909.66881791
R4 17.3336868286 (10500, 108225) 4909.66881791
R5 15.7530870438 (10500, 108225) 70.0690289494
R6 11.670968771 (108225, 10500) 4909.66881791
В то время как последняя дает SQRT ((VVM-VVS)^2 + (HHm-HHs)^2), а остальные дают (VVm-VVs)^2 + (HHm-HHs)^2. Это не очень важно, так как иначе в моем коде я беру минимум из R [i ,:] для каждого i, и sqrt никак не влияет на минимальное значение (и если меня интересует расстояние, я просто беру sqrt (value) вместо того, чтобы делать sqrt по всему массиву, так что на самом деле нет времени разница из-за этого.
Вопрос остается: как первое решение является лучшим (причина, по которой вторая и третья медленнее, потому что deltas = ... занимает 5.8 сек. (Что также объясняет, почему эти два метода принимают 26 Гб)), И почему sqeuclidean медленнее, чем евклид?
sqeuclidean должен просто делать (VVm-VVs)^2 + (HHm-HHs)^2, в то время как я думаю, что он делает что-то другое. Кто-нибудь знает, как найти исходный код (C или что-то еще внизу) этого метода? Я думаю, что это делает sqrt ((VVm-VVs)^2 + (HHm-HHs)^2)^2 (единственная причина, по которой я могу думать, почему она будет медленнее, чем (VVm-VVs)^2 + (HHm-HHs)^2 - Я знаю, что это глупая причина, кто-нибудь получил более логичный?)
Так как я ничего не знаю о C, как бы это сделать с помощью scipy.weave? и является ли этот код компилируемым, как правило, с помощью python? или мне нужны специальные материалы для этого?
Редактирование: хорошо, я попробовал его с scipy.weave.blitz, (метод R6), и это немного быстрее, но я предполагаю, что кто-то, кто знает больше C, чем я, может еще улучшить эту скорость? Я просто взял строки, которые имеют форму a = = b или * =, и посмотрел, как они будут на C, и помещает их в блиц-предложение, но я думаю, если бы я поместил строки с операторами с flatten и newaxis в C также, что он должен идти быстрее, но я не знаю, как я могу это сделать (кто-то, кто знает C, может объяснить?). Прямо сейчас, разница между материалом с блицом и моим первым методом невелика, чтобы действительно быть вызвана C vs numpy, я думаю?
Я думаю, что другие методы, например, с deltas = ... могут идти намного быстрее, когда я буду помещать их в C?
рассмотрите попытку чего-то по строкам http://jakevdp.github.io/blog/2013/06/15/numba-vs-cython-take-2/ (esp 'numpy with broadcasting' part) –
Вы возможно, сбрил бы несколько секунд, не выделяя память для «R» (т. е. просто используйте «R1 + = R3»). – bogatron
@bogatron да, так же, как R1 * = R1, но все же, что не уменьшит его до 1сек или около того (что я предполагаю, должно произойти, когда оно полностью находится в C от numpy)? – usethedeathstar