Cython: "Schwerwiegender Fehler: numpy / arrayobject.h: Keine solche Datei oder kein solches Verzeichnis"

133

Ich versuche hier die Antwort mit Cython zu beschleunigen . Ich versuche, den Code zu kompilieren (nachdem ich den hiercygwinccompiler.py erläuterten Hack ausgeführt habe ), erhalte jedoch eine Fehlermeldung. Kann mir jemand sagen, ob es ein Problem mit meinem Code oder eine esoterische Subtilität mit Cython ist?fatal error: numpy/arrayobject.h: No such file or directory...compilation terminated

Unten ist mein Code.

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
quelle
Können Sie ein Tag für das von Ihnen verwendete Betriebssystem hinzufügen?
Tacaswell
@tcaswell 64-Bit Windows 7.
Noob Saibot
Das Windows-Tag wurde hinzugefügt, hoffentlich hilft dies Menschen, die wissen, wie man Windows verwendet (im Gegensatz zu mir), dieses Problem zu erkennen.
Tacaswell
1
Ich fand diese . Ein Teil der Terminologie ist über meinem Kopf, aber ich werde es überprüfen.
Noob Saibot

Antworten:

185

In Ihrem setup.py, das Extensionsollte das Argument hat include_dirs=[numpy.get_include()].

Außerdem fehlen Sie np.import_array()in Ihrem Code.

- -

Beispiel 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
quelle
4
Warum sollte ich brauchen np.import_array()? Ist das nicht für die Numpy C-API ?
Noob Saibot
Ich habe deine Idee ausprobiert, aber jetzt bekomme ich diesen verrückten Fehler, der zu lang ist, um hier zu posten, aber er beginnt mitwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot
Ah, stimmt, du brauchst es wahrscheinlich nicht np.import_array(). Ich schreibe jedoch selten numpy-verwendende Cython-Erweiterungen ohne diese, daher verwende ich sie aus Gewohnheit. Was Ihr anderes Problem betrifft, ist das, was Sie zitiert haben, nur eine Warnung, kein Fehler. Wenn Sie andere Fehler haben, die behoben werden müssen, erstellen Sie bitte einen neuen Beitrag.
Robert Kern
1
include_dirs=[numpy.get_include()]ist ein schöner Trick danke!
Daniel Farrell
14
include_dirsübergeben an setup()wird in den neuesten distutils ignoriert, es muss an jeden weitergegeben werden Extension, zumindest auf mac
dashesy
45

Für ein Projekt mit einer Datei wie Ihres können Sie auch eine andere Alternative verwenden pyximport. Sie müssen keine erstellen setup.py... Sie müssen nicht einmal eine Befehlszeile öffnen, wenn Sie IPython verwenden ... alles ist sehr praktisch. Versuchen Sie in Ihrem Fall, diese Befehle in IPython oder in einem normalen Python-Skript auszuführen:

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

Möglicherweise müssen Sie den Compiler natürlich bearbeiten. Dadurch funktionieren Import und Neuladen für .pyxDateien genauso wie für .pyDateien.

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

Steve Byrnes
quelle
Danke, @SteveB. Aber können Sie etwas näher erläutern, was Sie unter " Für ein Projekt mit einer Datei wie Ihrem ..." verstehen ? Das obige Modul ist ein (wenn auch wichtiger) Teil einer größeren Anwendung. Wie wirkt sich das pyximportauf die Geschwindigkeit meines Codes aus? Und schließlich impliziert der Abschnitt hier: " Seit Cython 0.11 bietet das Pyximport-Modul auch experimentelle Kompilierungsunterstützung für normale Python-Module ..." impliziert, dass noch einige Probleme zu lösen sind. Kannst du das auch erklären?
Noob Saibot
1
Zu "Unterstützung der experimentellen Kompilierung für normale Python-Module" - mit dem oben vorgeschlagenen Code werden .pyModule normal kompiliert (nicht mit Cython), während .pyxModule mit Cython kompiliert werden. Wenn Sie pyimport = Truein übergeben pyximport.install(), wird Cython für alles verwendet, auch zum Beispiel import randomoder import os. Ich schlage nicht vor, diese Funktion zu verwenden, nur weil es keinen zwingenden Grund gibt, sie zu verwenden, und sie könnte Probleme verursachen. Es wird wahrscheinlich hauptsächlich von Cython-Entwicklern verwendet.
Steve Byrnes
Wenn es überhaupt pyximportfunktioniert, wird genau der gleiche C-Code wie bei jeder anderen Methode erstellt. Also probieren Sie es aus und sehen Sie. Ich bezog mich auf die Tatsache, dass wenn der Kompilierungsprozess ausreichend kompliziert ist, z. B. Links zu externen Systembibliotheken, Sie möglicherweise feststellen, dass pyximport fehlschlägt und Sie ein setup.pyund benötigen cythonize, um genau anzugeben, wie es erstellt werden soll. Die Tatsache, dass Ihr .pyxModul imports oder cimports hat, bedeutet jedoch nicht, dass es nicht kompiliert werden kann pyximport. es kann durchaus in Ordnung sein.
Steve Byrnes
Ich habe einen Cython-Beitrag, über den Sie möglicherweise einen Einblick geben können.
Phillip
14

Der Fehler bedeutet, dass beim Kompilieren keine Numpy-Header-Datei gefunden wird.

Versuchen Sie es export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/und kompilieren Sie dann. Dies ist ein Problem mit einigen verschiedenen Paketen. In ArchLinux wurde ein Fehler für dasselbe Problem gemeldet : https://bugs.archlinux.org/task/22326

John Brodie
quelle
Wo füge ich die exportZeile hinzu? In meiner setup.pyAkte?
Noob Saibot
Nein, es ist ein Shell-Befehl. Führen Sie es in Ihrer Shell aus und beginnen Sie mit dem Kompilieren.
John Brodie
@NoobSaibot in der Shell (wo Sie ausführen python setup.py) führen Sie zuerst den export ..Befehl aus. Es legt die Umgebungsvariablen der Shell fest und hat nichts direkt mit [pc] ython zu tun.
Tacaswell
@tcaswell: Das habe ich mir gedacht. Ich benutze cmd und habe diesen 'export' is not recognized as an internal or external command, operable program or batch file.Fehler ... kann mit diesem einfach nicht gewinnen ...
Noob Saibot
4
@ NoobSaibot Sie erhalten Lunix-Antworten für das, was nach einem Windows-Problem riecht ....
Tacaswell
1

Einfache Antwort

Eine einfachere Möglichkeit besteht darin, den Pfad zu Ihrer Datei hinzuzufügen distutils.cfg. Der Pfad für Windows 7 ist standardmäßig C:\Python27\Lib\distutils\. Sie behaupten nur die folgenden Inhalte und es sollte funktionieren:

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

Ganze Konfigurationsdatei

Um Ihnen ein Beispiel zu geben, wie die Konfigurationsdatei aussehen könnte, lautet meine gesamte Datei:

[build]
compiler = mingw32

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

Es sollte in der Lage sein, dies innerhalb der hiercythonize() erwähnten Funktion zu tun , aber es funktioniert nicht, da ein bekanntes Problem vorliegt

hsc
quelle
1

Wenn Sie zu faul sind, um Setup-Dateien zu schreiben und den Pfad für Include-Verzeichnisse herauszufinden, versuchen Sie es mit cyper . Es kann Ihren Cython-Code kompilieren und include_dirsautomatisch auf Numpy einstellen.

Laden Sie Ihren Code in eine Zeichenfolge, führen Sie ihn einfach aus cymodule = cyper.inline(code_string), und Ihre Funktion ist cymodule.sparsemakersofort verfügbar . Etwas wie das

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

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

Sie können cyper über installieren pip install cyper.

Syrtis Major
quelle