евклидова норма с использованием numexpr

Мне нужно переписать этот код с помощью numexpr, он вычисляет матрицу нормалей евклидова матричных данных [rows x cols] и vector [1 x cols].

d = ((data-vec)**2).sum(axis=1) 

Как это можно сделать? Возможно, есть еще один более быстрый метод?

Проблема, из-за которой я использую hdf5, и данные, полученные из нее. Например, этот код дает ошибку: объекты не выровнены.

 #naive numpy solution, can be parallel? def test_bruteforce_knn(): h5f = tables.open_file(fileName) t0= time.time() d = np.empty((rows*batches,)) for i in range(batches): d[i*rows:(i+1)*rows] = ((h5f.root.carray[i*rows:(i+1)*rows]-vec)**2).sum(axis=1) print (time.time()-t0) ndx = d.argsort() print ndx[:k] h5f.close() #using some tricks (don't work error: objects are not aligned ) def test_bruteforce_knn(): h5f = tables.open_file(fileName) t0= time.time() d = np.empty((rows*batches,)) for i in range(batches): d[i*rows:(i+1)*rows] = (np.einsum('ij,ij->i', h5f.root.carray[i*rows:(i+1)*rows], h5f.root.carray[i*rows:(i+1)*rows]) + np.dot(vec, vec) -2 * np.dot(h5f.root.carray[i*rows:(i+1)*rows], vec)) print (time.time()-t0) ndx = d.argsort() print ndx[:k] h5f.close() 

Использование numexpr: кажется, что numexpr не понимает h5f.root.carray [i * rows: (i + 1) * rows] его нужно переназначить?

 import numexpr as ne def test_bruteforce_knn(): h5f = tables.open_file(fileName) t0= time.time() d = np.empty((rows*batches,)) for i in range(batches): ne.evaluate("sum((h5f.root.carray[i*rows:(i+1)*rows] - vec) ** 2, axis=1)") print (time.time()-t0) ndx = d.argsort() print ndx[:k] h5f.close() 

One Solution collect form web for “евклидова норма с использованием numexpr”

Существует потенциально быстрый способ (для очень больших массивов) с использованием только NumPy, который используется в scikit-learn:

 def squared_row_norms(X): # From http://stackoverflow.com/q/19094441/166749 return np.einsum('ij,ij->i', X, X) def squared_euclidean_distances(data, vec): data2 = squared_row_norms(data) vec2 = squared_row_norms(vec) d = np.dot(data, vec.T).ravel() d *= -2 d += data2 d += vec2 return d 

Это основано на том, что (x – y) ² = x² + y² – 2xy, даже для векторов.

Контрольная работа:

 >>> data = np.random.randn(10, 40) >>> vec = np.random.randn(1, 40) >>> ((data - vec) ** 2).sum(axis=1) array([ 96.75712686, 69.45894306, 100.71998244, 80.97797154, 84.8832107 , 82.28910021, 67.48309433, 81.94813371, 64.68162331, 77.43265692]) >>> squared_euclidean_distances(data, vec) array([ 96.75712686, 69.45894306, 100.71998244, 80.97797154, 84.8832107 , 82.28910021, 67.48309433, 81.94813371, 64.68162331, 77.43265692]) >>> from sklearn.metrics.pairwise import euclidean_distances >>> euclidean_distances(data, vec, squared=True).ravel() array([ 96.75712686, 69.45894306, 100.71998244, 80.97797154, 84.8832107 , 82.28910021, 67.48309433, 81.94813371, 64.68162331, 77.43265692]) 

Профиль:

 >>> data = np.random.randn(1000, 40) >>> vec = np.random.randn(1, 40) >>> %timeit ((data - vec)**2).sum(axis=1) 10000 loops, best of 3: 114 us per loop >>> %timeit squared_euclidean_distances(data, vec) 10000 loops, best of 3: 52.5 us per loop 

Использование numexpr также возможно, но, похоже, оно не дает ускорения на 1000 пунктов (и на 10000 оно не намного лучше):

 >>> %timeit ne.evaluate("sum((data - vec) ** 2, axis=1)") 10000 loops, best of 3: 142 us per loop 
Python - лучший язык программирования в мире.