Cython: “致命错误:numpy/arrayobject.h:没有那个文件或目录”

185

我试图使用Cython加速这里的回答。我尝试编译代码(在执行此处解释的cygwinccompiler.py hack之后),但是遇到了一个fatal error: numpy/arrayobject.h: No such file or directory...compilation terminated 错误。有人能告诉我它是我的代码问题,还是Cython中的一些微妙细节?

以下是我的代码。

import numpy as np
import scipy as sp
cimport numpy as np
cimport cython

cdef inline np.ndarray[np.int, ndim=1] fbincount(np.ndarray[np.int_t, ndim=1] x):
    cdef int m = np.amax(x)+1
    cdef int n = x.size
    cdef unsigned int i
    cdef np.ndarray[np.int_t, ndim=1] c = np.zeros(m, dtype=np.int)

    for i in xrange(n):
        c[<unsigned int>x[i]] += 1

    return c

cdef packed struct Point:
    np.float64_t f0, f1

@cython.boundscheck(False)
def sparsemaker(np.ndarray[np.float_t, ndim=2] X not None,
                np.ndarray[np.float_t, ndim=2] Y not None,
                np.ndarray[np.float_t, ndim=2] Z not None):

    cdef np.ndarray[np.float64_t, ndim=1] counts, factor
    cdef np.ndarray[np.int_t, ndim=1] row, col, repeats
    cdef np.ndarray[Point] indices

    cdef int x_, y_

    _, row = np.unique(X, return_inverse=True); x_ = _.size
    _, col = np.unique(Y, return_inverse=True); y_ = _.size
    indices = np.rec.fromarrays([row,col])
    _, repeats = np.unique(indices, return_inverse=True)
    counts = 1. / fbincount(repeats)
    Z.flat *= counts.take(repeats)

    return sp.sparse.csr_matrix((Z.flat,(row,col)), shape=(x_, y_)).toarray()

你可以添加一个标签来说明你正在使用哪个操作系统吗? - tacaswell
@tcaswell 64位的Windows 7。 - Noob Saibot
添加了Windows标签,希望这个问题能够被会使用Windows的人看到(而不是像我这样的人)。 - tacaswell
1
我发现了这个链接:http://wiki.cython.org/64BitCythonExtensionsOnWindows。其中有一些专业术语超出了我的理解范畴,但我打算去看看。 - Noob Saibot
这个回答解决了你的问题吗?让distutils在正确的位置查找numpy头文件 - ead
8个回答

264

在您的setup.py文件中,Extension应该有参数include_dirs=[numpy.get_include()]

还有,您的代码中缺少np.import_array()

--

示例setup.py:

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

setup(
    ext_modules=[
        Extension("my_module", ["my_module.c"],
                  include_dirs=[numpy.get_include()]),
    ],
)

# Or, if you use cythonize() to make the ext_modules list,
# include_dirs can be passed to setup()

setup(
    ext_modules=cythonize("my_module.pyx"),
    include_dirs=[numpy.get_include()]
)    

5
我为什么需要np.import_array()?那不是为了Numpy C-API吗? - Noob Saibot
4
include_dirs=[numpy.get_include()] 是个好技巧,谢谢! - Daniel Farrell
21
在最新的distutils中,传递给setup()include_dirs会被忽略,必须传递给每个Extension,至少在Mac上是这样。 - dashesy
如果在调用Cython模块的Python代码中执行np.import_array(),则会出现AttributeError: 'module' object has no attribute 'import_array'错误。 - loretoparisi
谢谢您,看来这个关键步骤在Cython文档中确实缺失了! - Eddy
显示剩余5条评论

52

对于类似您的一个单文件项目,另一种选择是使用pyximport。您不需要创建setup.py……如果您使用IPython,则甚至不需要打开命令行……这非常方便。在您的情况下,请尝试在IPython或普通Python脚本中运行以下命令:

import numpy
import pyximport
pyximport.install(setup_args={"script_args":["--compiler=mingw32"],
                              "include_dirs":numpy.get_include()},
                  reload_support=True)

import my_pyx_module

print my_pyx_module.some_function(...)
...

当然,您可能需要编辑编译器。 这将使.pyx文件的导入和重新加载与.py文件的工作方式相同。

来源:http://wiki.cython.org/InstallingOnWindows


谢谢,@SteveB。但是你能详细解释一下你所说的“对于像你这样的单文件项目...”是什么意思吗?上面的模块是一个更大应用程序中的一个(尽管重要)部分。 pyximport 如何影响我的代码速度?最后,在这里的部分:"自Cython 0.11以来,pyximport模块还具有普通Python模块的实验编译支持..." 暗示它仍然有一些问题需要解决。你能解释一下吗? - Noob Saibot
1
关于“普通Python模块的实验性编译支持”——使用我上面建议的代码,.py模块将正常编译(不使用Cython),而.pyx模块将使用Cython编译。如果你在pyximport.install()中传入pyimport = True,那么它将对所有东西都使用Cython,即使是import randomimport os等。我不建议使用这个功能,因为没有强制使用它的理由,而且它可能会创建问题。它可能主要被Cython开发人员使用。 - Steve Byrnes
如果 pyximport 能够正常工作,它将创建与任何其他方法完全相同的 C 代码。所以试一下吧。我指的是当编译过程足够复杂时,例如链接到外部系统库,您可能会发现 pyximport 失败,需要使用 setup.pycythonize 来指定如何构建它。但是,您的 .pyx 模块具有 importcimport 并不意味着它不能使用 pyximport 编译;它可能完全没有问题。 - Steve Byrnes
这个很好用!但是如果你已经安装了MSVC,我建议使用--compiler=msvc。这样你就不需要安装Mingw了。 - Steve

19

该错误意味着在编译过程中找不到一个numpy头文件。

尝试执行export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, 然后进行编译。这是一些不同软件包的问题。在ArchLinux中,已经提交了一个关于同样问题的bug报告:https://bugs.archlinux.org/task/22326


我应该在哪里添加 export 行?是在我的 setup.py 文件中吗? - Noob Saibot
不,这是一个 shell 命令。在你的 shell 中运行它,然后开始编译。 - John Brodie
在 shell(运行 python setup.py 的地方)中,首先运行 export .. 命令。它设置了 shell 的环境变量,与 [pc]ython 没有直接关系。 - tacaswell
@tcaswell:我也是这么想的。我正在使用cmd,但是出现了“'export'不是内部或外部命令,也不是可运行的程序或批处理文件。”错误...这个问题真是让人头疼... - Noob Saibot
4
@NoobSaibot,你正在寻求Linux方面的解答来解决一个看起来像是Windows问题的情况。 - tacaswell
显示剩余6条评论

4
根据这个答案,如果你在Linux上使用pip安装了numpy,则需要手动设置符号链接到/usr/include/numpy
在我的情况下,路径是:
sudo ln -s /usr/local/lib/python3.8/dist-packages/numpy/core/include/numpy/ /usr/include/numpy

3
如果您懒得编写设置文件并确定包含目录的路径,可以尝试使用 cyper 工具。它可以自动编译您的Cython代码,并为Numpy设置include_dirs。
将代码加载到字符串中,然后简单运行cymodule = cyper.inline(code_string),此时您的函数即可立即作为cymodule.sparsemaker使用。类似这样:
code = open(your_pyx_file).read()
cymodule = cyper.inline(code)

cymodule.sparsemaker(...)
# do what you want with your function

您可以通过pip install cyper安装Cyper。

1

简单回答

更简单的方法是将文件路径添加到您的distutils.cfg文件中。对于Windows 7来说,它的默认路径是C:\Python27\Lib\distutils\。您只需插入以下内容即可:

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include

完整的配置文件

为了给您一个示例,配置文件可能如下所示,我的完整文件内容如下:

[build]
compiler = mingw32

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include
compiler = mingw32

1

根据这里提到的,应该能够在cythonize()函数中实现,但由于已知问题,它无法正常工作。


-1

我在运行的服务器上没有sudo权限,export CFLAGS对我也没用。为了简化起见,我安装了Anaconda(https://docs.anaconda.com/anaconda/install/),它会创建到其所有已安装软件包(包括Numpy)的链接。您也可以安装Miniconda并使用环境来避免使用过多空间。


你确定这回答了问题吗?请阅读[答案]。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接