Cython: "kesalahan fatal: numpy / arrayobject.h: Tidak ada file atau direktori seperti itu"

133

Saya mencoba mempercepat jawabannya di sini menggunakan Cython. Saya mencoba mengkompilasi kode (setelah melakukan cygwinccompiler.pyperetasan dijelaskan di sini ), tetapi mendapatkan fatal error: numpy/arrayobject.h: No such file or directory...compilation terminatedkesalahan. Adakah yang bisa memberi tahu saya jika ada masalah dengan kode saya, atau beberapa kehalusan esoterik dengan Cython?

Di bawah ini adalah kode saya.

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
sumber
dapatkah Anda menambahkan tag untuk OS apa yang Anda gunakan?
tacaswell
@tcaswell 64-bit Windows 7.
Noob Saibot
menambahkan tag windows, semoga itu akan membantu masalah ini dilihat oleh orang-orang yang tahu cara menggunakan windows (tidak seperti saya).
tacaswell
1
Saya menemukan ini . Beberapa terminologi ada di atas kepala saya, tetapi saya akan memeriksanya.
Noob Saibot
Apakah ini menjawab pertanyaan Anda? Buat distutils mencari file header numpy di tempat yang benar
ead

Jawaban:

186

Di Anda setup.py, Extensionharus memiliki argumen include_dirs=[numpy.get_include()].

Juga, Anda kehilangan np.import_array()kode Anda.

-

Contoh 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
sumber
4
Mengapa saya perlu np.import_array()? Bukankah itu untuk C-API Numpy ?
Noob Saibot
Saya mencoba ide Anda, tetapi sekarang saya mendapatkan kesalahan gila ini yang terlalu panjang untuk dikirim di sini, tetapi dimulai denganwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot
Ah, benar, kamu mungkin tidak perlu np.import_array(). Saya jarang menulis ekstensi Cython numpy menggunakan tanpa itu, jadi saya menggunakannya sebagai kebiasaan. Adapun masalah Anda yang lain, apa yang Anda kutip hanyalah peringatan, bukan kesalahan. Jika Anda memiliki kesalahan lain yang perlu diperbaiki, silakan buat posting baru.
Robert Kern
1
include_dirs=[numpy.get_include()]adalah trik yang bagus terima kasih!
Daniel Farrell
14
include_dirsdilewatkan untuk setup()diabaikan dalam distutils terbaru, itu harus diteruskan ke masing - masing Extension, setidaknya pada mac
dashesy
45

Untuk proyek satu-file seperti milik Anda, alternatif lain adalah menggunakan pyximport. Anda tidak perlu membuat setup.py... Anda bahkan tidak perlu membuka baris perintah jika Anda menggunakan IPython ... semuanya sangat nyaman. Dalam kasus Anda, coba jalankan perintah ini dalam IPython atau dalam skrip 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(...)
...

Anda mungkin perlu mengedit kompiler tentu saja. Ini membuat impor dan memuat ulang berfungsi sama untuk .pyxfile seperti mereka bekerja untuk .pyfile.

Sumber: http://wiki.cython.org/InstalingOnWindows

Steve Byrnes
sumber
Terima kasih, @SteveB. Tetapi bisakah Anda menguraikan sedikit tentang apa yang Anda maksud dengan " Untuk proyek satu-file seperti milik Anda ..."? Modul di atas adalah satu (walaupun penting) bagian dari aplikasi yang lebih besar. Bagaimana cara pyximportmemengaruhi kecepatan kode saya? Dan akhirnya, bagian di sini: " Sejak Cython 0.11, modul pyximport juga memiliki dukungan kompilasi eksperimental untuk modul Python normal ..." menyiratkan bahwa ia masih memiliki beberapa kekusutan untuk dikerjakan. Bisakah Anda menjelaskannya juga?
Noob Saibot
1
Re "dukungan kompilasi eksperimental untuk modul Python normal" - dengan kode yang saya sarankan di atas, .pymodul dikompilasi secara normal (bukan dengan cython) sementara .pyxmodul dikompilasi dengan cython. Jika Anda pyimport = Truemasuk pyximport.install(), maka ia akan menggunakan cython untuk semuanya, bahkan untuk contoh import randomatau import os. Saya tidak menyarankan menggunakan fitur itu, hanya karena tidak ada alasan kuat untuk menggunakannya, dan itu bisa membuat masalah. Ini mungkin digunakan terutama oleh pengembang cython.
Steve Byrnes
Jika pyximportberhasil, itu akan membuat kode C yang sama persis seperti metode lainnya. Jadi cobalah dan lihat. Saya merujuk pada fakta bahwa ketika proses kompilasi cukup rumit, misalnya tautan ke pustaka sistem eksternal, Anda mungkin menemukan bahwa pyximport gagal dan Anda perlu setup.pydan cythonizeuntuk menentukan cara membuatnya secara tepat. Tetapi fakta bahwa .pyxmodul Anda memiliki imports atau cimports tidak berarti bahwa ia tidak dapat dikompilasi dengan pyximport; mungkin baik-baik saja.
Steve Byrnes
Saya memiliki pos Cython yang mungkin dapat Anda berikan wawasan.
Phillip
14

Kesalahan berarti bahwa file header numpy tidak ditemukan selama kompilasi.

Coba lakukan export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, dan kemudian kompilasi. Ini adalah masalah dengan beberapa paket berbeda. Ada bug yang diajukan di ArchLinux untuk masalah yang sama: https://bugs.archlinux.org/task/22326

John Brodie
sumber
Di mana saya menambahkan exportbaris? Dalam setup.pyfile saya ?
Noob Saibot
Tidak, ini perintah shell. Jalankan di shell Anda, lalu mulai kompilasi.
John Brodie
@NoobSaibot di shell (tempat Anda menjalankan python setup.py) jalankan export ..perintah terlebih dahulu. Ini mengatur variabel lingkungan dari shell, tidak ada hubungannya langsung dengan [pc] ython.
tacaswell
@tcaswell: Saya pikir banyak. Saya menggunakan cmd, dan mendapat 'export' is not recognized as an internal or external command, operable program or batch file.kesalahan ini ... tidak bisa menang dengan yang ini ...
Noob Saibot
4
@NoobSaibot Anda mendapatkan jawaban lunix untuk apa yang berbau seperti masalah windows ....
tacaswell
1

Jawaban sederhana

Cara yang lebih sederhana adalah menambahkan path ke file Anda distutils.cfg. Itu nama path Windows 7 secara default C:\Python27\Lib\distutils\. Anda hanya menegaskan konten berikut dan itu akan berhasil:

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

Seluruh file konfigurasi

Untuk memberi Anda contoh bagaimana tampilan file konfigurasi, seluruh file saya berbunyi:

[build]
compiler = mingw32

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

Jika Anda terlalu malas untuk menulis file setup dan mencari jalan untuk menyertakan direktori, coba cyper . Itu dapat mengkompilasi kode Cython Anda dan ditetapkan include_dirsuntuk Numpy secara otomatis.

Muat kode Anda ke dalam string, kemudian jalankan cymodule = cyper.inline(code_string), maka fungsi Anda tersedia secara cymodule.sparsemakerinstan. Sesuatu seperti ini

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

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

Anda dapat menginstal cyper via pip install cyper.

Syrtis Major
sumber