首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用numexpr的欧几里德范数

使用numexpr的欧几里德范数
EN

Stack Overflow用户
提问于 2013-10-29 09:13:48
回答 1查看 755关注 0票数 1

我需要用numexpr重写这个代码,它是计算矩阵数据行x cols和向量1x cols的欧几里德范数矩阵。

代码语言:javascript
复制
d = ((data-vec)**2).sum(axis=1)

怎么做呢?也许还有另一种更快的方法?

我使用hdf5时遇到的问题,以及从中读取的数据矩阵。例如,这段代码会产生错误:对象没有对齐。

代码语言:javascript
复制
#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.carrayi*rows:(i+1)*行,它必须重新分配吗?

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-29 09:41:50

有一种可能的快速方法(对于非常大的数组)是只使用NumPy的,这是在scikit中使用的--学习:

代码语言:javascript
复制
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)2=x 2+y 2-2 2xy,即使对矢量也是如此。

测试:

代码语言:javascript
复制
>>> 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])

配置文件:

代码语言:javascript
复制
>>> 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点时,它也不会更好):

代码语言:javascript
复制
>>> %timeit ne.evaluate("sum((data - vec) ** 2, axis=1)")
10000 loops, best of 3: 142 us per loop
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19653951

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档