Cython: "erreur fatale: numpy / arrayobject.h: aucun fichier ou répertoire de ce type"

133

J'essaye d'accélérer la réponse ici en utilisant Cython. J'essaye de compiler le code (après avoir fait le cygwinccompiler.pyhack expliqué ici ), mais j'obtiens une fatal error: numpy/arrayobject.h: No such file or directory...compilation terminatederreur. Quelqu'un peut-il me dire si c'est un problème avec mon code, ou une subtilité ésotérique avec Cython?

Ci-dessous mon 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
la source
pouvez-vous ajouter une balise pour quel système d'exploitation vous utilisez?
tacaswell le
@tcaswell 64 bits Windows 7.
Noob Saibot
a ajouté la balise windows, j'espère que cela aidera ce problème à être vu par les gens qui savent comment utiliser Windows (contrairement à moi).
tacaswell
1
J'ai trouvé ça . Une partie de la terminologie est au-dessus de ma tête, mais je vais vérifier.
Noob Saibot le
Est-ce que cela répond à votre question? Faites que les distutils recherchent les fichiers d'en-tête numpy au bon endroit
lisez le

Réponses:

186

Dans votre setup.py, le Extensiondevrait avoir l'argument include_dirs=[numpy.get_include()].

De plus, vous manquez np.import_array()dans votre code.

-

Exemple 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
la source
4
Pourquoi aurais-je besoin np.import_array()? N'est-ce pas pour l' API C Numpy ?
Noob Saibot le
J'ai essayé votre idée, mais maintenant j'obtiens cette erreur folle qui est trop longue à publier ici, mais cela commence parwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot
Ah, c'est vrai, vous n'en avez probablement pas besoin np.import_array(). J'écris rarement des extensions Cython avec numpy sans cela, donc je l'utilise par habitude. Quant à votre autre problème, ce que vous avez cité n'est qu'un avertissement, pas une erreur. Si vous avez d'autres erreurs à corriger, veuillez publier un nouveau message.
Robert Kern
1
include_dirs=[numpy.get_include()]c'est un joli truc merci!
Daniel Farrell
14
include_dirspassé à setup()est ignoré dans les derniers distutils, il doit être transmis à chacun Extension, au moins sur mac
dashesy
45

Pour un projet à un fichier comme le vôtre, une autre alternative consiste à utiliser pyximport. Vous n'avez pas besoin de créer un setup.py... vous n'avez même pas besoin d'ouvrir une ligne de commande si vous utilisez IPython ... c'est très pratique. Dans votre cas, essayez d'exécuter ces commandes en IPython ou dans 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(...)
...

Vous devrez peut-être modifier le compilateur bien sûr. Cela fait que l'importation et le rechargement fonctionnent de la même manière pour les .pyxfichiers que pour.py fichiers.

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

Steve Byrnes
la source
Merci, @SteveB. Mais pouvez-vous expliquer un peu ce que vous entendez par " Pour un projet à un seul fichier comme le vôtre ..."? Le module ci-dessus est une partie (quoique importante) d'une application plus large. Comment pyximportaffecte la vitesse de mon code? Et enfin, la section ici: " Depuis Cython 0.11, le module pyximport a également un support de compilation expérimentale pour les modules Python normaux ..." implique qu'il a encore quelques problèmes à résoudre. Pouvez-vous expliquer cela également?
Noob Saibot
1
Re "support de compilation expérimentale pour les modules Python normaux" - avec le code que j'ai suggéré ci-dessus, les .pymodules sont compilés normalement (pas avec cython) tandis que les .pyxmodules sont compilés avec cython. Si vous passez pyimport = Truedans pyximport.install(), alors il utilisera cython pour tout, même par exemple import randomou import os. Je ne suggère pas d'utiliser cette fonctionnalité, simplement parce qu'il n'y a aucune raison impérieuse de l'utiliser, et cela pourrait créer des problèmes. Il est probablement principalement utilisé par les développeurs cython.
Steve Byrnes
Si cela pyximportfonctionne, cela créera exactement le même code C que toute autre méthode. Alors essayez-le et voyez. Je faisais référence au fait que lorsque le processus de compilation est suffisamment compliqué, par exemple des liens vers des bibliothèques système externes, vous pourriez constater que pyximport échoue et que vous avez besoin d'un setup.pyet cythonizepour spécifier exactement comment le construire. Mais le fait que votre .pyxmodule ait imports ou cimports ne signifie pas qu'il ne peut pas être compilé avec pyximport; ça peut bien être tout à fait bien.
Steve Byrnes
J'ai un article sur Cython sur lequel vous pourrez peut-être donner un aperçu.
Phillip
14

L'erreur signifie qu'un fichier d'en-tête numpy n'est pas trouvé lors de la compilation.

Essayez de faire export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, puis compilez. C'est un problème avec quelques packages différents. Il y a un bogue déposé dans ArchLinux pour le même problème: https://bugs.archlinux.org/task/22326

John Brodie
la source
Où ajouter la exportligne? Dans mon setup.pydossier?
Noob Saibot
Non, c'est une commande shell. Exécutez-le dans votre shell, puis lancez la compilation.
John Brodie
@NoobSaibot dans le shell (où vous exécutez python setup.py) exécutez d'abord la export ..commande. Il définit les variables d'environnement du shell, rien à voir directement avec [pc] ython.
tacaswell le
@tcaswell: J'en ai pensé autant. J'utilise cmd et j'ai cette 'export' is not recognized as an internal or external command, operable program or batch file.erreur ... je ne peux tout simplement pas gagner avec celui-ci ...
Noob Saibot
4
@NoobSaibot vous obtenez des réponses Lunix pour ce qui sent comme un problème de Windows ....
Tacaswell
1

Réponse simple

Un moyen plus simple consiste à ajouter le chemin d'accès à votre fichier distutils.cfg. Son nom de chemin de Windows 7 est par défaut C:\Python27\Lib\distutils\. Vous venez d'affirmer le contenu suivant et cela devrait fonctionner:

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

Fichier de configuration complet

Pour vous donner un exemple à quoi le fichier de configuration pourrait ressembler, mon fichier entier se lit comme suit:

[build]
compiler = mingw32

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

Il devrait être capable de le faire dans la cythonize()fonction mentionnée ici , mais cela ne fonctionne pas car il y a un problème connu

hsc
la source
1

Si vous êtes trop paresseux pour écrire des fichiers de configuration et déterminer le chemin des répertoires d'inclusion, essayez cyper . Il peut compiler votre code Cython et définir include_dirsautomatiquement Numpy.

Chargez votre code dans une chaîne, puis exécutez simplement cymodule = cyper.inline(code_string), puis votre fonction est disponible cymodule.sparsemakerinstantanément. Quelque chose comme ça

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

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

Vous pouvez installer cyper via pip install cyper.

Syrtis Major
la source