【问题标题】:Cython program with numpy arrays does not allow vectorized inputs (only accepts length 1 arrays), how to fix?带有 numpy 数组的 Cython 程序不允许矢量化输入(仅接受长度为 1 的数组),如何解决?
【发布时间】:2016-05-11 15:29:28
【问题描述】:

已修复:请参阅下面的更新代码。

这是我第一次尝试 Cython 并且有一个有效的构建,但它不允许 numpy 数组(向量)作为输入,这是我在这里的真正目的。它是 Black 模型(Black Scholes 用于没有股息的欧洲期权定价)。它只接受长度为 1 的数组作为输入(如果我尝试使用长度为 2 的数组进行计算,则会出错:TypeError: CyBlack() takes exactly 7 positional arguments (14 given),如果我传递长度为 10 的数组,(70 given) 等)。我不确定为什么我在 Cython 代码中定义了 numpy 数组。作为参考,您可以使用以下代码对其进行编译,然后按如下方式使用它:from CyBlack.CyBlack import CyBlack 然后调用CyBlack(BlackPnL, Black_S, Black_Texpiry, Black_strike, Black_volatility, Black_IR, Black_callput) 这是代码(另存为CyBlack.pyx 文件进行编译):

from numpy cimport ndarray
cimport numpy as np
cimport cython

cdef extern from "math.h":
    double exp(double)
    double sqrt(double)
    double log(double)
    double erf(double)

cdef double std_norm_cdf(double x):
    return 0.5*(1+erf(x/sqrt(2.0)))

@cython.boundscheck(False)
cpdef CyBlack(ndarray[np.float64_t, ndim=1] BlackPnL, ndarray[np.float64_t, ndim=1] Black_S, ndarray[np.float64_t, ndim=1] Black_Texpiry, ndarray[np.float64_t, ndim=1] Black_strike, ndarray [np.float64_t, ndim=1] Black_volatility, ndarray[np.float64_t, ndim=1] Black_IR, ndarray[np.int64_t, ndim=1] Black_callput):

    cdef Py_ssize_t i
    cdef Py_ssize_t N = BlackPnL.shape[0]
    cdef double d1, d2


    for i in range(N):
        d1 = ((log(Black_S[i] / Black_strike[i]) + Black_Texpiry[i] * Black_volatility[i] **2 / 2)) / (Black_volatility[i] * sqrt(Black_Texpiry[i]))
        d2 = d1 - Black_volatility[i] * sqrt(Black_Texpiry[i])
        BlackPnL[i] = exp(-Black_IR[i] * Black_Texpiry[i]) * (Black_callput[i] * Black_S[i] * std_norm_cdf(Black_callput[i] * d1) - Black_callput[i] * Black_strike[i] * std_norm_cdf(Black_callput[i] * d2)) 

    return BlackPnL

这是setup.py,因此其他人可以构建此类型:python setup.py build_ext --inplace 为 Python 3.5 64 位 Windows 使用 VS2015 构建。

from distutils.core import setup
from Cython.Build import cythonize
import numpy

extra_compile_args = ['/EHsc', '/openmp', '/favor:INTEL64']

setup(
ext_modules=cythonize("CyBlack.pyx"),
include_dirs=['.', numpy.get_include()],
extra_compile_args=extra_compile_args)

在对变量类型使用修复后,上面的编译和工作(Black_callput 实际上是一个int64),你必须按原样传递 numpy 数组(没有星号),它可以正常工作。

【问题讨论】:

  • “它一次只会计算 1 个值” - 你到底是什么意思?
  • “您必须将 numpy 数组传递给带有星号的函数” - 什么?你为什么这样做?那要么是你的全部问题,要么是你问题的很大一部分。向我们展示您传递的参数以及方法。
  • “您必须将 numpy 数组传递给带有星号的函数,以 *Black_PnL 为例” - 嗯,不!尝试将它们作为单独的参数传递。
  • ValueError: Buffer dtype mismatch, expected 'float64_t' but got 'long long' 如果您只是在没有星号的情况下传递值,则结果。
  • 好的,现在ValueError 表示您传递的是一个 int64 数组,而不是输入类型声明中指定的 float64

标签: python numpy cython


【解决方案1】:

这里有两个问题:

  1. TypeError: CyBlack() takes exactly 7 positional arguments (14 given)

    这是由于您使用 * ("splat") 运算符对输入数组进行解包这一事实造成的。您需要将它们作为 7 个单独的参数传入。

  2. ValueError: Buffer dtype mismatch, expected 'float64_t' but got 'long long':

    此错误告诉您其中一个输入数组的 C 类型为 long long(这是一个 64 位整数),而不是您输入类型声明中指定的 float64_t。您需要将所有输入数组转换为 np.float64

【讨论】:

    猜你喜欢
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    相关资源
    最近更新 更多