Cython: "error fatal: numpy / arrayobject.h: No existe tal archivo o directorio"

133

Estoy tratando de acelerar la respuesta aquí usando Cython. Intento compilar el código (después de hacer el cygwinccompiler.pyhack explicado aquí ), pero aparece un fatal error: numpy/arrayobject.h: No such file or directory...compilation terminatederror. ¿Alguien puede decirme si hay un problema con mi código o alguna sutileza esotérica con Cython?

Abajo está mi código.

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()
Noob Saibot
fuente
¿Puedes agregar una etiqueta para el sistema operativo que estás utilizando?
tacaswell 02 de
@tcaswell 64-bit Windows 7.
Noob Saibot
agregó la etiqueta de Windows, con suerte eso ayudará a que este problema sea visto por personas que saben cómo usar Windows (a diferencia de mí)
tacaswell 02 de
1
Encontré esto . Parte de la terminología está por encima de mi cabeza, pero voy a comprobarlo.
Noob Saibot

Respuestas:

186

En su setup.py, el Extensiondebería tener el argumento include_dirs=[numpy.get_include()].

Además, te falta np.import_array()tu código.

-

Ejemplo 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()]
)    
Robert Kern
fuente
44
¿Por qué necesitaría np.import_array()? ¿No es eso para el Numpy C-API ?
Noob Saibot
Intenté tu idea, pero ahora recibo este error loco que es demasiado largo para publicar aquí, pero comienza conwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot
Ah, cierto, probablemente no necesites np.import_array(). Sin embargo, rara vez escribo extensiones de Cython que usan numpy sin él, así que lo uso por costumbre. En cuanto a su otro problema, lo que citó es solo una advertencia, no un error. Si tiene otros errores que necesitan reparación, haga una nueva publicación.
Robert Kern
1
include_dirs=[numpy.get_include()]es un buen truco gracias!
Daniel Farrell
14
include_dirspasado a setup()se ignora en las últimas destutils, se debe pasar a cada uno Extension, al menos en mac
guiones el
45

Para un proyecto de un archivo como el suyo, otra alternativa es usar pyximport. No necesita crear un setup.py... ni siquiera necesita abrir una línea de comando si usa IPython ... todo es muy conveniente. En su caso, intente ejecutar estos comandos en IPython o en un script Python normal:

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(...)
...

Es posible que deba editar el compilador, por supuesto. Esto hace que la importación y la recarga funcionen igual para los .pyxarchivos que para los .pyarchivos.

Fuente: http://wiki.cython.org/InstallingOnWindows

Steve Byrnes
fuente
Gracias, @SteveB. Pero, ¿puede explicar un poco lo que quiere decir con " Para un proyecto de un archivo como el suyo ..."? El módulo anterior es una parte (aunque importante) de una aplicación más grande. ¿Cómo pyximportafecta la velocidad de mi código? Y finalmente, la sección aquí: " Desde Cython 0.11, el módulo pyximport también tiene soporte de compilación experimental para módulos Python normales ..." implica que todavía tiene algunos problemas para resolver. ¿Puedes explicar eso también?
Noob Saibot
1
Re "soporte de compilación experimental para módulos Python normales": con el código que sugerí anteriormente, los .pymódulos se compilan normalmente (no con cython) mientras que los .pyxmódulos se compilan con cython. Si pasa pyimport = Trueen pyximport.install(), entonces se usará Cython por todo, incluso por ejemplo import randomo import os. No sugiero usar esa función, simplemente porque no hay una razón convincente para usarla, y podría crear problemas. Probablemente lo usan principalmente los desarrolladores de cython.
Steve Byrnes
Si pyximportfunciona, creará exactamente el mismo código C que cualquier otro método. Así que pruébalo y verás. Me refiero al hecho de que cuando el proceso de compilación se complica bastante, por ejemplo, enlaces a bibliotecas externos del sistema, puede encontrarse con que pyximport falla y necesita una setup.pyy cythonizeespecificar exactamente cómo construirlo. Pero el hecho de que su .pyxmódulo tenga imports o cimports no significa que no se pueda compilar pyximport; bien puede estar totalmente bien.
Steve Byrnes
Tengo una publicación de Cython en la que puedes proporcionar información.
Phillip
14

El error significa que no se encuentra un archivo de encabezado numpy durante la compilación.

Intenta hacerlo export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/y luego compila. Este es un problema con algunos paquetes diferentes. Hay un error archivado en ArchLinux para el mismo problema: https://bugs.archlinux.org/task/22326

John Brodie
fuente
¿Dónde agrego la exportlínea? En mi setup.pyarchivo
Noob Saibot
No, es un comando de shell. Ejecútelo en su shell, luego comience a compilar.
John Brodie
@NoobSaibot en el shell (donde ejecuta python setup.py) ejecute el export ..comando primero. Establece las variables ambientales del shell, no nada que tenga que ver directamente con [pc] ython.
tacaswell 02 de
@tcaswell: me lo imaginé. Estoy usando cmd, y obtuve este 'export' is not recognized as an internal or external command, operable program or batch file.error ... simplemente no puedo ganar con este ...
Noob Saibot
44
@NoobSaibot que está recibiendo respuestas LUNIX para lo que huele como un problema de Windows ....
tacaswell
1

Respuesta simple

Una manera más simple es agregar la ruta a su archivo distutils.cfg. Su nombre de ruta de Windows 7 es por defecto C:\Python27\Lib\distutils\. Simplemente afirma los siguientes contenidos y debería funcionar:

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

Archivo de configuración completo

Para darle un ejemplo de cómo podría verse el archivo de configuración, se lee todo mi archivo:

[build]
compiler = mingw32

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

Debería poder hacerlo dentro de la cythonize()función como se menciona aquí , pero no funciona porque hay un problema conocido

hsc
fuente
1

Si eres demasiado vago para escribir archivos de configuración y descubrir la ruta para incluir directorios, prueba cyper . Puede compilar su código Cython y configurarlo include_dirspara Numpy automáticamente.

Cargue su código en una cadena, luego simplemente ejecute cymodule = cyper.inline(code_string), luego su función estará disponible de forma cymodule.sparsemakerinstantánea. Algo como esto

code = open(your_pyx_file).read()
cymodule = cyper.inline(code)

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

Puede instalar cyper a través de pip install cyper.

Syrtis Major
fuente