Wie identifiziere ich Numpy-Typen in Python?

99

Wie kann man zuverlässig feststellen, ob ein Objekt einen Numpy-Typ hat?

Mir ist klar, dass diese Frage gegen die Philosophie der Ententypisierung verstößt, aber es soll sichergestellt werden, dass eine Funktion (die scipy und numpy verwendet) niemals einen numpy-Typ zurückgibt, es sei denn, sie wird mit einem numpy-Typ aufgerufen. Dies ergibt sich aus der Lösung einer anderen Frage, aber ich denke, das allgemeine Problem, festzustellen, ob ein Objekt einen Numpy-Typ hat, ist weit genug von dieser ursprünglichen Frage entfernt, dass sie getrennt werden sollten.

Douglas B. Staple
quelle
Eine Frage: Wenn Sie (oder beispielsweise scipy) einen Typ definieren, der einem Numpy-Typ untergeordnet ist, sollte das zählen oder nicht? (Ich glaube, Sie können Numpy-Typen in Python nicht unterordnen, aber Sie können in einem C-Modul, und ich denke, Sie können Numpypy-Typen auch in PyPy unterordnen. Es spielt also wahrscheinlich keine Rolle, aber es ist nicht unvorstellbar, dass dies möglich ist.)
Abarnert
Daran hatte ich nicht gedacht; Grundsätzlich weist Ihr Kommentar darauf hin, dass die Frage schwieriger als erwartet ist. Ehrlich gesagt ist diese Art von hochrangiger Überlegung für meine Situation viel zu viel des Guten. Für die allgemeine und tragbare Antwort würde ich sagen, dass es in Ordnung ist, solange das Verhalten definiert ist.
Douglas B. Staple

Antworten:

114

Verwenden Sie die integrierte typeFunktion, um den Typ abzurufen. Anschließend können Sie mithilfe der __module__Eigenschaft herausfinden, wo er definiert wurde:

>>> import numpy as np
a = np.array([1, 2, 3])
>>> type(a)
<type 'numpy.ndarray'>
>>> type(a).__module__
'numpy'
>>> type(a).__module__ == np.__name__
True
abarnert
quelle
Ist zB numpy.ma.MaskedArray nicht numpy genug?
Panda-34
Wenn Sie etwas in numpy wollen. * Gehen Sie einfach durch das übergeordnete Paket des Moduls. (An diesem Punkt möchten Sie es offensichtlich in eine Funktion einbinden.) Und wenn Pandas DataFrames als numpyisch gelten sollen, fügen Sie ein oder hinzu, um dies zu testen. Und so weiter. Der Punkt ist, dass Sie wissen müssen, wonach Sie tatsächlich fragen, wenn Sie etwas so Ungewöhnliches wie lose manuelle Typumschaltung durchführen möchten, aber sobald Sie wissen, ist es einfach zu implementieren.
Abarnert
1
Diese Lösung scheint sehr unpythonisch zu sein und basiert auf versteckten Attributen. Aber vielleicht ist das nur Geschmackssache?
j08lue
2
@ j08lue Sie sind keine versteckten Attribute, sondern dokumentierte spezielle Attribute. Es ist dennoch unpythonisch, aber ich denke, das ist dem Problem inhärent. (Und ich denke, es ist eine Stärke von Python, dass, wenn Sie etwas tun möchten, von dem die Sprache abhält, die beste Lösung normalerweise sichtbar hässlich genug ist, um darauf hinzuweisen, dass Sie etwas tun, das normalerweise eine schlechte Idee ist.)
abarnert
68

Die Lösung, die ich mir ausgedacht habe, ist:

isinstance(y, (np.ndarray, np.generic) )

Doch es ist nicht 100% klar , dass alle numpy Typen garantiert werden entweder np.ndarrayoder np.generic, und dies ist wahrscheinlich nicht Version robust.

Douglas B. Staple
quelle
1
Ich nehme an, Sie könnten dir(numpy)nach Typen und eingebauten Funktionen (und Klassen, aber ich glaube nicht, dass es welche gibt) filtern und damit ein Tupel isinstancegegen generieren , das robust wäre. (Ich glaube, Sie können eingebaute Funktionen an isinstance übergeben, ob sie tatsächlich Typkonstruktoren sind oder nicht, aber Sie
müssten das
Ja, sie sollten alle Unterklassen dieser beiden AFAIK sein.
seberg
@seberg Danke. Dies scheint vorerst sicherlich der Fall zu sein, aber die Python-Dokumentation ist diesbezüglich nicht sehr klar und könnte sich möglicherweise in Zukunft ändern.
Douglas B. Staple
19

Alte Frage, aber ich habe eine endgültige Antwort mit einem Beispiel gefunden. Es kann nicht schaden, Fragen frisch zu halten, da ich das gleiche Problem hatte und keine klare Antwort fand. Der Schlüssel besteht darin, sicherzustellen, dass Sie numpyimportiert haben, und dann den isinstanceBool auszuführen . Dies mag zwar einfach erscheinen, aber wenn Sie einige Berechnungen über verschiedene Datentypen hinweg durchführen, kann diese kleine Überprüfung als schneller Test dienen, bevor Sie eine numpy-vektorisierte Operation starten.

##################
# important part!
##################

import numpy as np

####################
# toy array for demo
####################

arr = np.asarray(range(1,100,2))

########################
# The instance check
######################## 

isinstance(arr,np.ndarray)
Linwoodc3
quelle
9

Das hängt eigentlich davon ab, wonach Sie suchen.

  • Wenn Sie testen möchten, ob eine Sequenz tatsächlich eine ist ndarray, isinstance(..., np.ndarray)ist a wahrscheinlich die einfachste. Stellen Sie sicher, dass Sie numpy nicht im Hintergrund neu laden, da das Modul möglicherweise anders ist. Andernfalls sollten Sie in Ordnung sein. MaskedArrays, matrix, recarraySind alle Unterklassen von ndarray, so dass Sie sollten eingestellt werden.
  • Wenn Sie testen möchten, ob ein Skalar ein Numpy-Skalar ist, werden die Dinge etwas komplizierter. Sie können überprüfen, ob es ein shapeund ein dtypeAttribut hat. Sie können es dtypemit den grundlegenden dtypes vergleichen, deren Liste Sie finden können np.core.numerictypes.genericTypeRank. Beachten Sie, dass die Elemente dieser Liste Zeichenfolgen sind, sodass Sie tested.dtype is np.dtype(an_element_of_the_list)...
Pierre GM
quelle
+1. Wenn Sie tatsächlich nach etwas anderem als "ist ein numpyTyp" suchen und definieren können, was dieses etwas ist, ist dies besser als die anderen Antworten. Und in den meisten Fällen, Sie sollten etwas Bestimmtes suchen , die Sie definieren können.
Abarnert
8

Verwenden Sie die integrierte typeFunktion, um den Typ abzurufen . Mit dem inOperator können Sie testen, ob der Typ ein Numpy-Typ ist, indem Sie überprüfen, ob er die Zeichenfolge enthält numpy.

In [1]: import numpy as np

In [2]: a = np.array([1, 2, 3])

In [3]: type(a)
Out[3]: <type 'numpy.ndarray'>

In [4]: 'numpy' in str(type(a))
Out[4]: True

(Dieses Beispiel wurde übrigens in IPython ausgeführt . Sehr praktisch für die interaktive Verwendung und schnelle Tests.)

Roland Smith
quelle
2
Dies funktioniert, aber wenn Sie einen Typ mit dem Namen "numpygroup" definieren, erhalten Sie falsch positive Ergebnisse. Abhängig von der Zeichenfolgendarstellung von Typen ist es auch eine schlechte Idee, wenn Sie dies vermeiden können - und in diesem Fall auch. Schauen Sie sich stattdessen das Modul an.
abarnert
Die Verwendung des Moduls ist in der Tat eine bessere Lösung.
Roland Smith
Regex könnte verwendet werden
Omkaar.K
@ Omkaar.K Regex könnte für was verwendet werden? Um genau die gleiche Prüfung etwas komplizierter durchzuführen?
Abarnert
@abamert "Could" ist das, was ich gesagt habe, auch Regex könnte für einfache Aufgaben wie diese kompliziert aussehen, aber es ist äußerst nützlich für große Zeichenfolgenverarbeitungsaufgaben. Es ist also keine schlechte Idee, es zu lernen. Ich denke, Sie wissen das schon, seit Ihr Portfolio Sie als Senior-Programmierer darstellt?
Omkaar.K
3

Beachten Sie, dass dies type(numpy.ndarray)ein typeSelbst ist und achten Sie auf boolesche und skalare Typen. Seien Sie nicht zu entmutigt, wenn es nicht intuitiv oder einfach ist, es ist zunächst ein Schmerz.

Siehe auch: - https://docs.scipy.org/doc/numpy-1.15.1/reference/arrays.dtypes.html - https://github.com/machinalis/mypy-data/tree/master/numpy- mypy

>>> import numpy as np
>>> np.ndarray
<class 'numpy.ndarray'>
>>> type(np.ndarray)
<class 'type'>
>>> a = np.linspace(1,25)
>>> type(a)
<class 'numpy.ndarray'>
>>> type(a) == type(np.ndarray)
False
>>> type(a) == np.ndarray
True
>>> isinstance(a, np.ndarray)
True

Spaß mit Booleschen:

>>> b = a.astype('int32') == 11
>>> b[0]
False
>>> isinstance(b[0], bool)
False
>>> isinstance(b[0], np.bool)
False
>>> isinstance(b[0], np.bool_)
True
>>> isinstance(b[0], np.bool8)
True
>>> b[0].dtype == np.bool
True
>>> b[0].dtype == bool  # python equivalent
True

Weitere Informationen zu Skalartypen finden Sie unter: - https://docs.scipy.org/doc/numpy-1.15.1/reference/arrays.scalars.html#arrays-scalars-built-in

>>> x = np.array([1,], dtype=np.uint64)
>>> x[0].dtype
dtype('uint64')
>>> isinstance(x[0], np.uint64)
True
>>> isinstance(x[0], np.integer)
True  # generic integer
>>> isinstance(x[0], int)
False  # but not a python int in this case

# Try matching the `kind` strings, e.g.
>>> np.dtype('bool').kind                                                                                           
'b'
>>> np.dtype('int64').kind                                                                                          
'i'
>>> np.dtype('float').kind                                                                                          
'f'
>>> np.dtype('half').kind                                                                                           
'f'

# But be weary of matching dtypes
>>> np.integer
<class 'numpy.integer'>
>>> np.dtype(np.integer)
dtype('int64')
>>> x[0].dtype == np.dtype(np.integer)
False

# Down these paths there be dragons:

# the .dtype attribute returns a kind of dtype, not a specific dtype
>>> isinstance(x[0].dtype, np.dtype)
True
>>> isinstance(x[0].dtype, np.uint64)
False  
>>> isinstance(x[0].dtype, np.dtype(np.uint64))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types
# yea, don't go there
>>> isinstance(x[0].dtype, np.int_)
False  # again, confusing the .dtype with a specific dtype


# Inequalities can be tricky, although they might
# work sometimes, try to avoid these idioms:

>>> x[0].dtype <= np.dtype(np.uint64)
True
>>> x[0].dtype <= np.dtype(np.float)
True
>>> x[0].dtype <= np.dtype(np.half)
False  # just when things were going well
>>> x[0].dtype <= np.dtype(np.float16)
False  # oh boy
>>> x[0].dtype == np.int
False  # ya, no luck here either
>>> x[0].dtype == np.int_
False  # or here
>>> x[0].dtype == np.uint64
True  # have to end on a good note!
Darren Weber
quelle