Comment identifier les types numpy en python?

100

Comment déterminer de manière fiable si un objet a un type numpy?

Je me rends compte que cette question va à l'encontre de la philosophie du typage canard, mais l'idée est de s'assurer qu'une fonction (qui utilise scipy et numpy) ne renvoie jamais un type numpy à moins qu'elle ne soit appelée avec un type numpy. Cela vient dans la solution à une autre question, mais je pense que le problème général de déterminer si un objet a un type numpy est suffisamment éloigné de cette question originale pour qu'ils devraient être séparés.

Douglas B. Staple
la source
Une question: si vous (ou, disons, scipy) définissez un type qui sous-classe un type numpy, cela devrait-il compter ou non? (Je crois que vous ne pouvez pas sous-classer les types numpy en Python, mais vous pouvez le faire dans un module C, et je pense que vous pouvez également sous-classer les types numpypy dans PyPy ... donc cela n'a probablement pas d'importance, mais ce n'est pas inconcevable que cela le puisse.)
abarnert le
Je n'avais pas pensé à ça; votre commentaire fait essentiellement ressortir que la question est plus difficile que prévu. Honnêtement, ce genre de considération de haut niveau est bien exagéré pour ma situation. Pour la réponse générale et portable, je dirais que tant que le comportement est défini, tout va bien.
Douglas B.Staple

Réponses:

116

Utilisez la typefonction intégrée pour obtenir le type, puis vous pouvez utiliser la __module__propriété pour savoir où elle a été définie:

>>> 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
la source
est-ce que numpy.ma.MaskedArray n'est pas un type assez numpy?
panda-34
Si vous voulez quelque chose dans numpy. *, Il vous suffit de parcourir le paquet parent du module. (À ce stade, vous voulez évidemment l'envelopper dans une fonction.) Et si vous voulez que les pandas DataFrames comptent comme numpyish, ajoutez un ou pour tester cela. Etc. Le fait est que vous devez savoir ce que vous demandez réellement lorsque vous voulez faire quelque chose d'aussi inhabituel que le changement de type manuel, mais une fois que vous le savez, c'est facile à mettre en œuvre.
abarnert
1
Cette solution semble très impythonique, reposant sur des attributs cachés. Mais c'est peut-être juste une question de goût?
j08lue
2
@ j08lue Ce ne sont pas des attributs cachés, ce sont des attributs spéciaux documentés. C'est néanmoins impythonique, mais je pense que c'est inhérent au problème. (Et je pense que c'est une force de Python que lorsque vous voulez faire quelque chose que le langage décourage, la meilleure solution est généralement assez moche pour dire que vous faites quelque chose qui est normalement une mauvaise idée.)
abarnert
69

La solution que j'ai trouvée est:

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

Cependant, il n'est pas clair à 100% que tous les types numpy sont garantis soit np.ndarrayou np.generic, et ce n'est probablement pas une version robuste.

Douglas B. Staple
la source
1
Je suppose que vous pouvez filtrer dir(numpy)sur les types et les fonctions intégrées (et les classes, mais je ne pense pas qu'il en ait) et l'utiliser pour générer un tuple à isinstancecontre, ce qui serait robuste. (Je crois que vous pouvez passer des fonctions intégrées à isinstance, qu'il s'agisse en fait de constructeurs de type ou non, mais vous devrez vérifier cela.)
abarnert
Oui, ils devraient tous être des sous-classes de ces deux AFAIK.
seberg
@seberg Merci. Cela semble certainement être le cas pour le moment, mais la documentation de python n'est pas très claire à ce sujet et elle pourrait éventuellement changer à l'avenir.
Douglas B.Staple
19

Ancienne question mais j'ai trouvé une réponse définitive avec un exemple. Je ne peux pas faire de mal à garder les questions fraîches car j'ai eu ce même problème et je n'ai pas trouvé de réponse claire. La clé est de vous assurer que vous avez numpyimporté, puis d'exécuter le isinstancebooléen. Bien que cela puisse sembler simple, si vous effectuez des calculs sur différents types de données, cette petite vérification peut servir de test rapide avant de commencer une opération vectorisée numpy.

##################
# 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
la source
9

Cela dépend en fait de ce que vous recherchez.

  • Si vous voulez tester si une séquence est réellement a ndarray, a isinstance(..., np.ndarray)est probablement le plus simple. Assurez-vous de ne pas recharger numpy en arrière-plan car le module peut être différent, mais sinon, vous devriez être OK. MaskedArrays, matrix, recarraySont toutes les sous - classes de ndarray, vous devriez donc être réglé.
  • Si vous voulez tester si un scalaire est un scalaire numpy, les choses deviennent un peu plus compliquées. Vous pouvez vérifier s'il a un shapeet un dtypeattribut. Vous pouvez le comparer dtypeaux dtypes de base, dont vous pouvez trouver la liste np.core.numerictypes.genericTypeRank. Notez que les éléments de cette liste sont des chaînes, vous devrez donc faire un tested.dtype is np.dtype(an_element_of_the_list)...
Pierre GM
la source
+1. Si vous cherchez réellement quelque chose en plus de "est un numpytype" et que vous pouvez définir ce qu'est ce quelque chose, c'est mieux que les autres réponses. Et dans la plupart des cas, vous devriez rechercher quelque chose de spécifique que vous pouvez définir.
abarnert le
8

Pour obtenir le type, utilisez la typefonction intégrée . Avec l' inopérateur, vous pouvez tester si le type est un type numpy en vérifiant s'il contient la chaîne 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

(Cet exemple a été exécuté en IPython , d'ailleurs. Très pratique pour une utilisation interactive et des tests rapides.)

Roland Smith
la source
2
Cela fonctionne, mais si vous définissez un type appelé, par exemple, "numpygroup", vous obtiendrez des faux positifs. En outre, dépendre de la représentation sous forme de chaîne des types est une mauvaise idée si vous pouvez l'éviter - et dans ce cas, vous le pouvez. Regardez plutôt son module.
abarnert le
L'utilisation du module est en effet une meilleure solution.
Roland Smith
Regex pourrait être utilisé
omkaartg
@ Omkaar.K Regex pourrait être utilisé pour quoi? Faire exactement la même vérification d'une manière un peu plus compliquée?
abarnert le
@abamert "Could" est ce que j'ai dit, aussi regex pourrait sembler compliqué pour des tâches simples comme celles-ci, mais c'est extrêmement utile pour les tâches de traitement de grandes chaînes, donc ce n'est pas une mauvaise idée de l'apprendre. Je suppose que vous le savez déjà depuis que votre portfolio vous présente comme un programmeur senior?
omkaartg
3

Notez que le type(numpy.ndarray)est un typelui-même et faites attention aux types booléens et scalaires. Ne vous découragez pas trop si ce n'est pas intuitif ou facile, c'est une douleur au début.

Voir aussi: - 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

Amusez-vous avec les booléens:

>>> 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

Plus amusant avec les types scalaires, voir: - 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
la source