Cython: "errore fatale: numpy / arrayobject.h: nessun file o directory del genere"


133

Sto cercando di accelerare la risposta qui usando Cython. Provo a compilare il codice (dopo aver fatto l' cygwinccompiler.pyhack spiegato qui ), ma ottengo un fatal error: numpy/arrayobject.h: No such file or directory...compilation terminatederrore. Qualcuno può dirmi se è un problema con il mio codice o qualche sottigliezza esoterica con Cython?

Di seguito è il mio codice.

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

puoi aggiungere un tag per quale sistema operativo stai usando?
Tacaswell,

@tcaswell 64-bit Windows 7.
Noob Saibot

aggiunto il tag windows, si spera che possa aiutare a vedere questo problema da persone che sanno usare windows (a differenza di me).
Tacaswell,

1
Ho trovato questo . Un po 'di terminologia è sopra la mia testa, ma lo controllerò.
Noob Saibot,

Risposte:


186

Nel tuo setup.py, Extensiondovrebbe avere l'argomento include_dirs=[numpy.get_include()].

Inoltre, ti manca il np.import_array()tuo codice.

-

Esempio 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()]
)    

4
Perché dovrei aver bisogno np.import_array()? Non è per la C-API di Numpy ?
Noob Saibot,

Ho provato la tua idea, ma ora ho questo folle errore che è troppo lungo per pubblicare qui, ma inizia conwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot

Ah, vero, probabilmente non ti serve np.import_array(). Raramente scrivo estensioni Cython che usano intorpidimento senza di essa, tuttavia, quindi lo uso come una questione di abitudine. Per quanto riguarda l'altro tuo problema, quello che hai citato è solo un avvertimento, non un errore. Se hai altri errori che devono essere corretti, ti preghiamo di fare un nuovo post.
Robert Kern,

1
include_dirs=[numpy.get_include()]è un bel trucco grazie!
Daniel Farrell,

14
include_dirspassato a setup()viene ignorato nelle ultime distutils, deve essere passato a ciascuno Extension, almeno su mac
dashesy

45

Per un progetto a un file come il tuo, un'altra alternativa è usare pyximport. Non è necessario creare un setup.py... non è nemmeno necessario aprire una riga di comando se si utilizza IPython ... è tutto molto conveniente. Nel tuo caso, prova a eseguire questi comandi in IPython o in un normale script 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(...)
...

Potrebbe essere necessario modificare il compilatore ovviamente. Questo fa sì che l'importazione e la ricarica funzionino allo stesso modo per i .pyxfile come funzionano per i .pyfile.

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


Grazie, @SteveB. Ma puoi approfondire cosa intendi con " Per un progetto in un file come il tuo ..."? Il modulo sopra è una parte (sebbene importante) di un'applicazione più grande. In che modo pyximportinfluisce sulla velocità del mio codice? E infine, la sezione qui: " A partire da Cython 0.11, il modulo pyximport ha anche un supporto di compilazione sperimentale per i normali moduli Python ..." implica che ha ancora qualche nodo da risolvere. Puoi spiegarlo anche tu?
Noob Saibot,

1
Ri "supporto di compilazione sperimentale per normali moduli Python" - con il codice che ho suggerito sopra, i .pymoduli vengono compilati normalmente (non con cython) mentre i .pyxmoduli vengono compilati con cython. Se passi pyimport = Truein pyximport.install(), allora utilizzerà cython per tutto, anche per esempio import randomo import os. Non suggerisco di usare quella funzione, semplicemente perché non ci sono motivi validi per usarla e potrebbe creare problemi. Probabilmente è utilizzato principalmente dagli sviluppatori cython.
Steve Byrnes,

Se pyximportfunziona, creerà esattamente lo stesso codice C di qualsiasi altro metodo. Quindi provalo e vedi. Mi riferivo al fatto che quando il processo di compilazione è sufficientemente complicato, ad esempio collegamenti a librerie di sistema esterne, potresti scoprire che pyximport fallisce e hai bisogno di un setup.pye cythonizedi specificare esattamente come costruirlo. Ma il fatto che il tuo .pyxmodulo abbia più importo cimportmeno non significa che non può essere compilato pyximport; potrebbe benissimo essere tutto a posto.
Steve Byrnes,

Ho un post su Cython di cui potresti essere in grado di fornire informazioni.
Phillip

14

L'errore indica che non è stato trovato un file di intestazione numpy durante la compilazione.

Prova a fare export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, quindi a compilare. Questo è un problema con alcuni pacchetti diversi. C'è un bug archiviato in ArchLinux per lo stesso problema: https://bugs.archlinux.org/task/22326


Dove aggiungo la exportlinea? Nel mio setup.pyfile?
Noob Saibot,

No, è un comando shell. Eseguilo nella tua shell, quindi inizia a compilare.
John Brodie,

@NoobSaibot nella shell (dove si esegue python setup.py) eseguire export ..prima il comando. Imposta le variabili ambientali della shell, non nulla a che fare direttamente con [pc] ython.
Tacaswell

@tcaswell: ho pensato tanto. Sto usando cmd e ho riscontrato questo 'export' is not recognized as an internal or external command, operable program or batch file.errore ... non posso vincere con questo ...
Noob Saibot

4
@NoobSaibot stai ricevendo risposte lunix per quello che puzza di un problema di Windows ....
tacaswell

1

Semplice risposta

Un modo più semplice è aggiungere il percorso al tuo file distutils.cfg. Il nome del percorso di Windows 7 è predefinito C:\Python27\Lib\distutils\. Devi solo affermare i seguenti contenuti e dovrebbe funzionare:

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

Intero file di configurazione

Per darvi un esempio di come potrebbe apparire il file di configurazione, il mio intero file dice:

[build]
compiler = mingw32

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

1

Dovrebbe essere in grado di farlo all'interno della cythonize()funzione come menzionato qui , ma non funziona perché c'è un problema noto


1

Se sei troppo pigro per scrivere i file di installazione e capire il percorso per includere le directory, prova cyper . Può compilare il tuo codice Cython e impostareinclude_dirs automaticamente per Numpy.

Carica il tuo codice in una stringa, quindi esegui semplicemente cymodule = cyper.inline(code_string), quindi la tua funzione è disponibile cymodule.sparsemakeristantaneamente. Qualcosa come questo

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

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

È possibile installare cyper tramite pip install cyper.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.