【问题标题】:Two Cython functions; why does one work, and the other give NameError?两个 Cython 函数;为什么一个有效,另一个给出 NameError?
【发布时间】:2020-03-11 16:28:39
【问题描述】:

我正在尝试使用 Cython 来加速我的 Python 脚本的某些部分。一个关键部分将函数应用于 Pandas 数据框;因为这做了很多次,所以我想用 Cython 编写这些函数以加快计算速度。函数如下,并且位于同一个 Jupyter 笔记本单元格中:

%%cython
cimport numpy as np
import numpy as np

cdef double breadth_c_type(np.ndarray[np.float64_t, ndim=1] arr):
    """ Calculates range between the maximum and minimum values of a given list. """
    return (max(arr) - min(arr))

cdef double evenness_c_type(np.ndarray[np.float64_t, ndim=1] arr):
    """ Calculates the sample variance of differences between values in a sorted list. """
    cdef np.ndarray[double] sorted_arr
    cdef list desc_diff
    cdef double m
    cdef double var_res
    sorted_arr = sorted(arr)
    desc_diff = []
    for x in range(len(arr)-1):
        desc_diff.append(sorted_arr[x+1]-sorted_arr[x])
    # following used to avoid usage of numpy
    m = sum(desc_diff) / len(desc_diff)
    var_res = sum((xi - m)**2 for xi in desc_diff) / len(desc_diff)
    return var_res

notebook cell 运行成功,所以我认为这两个函数都编译成功了。但是,此代码按预期运行:

%timeit rand_df.apply(breadth_c_type, raw=True)

而这段代码:

%timeit rand_df.apply(evenness_c_type, raw=True)

不运行,并返回“NameError: name 'evenness_c_type' is not defined”。如果没有 %timeit 装饰器,我会得到相同的结果,并且当使用 'cpdef' 或 'def' 代替 'cdef' 时,函数不会编译。由于我尝试对这两个函数使用相同的语法,所以我不知道是什么导致了 evenness_c_type 的错误。

编辑 感谢@DavidW,我发现了evenness_c_type() 函数的问题。它编译和运行良好,虽然不如普通 Cython 版本快。

cdef double evenness_c_type(np.ndarray[np.float64_t, ndim=1] arr):
    """ Calculates the population variance of differences between values in a sorted list. """
    cdef np.ndarray [double] desc_diff=np.empty(len(arr)-1, dtype = np.float64)
    arr.sort()
    for x in range(len(arr)-1):
        desc_diff[x]=(arr[x+1]-arr[x])
    return np.var(desc_diff)

【问题讨论】:

    标签: python-3.x numpy cython


    【解决方案1】:

    原则上两者都不应该与timeit 一起使用。 timeit 接受 Python 对象,而 cdef 函数不是 Python 对象。但是,在某些情况下,Cython 会自动创建从 cdef 函数->Python 对象的转换(有效地使其成为cpdef)。

    它没有用cpdef 编译的原因是生成器表达式("closures inside cpdef functions not yet supported"

    var_res = sum((xi - m)**2 for xi in desc_diff) / len(desc_diff)
    

    我收到了这样的错误消息,虽然编译器崩溃了,所以它们不是最清楚的

    用列表理解替换它就可以了(虽然它看起来不是特别好优化)

    var_res = sum([(xi - m)**2 for xi in desc_diff]) / len(desc_diff)
    

    我怀疑没有为cdef 函数生成自动转换的原因是这个生成器表达式。

    它不编译为def 函数的原因是您指定了返回类型。

    考虑whether you really need to make it cdef/cpdef。大多数时候没有什么好处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      相关资源
      最近更新 更多