我正在尝试使用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,我找出了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)
原则上都不应该与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
。在大多数情况下,收益很小。