当前位置: 首页 > 知识库问答 >
问题:

两个Cython函数;为什么一个工作,而另一个给出NameError?

缪征
2023-03-14

我正在尝试使用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: name'evenness_c_type'未定义"。我在没有%timeit装饰器的情况下得到相同的结果,并且在使用'cpdef'或'def'代替'cdef'时函数不会编译。由于我尝试为两个函数遵循相同的语法,我不知道是什么导致了evenness_c_type的错误。

多亏了@DavidW,我才解决了evenness\u c\u 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)

共有1个答案

臧烨烁
2023-03-14

原则上,两者都不应与timeit一起使用timeit接受Python对象,而cdef函数不是Python对象。但是,在某些情况下,Cython将自动创建从cdef函数的转换-

它不使用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。大多数时候没有什么好处。

 类似资料:
  • 问题内容: 我在编写Traveling Salesman程序时遇到了这个问题。对于内部循环,我尝试了 但是在该列表中添加另一个点时会导致被抛出。 但是,当我将循环更改为 循环运行良好,没有引发异常。 这两个都是for循环,那么为什么一个抛出异常却另一个没有抛出异常呢? 问题答案: 正如其他人解释的那样,迭代器检测到对基础集合的修改,这是一件好事,因为它可能会导致意外的行为。 想象一下下面的无迭代器

  • 我一直在做一个项目,在汇编中写一个递归函数,在那里它将计算斐波那契数。一开始我用Java代码写的: 这个递归函数工作得非常好。虽然当尝试在汇编代码中实现它时,我没有得到我所期望的结果。在排除了一段时间的故障后,我在Java编写了大致等价的代码: 这个函数得到了和我在汇编代码中得到的一样错误的结果,虽然我仍然不明白为什么,我遗漏了什么?这两个函数重复的次数相同。 结果 ASMFibonacci 0

  • 我是计算机视觉新手,还没有真正学习过阈值、模糊或其他过滤器的教程。我使用下面两段代码找出图像中的轮廓。一方面,这种方法是有效的,但另一方面,它不是。我需要帮助理解发生这种情况的原因,以便说服自己背景中发生了什么。 工作代码段: 不工作的代码段 如果有人能找出这里发生的错误的原因,我将不胜感激。 我所面对的错误是: 回溯(最近一次调用last):文件“convexhull.py”,第27行,在im2

  • 我知道容器可以有其他参数,如填充或装饰,但如果我不使用这些,为什么我要使用SizedBox而不是容器? 它们之间存在性能差异?

  • 我试图学习功能性Kotlin,并编写了以下测试代码: 在REPL中,我可以成功调用“findBorrowerX”: 但是我如何拨打“findBorrowerX2”的电话: 并将迭代的借用器x传递给getName?? 这看起来有关联,但我不确定: Kotlin:如何将一个函数作为参数传递给另一个? 提前感谢您对此的帮助! 编辑: 下面是我想做的等效Scala代码: 也许这在科特林是不可能的?

  • 问题内容: 我想将传递给function()的所有参数作为参数传递给内部的另一个function(), 这可以在被调用过程中完成并将它们传递给,但是还有另一种方法吗? 本来 但是如果我的func1签名是 我如何将它们全部发送到func2,而不使用 有没有一种方法像在javascript中? 问题答案: 显式比隐式更好, 但是如果您真的不想键入一些字符,请执行以下操作: 都是局部变量,因此您不能在调