6

考虑以下类:

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

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

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

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

那么我的替代方案是什么?使用Python C-API编写 C 函数会摆脱开销吗?还有其他方法可以加快计算速度吗?

4

2 回答 2

2

以下 cython 代码(我意识到第一行__init__是不同的,我用随机的东西替换它,因为我不知道var,因为无论如何都没关系 - 你说__call__的是瓶颈):

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

通过一个简单的 setup.py 编译(只是文件名更改的文档中的示例),它在简单的设计基准测试中的性能比等效的纯 python 好近 20 倍timeit。请注意,唯一更改的是字段和参数cdef的 s 。我认为这非常令人印象深刻。_norm__call__

于 2010-11-21T18:49:13.660 回答
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
于 2010-11-21T18:28:58.900 回答