开发者社区> 问答> 正文

两个Cython功能;为什么一个工作,另一个给NameError?

我正在尝试使用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

笔记本单元已按书面规定成功运行,因此我认为两个函数均已成功编译。但是,此代码按预期运行:

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

而此代码:

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

不会运行,并返回“ NameError:名称'evenness_c_type'未定义”。在没有%timeit装饰器的情况下,我得到的结果相同,并且在使用'cpdef'或'def'代替'cdef'时,函数无法编译。由于我试图对两个函数使用相同的语法,所以我不知道是什么导致了nessness_c_type的错误。

编辑感谢@DavidW,我找出了nessness_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)

问题来源:stackoverflow

展开
收起
is大龙 2020-03-24 20:30:46 424 0
1 条回答
写回答
取消 提交回答
  • 原则上都不应该使用timeit。timeit接受Python对象,而cdef函数不是Python对象。但是,在某些情况下,Cython会自动从cdef function-> Python对象创建一个转换(有效地使其变为cpdef)。

    不使用cpdef进行编译的原因是由于生成器表达式(`“”尚不支持cpdef函数内的闭包“”)

    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函数的原因是因为您指定了返回类型。

    考虑是否真的需要使它为cdef / cpdef。大多数情况下,收益很小。

    回答来源:stackoverflow

    2020-03-24 20:30:53
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
Python系列直播第一讲——Python中的一切皆对象 立即下载
Python 脚本速查手册 立即下载
低代码开发师(初级)实战教程 立即下载