考虑以下类:

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函数,它的计算,但显然转换的参数和返回值的远至昂贵的,因为产生的代码是要慢得多。

我当然可以实现整个KNN C和只是调用,但问题是,像我所描述的,我使用不同的距离函数的向量的一些尺寸,并翻译这些至C将是太多的工作

那么,什么是我的选择吗?会写使用 Python的C-API 摆脱开销的C函数?是否有任何其他方式来加速这一计算呢?

有帮助吗?

解决方案

下面用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(只是的来自实施例编译在文档结构改变的文件名),它的性能比在一个简单的contrieved timeit基准相当于纯Python更好的近20倍。请注意,只改者为cdef_norms和__call__参数。我认为这是相当令人印象深刻。

其他提示

这可能会帮助不大,但可以使用嵌套函数重写:

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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top