Ich habe mit so vielen etwas zu kämpfen int
Datentypen in cython.
np.int, np.int_, np.int_t, int
ich vermute int
in reinem Python entspricht np.int_
wo dann np.int
komme aus? Ich kann das Dokument von numpy nicht finden? Auch warum np.int_
existieren, da wir bereits haben int
?
In Cython, schätze ich int
wird ein C-Typ, wenn es als verwendet wird cdef int
oder ndarray[int]
und wenn verwendet als int()
es bleibt beim python caster?
Ist np.int_
gleichwertig long
in C? Also cdef long
ist identisch mit cdef np.int_
?
Unter welchen Umständen sollte ich verwenden np.int_t
Anstatt von np.int
? z.B cdef np.int_t
, ndarray[np.int_t]
…
Kann jemand kurz erklären, wie sich die falsche Verwendung dieser Typen auf die Leistung von kompiliertem Cython-Code auswirken würde?
Es ist ein bisschen kompliziert, weil die Namen je nach Kontext unterschiedliche Bedeutungen haben.
int
-
Bei Python
Das int
ist normalerweise nur ein Python-Typ, es ist von beliebiger Genauigkeit, was bedeutet, dass Sie jede denkbare ganze Zahl darin speichern können (solange Sie genug Speicher haben).
>>> int(10**50)
100000000000000000000000000000000000000000000000000
-
Allerdings, wenn Sie es als verwenden dtype
für ein NumPy-Array wird es interpretiert als np.int_
1. Welches ist nicht von beliebiger Genauigkeit, hat es die gleiche Größe wie C’s long
:
>>> np.array(10**50, dtype=int)
OverflowError: Python int too large to convert to C long
Das bedeutet auch, dass die folgenden beiden äquivalent sind:
np.array([1,2,3], dtype=int)
np.array([1,2,3], dtype=np.int_)
-
Als Cython-Typ-Bezeichner hat es eine andere Bedeutung, hier steht es für den c-Typ int
. Es ist von begrenzter Genauigkeit (normalerweise 32 Bit). Sie können es als Cython-Typ verwenden, zum Beispiel beim Definieren von Variablen mit cdef
:
cdef int value = 100 # variable
cdef int[:] arr = ... # memoryview
Als Rückgabewert oder Argumentwert für cdef
oder cpdef
Funktionen:
cdef int my_function(int argument1, int argument2):
# ...
Als “generisch” für ndarray
:
cimport numpy as cnp
cdef cnp.ndarray[int, ndim=1] val = ...
Für Type-Casting:
avalue = <int>(another_value)
Und wahrscheinlich noch viele mehr.
-
In Cython, aber als Python-Typ. Sie können immer noch anrufen int
und Sie erhalten ein “Python int” (mit beliebiger Genauigkeit) oder verwenden es für isinstance
oder als dtype
Argument für np.array
. Hier ist der Kontext wichtig, also in Python umwandeln int
unterscheidet sich von der Konvertierung in ein C int:
cdef object val = int(10) # Python int
cdef int val = <int>(10) # C int
np.int
Eigentlich ist das ganz einfach. Es ist nur ein Alias für int
:
>>> int is np.int
True
Also trifft alles von oben zu np.int
auch. Sie können es jedoch nicht als Typkennung verwenden, außer wenn Sie es auf der verwenden cimport
Ed-Paket. In diesem Fall repräsentiert es den Python-Integer-Typ.
cimport numpy as cnp
cpdef func(cnp.int obj):
return obj
Dies wird erwartet obj
eine Python-Ganzzahl sein kein NumPy-Typ:
>>> func(np.int_(10))
TypeError: Argument 'obj' has incorrect type (expected int, got numpy.int32)
>>> func(10)
10
Mein Tipp bzgl np.int
: Vermeiden Sie es, wann immer möglich. Im Python-Code ist es äquivalent zu int
und im Cython-Code entspricht es auch Pythons int
aber wenn es als Typkennung verwendet wird, wird es Sie und jeden, der den Code liest, wahrscheinlich verwirren! Es hat mich natürlich verwirrt…
np.int_
Eigentlich hat es nur eine Bedeutung: Es ist ein Python-Typ das einen skalaren NumPy-Typ darstellt. Sie verwenden es wie Pythons int
:
>>> np.int_(10) # looks like a normal Python integer
10
>>> type(np.int_(10)) # but isn't (output may vary depending on your system!)
numpy.int32
Oder Sie verwenden es, um die zu spezifizieren dtype
zum Beispiel mit np.array
:
>>> np.array([1,2,3], dtype=np.int_)
array([1, 2, 3])
Sie können es jedoch nicht als Typkennung in Cython verwenden.
cnp.int_t
Es ist die Typkennungsversion für np.int_
. Das heißt, Sie können es nicht als dtype-Argument verwenden. Aber Sie können es als Typ für verwenden cdef
Erklärungen:
cimport numpy as cnp
import numpy as np
cdef cnp.int_t[:] arr = np.array([1,2,3], dtype=np.int_)
|---TYPE---| |---DTYPE---|
Dieses Beispiel zeigt (hoffentlich) dass die Typkennung mit dem Trailing _t
stellt tatsächlich den Typ eines Arrays dar, das die verwendet dtyp ohne Nachlauf t
. Sie können sie nicht im Cython-Code austauschen!
Anmerkungen
Es gibt mehrere weitere numerische Typen in NumPy. Ich füge eine Liste mit dem NumPy-Dtype und der Cython-Typkennung und der C-Typkennung hinzu, die hier auch in Cython verwendet werden könnten. Aber es ist im Grunde übernommen die NumPy-Dokumentation und die Cython NumPy pxd
Datei:
NumPy dtype Numpy Cython type C Cython type identifier
np.bool_ None None
np.int_ cnp.int_t long
np.intc None int
np.intp cnp.intp_t ssize_t
np.int8 cnp.int8_t signed char
np.int16 cnp.int16_t signed short
np.int32 cnp.int32_t signed int
np.int64 cnp.int64_t signed long long
np.uint8 cnp.uint8_t unsigned char
np.uint16 cnp.uint16_t unsigned short
np.uint32 cnp.uint32_t unsigned int
np.uint64 cnp.uint64_t unsigned long
np.float_ cnp.float64_t double
np.float32 cnp.float32_t float
np.float64 cnp.float64_t double
np.complex_ cnp.complex128_t double complex
np.complex64 cnp.complex64_t float complex
np.complex128 cnp.complex128_t double complex
Eigentlich gibt es Cython-Typen für np.bool_
: cnp.npy_bool
und bint
aber beide können derzeit nicht für NumPy-Arrays verwendet werden. Für Skalare cnp.npy_bool
wird nur eine vorzeichenlose ganze Zahl sein, während bint
wird ein boolescher Wert sein. Bin mir nicht sicher was da los ist…
1 Entnommen aus der NumPy-Dokumentation “Datentypobjekte”
Eingebaute Python-Typen
Mehrere Python-Typen entsprechen einem entsprechenden Array-Skalar, wenn sie zum Generieren eines dtype-Objekts verwendet werden:
int np.int_
bool np.bool_
float np.float_
complex np.cfloat
bytes np.bytes_
str np.bytes_ (Python2) or np.unicode_ (Python3)
unicode np.unicode_
buffer np.void
(all others) np.object_
np.int_
ist der standardmäßige ganzzahlige Typ (wie in den NumPy-Dokumenten definiert), auf einem 64-Bit-System wäre dies a C long
. np.intc
ist die Vorgabe C int
entweder int32
oder int64
. np.int
ist ein Alias für die eingebaute int
Funktion
>>> np.int(2.4)
2
>>> np.int is int # object id equality
True
Die Cython-Datentypen sollten widerspiegeln C
Datentypen, also cdef int a
ist ein C int
usw.
Wie für np.int_t
das ist die Cython
Kompilierzeitäquivalent von NumPy np.int_
Datentyp, np.int64_t
ist der Cython
Kompilierzeitäquivalent von np.int64
Dies ist eine Klärung des Unterschieds zwischen int
und np.int_t
im Cython-Code, die nicht gleich sind:
np.int_t
Karten zu long
und nicht zu int
im Cython-Code.
Das bedeutet:
- Unter 64-Bit-Windows (dh mit MSVC kompiliert)
int
ist aber auch 4 bytes long
(und somit np.int_t
).
- Unter 64-Bit-Linux (dh mit gcc kompiliert)
int
ist aber 4 Bytes long
(und somit np.int_t
) ist 8 Byte!
Ein np.int
-numpy-array würde zuordnen np.int_t[:]
-Speicheransicht in Cython, was richtig ist, weil der folgende Code:
import numpy as np
a = np.zeros(1, np.int_) # or np.zeros(1, np.int)
print(a.itemsize)
ergäbe 4
(Größe von long
in Bytes unter Windows) unter Windows und 8
auf Linux.
Oft ist es sinnvoll, die Größe der Werte genau anzugeben, zB durch using np.int32
und np.int64
was zuordnen würde np.int32_t
und np.int64_t
in Cython und haben auf allen Plattformen die gleiche Größe.
github.com/scikit-learn/scikit-learn/wiki/…
– Fred Foo
18. Februar 2014 um 12:40 Uhr