建议

2010-11-21 43 views
5

考虑下面的类:建议

class SquareErrorDistance(object): 
    def __init__(self, dataSample): 
     variance = var(list(dataSample)) 
     if variance == 0: 
      self._norm = 1.0 
     else: 
      self._norm = 1.0/(2 * variance) 

    def __call__(self, u, v): # u and v are floats 
     return (u - v) ** 2 * self._norm 

我用它来计算一个矢量的两个元素之间的距离。我基本上为使用此距离度量的向量的每个维度创建该类的一个实例(有使用其他距离度量的维度)。分析表明,这个类的功能占我knn实现的运行时间的90%(谁会想到)。我不认为有任何纯Python的方式来加速,但也许如果我在C中实现它?

如果我运行一个简单的C程序,它使用上面的公式计算随机值的距离,它比Python快几个数量级。所以我尝试使用ctypes并调用一个执行计算的C函数,但显然参数和返回值的转换远远要昂贵,因为结果代码要慢得多。

我当然可以在C中实现整个kn并且只是调用它,但问题是,就像我所描述的,我使用不同的距离函数来处理矢量的某个维度,并且将这些转换为C会太多工作。

那么我的替代方案是什么?使用Python C-API编写C函数会摆脱开销吗?有没有其他的方法来加速这个计算?

+0

我会建议Cython(答案与示例实现可能会在几分钟内)。我猜你算法已经尽可能地调整过了吗? – delnan 2010-11-21 18:09:24

+0

@delnan:我已经在可能和适当的地方使用了缓存,所以我没有看到任何保存距离计算的方法。 – 2010-11-21 18:17:48

+0

那么......无关,什么是'dataSample'和'var'? – delnan 2010-11-21 18:21:52

回答

1

下面用Cython代码(我知道的__init__第一线不同的是,我用随机的东西,因为它取代我不知道var因为它不怎样都无所谓 - 你说__call__是瓶颈):通过一个简单的setup.py(只是the example from the docs结构改变文件名)编译

cdef class SquareErrorDistance: 
    cdef double _norm 

    def __init__(self, dataSample): 
     variance = round(sum(dataSample)/len(dataSample)) 
     if variance == 0: 
      self._norm = 1.0 
     else: 
      self._norm = 1.0/(2 * variance) 

    def __call__(self, double u, double v): # u and v are floats 
     return (u - v) ** 2 * self._norm 

,它在一个简单的调查timeit基准测试中,它的性能比同等级的纯Python高出近20倍。请注意,唯一更改为cdef s的_norm字段和__call__参数。我认为这很令人印象深刻。

+0

**这是 - 令人惊叹**。非常感谢。我实际上可以将这个(意思是Cython)应用于许多其他热点。你只是让我的一天:) – 2010-11-21 19:09:00

+1

@ Space_C0wb0y:总是很高兴帮助:)如果你使用numpy重,也可以看看http://docs.cython。组织/ src目录/教程/ numpy.html。 – delnan 2010-11-21 19:26:36

+0

您也可以声明差异为双倍。它可能不会有很大的区别,但为什么不呢? – 2010-11-22 03:27:03

0

这可能帮助不大,但可以将其使用嵌套函数改写:

def SquareErrorDistance(dataSample): 
    variance = var(list(dataSample)) 
    if variance == 0: 
     def f(u, v): 
      x = u - v 
      return x * x 
    else: 
     norm = 1.0/(2 * variance) 
     def f(u, v): 
      x = u - v 
      return x * x * norm 
    return f