Come identificare i tipi numpy in Python?


100

Come si può determinare in modo affidabile se un oggetto ha un tipo numpy?

Mi rendo conto che questa domanda va contro la filosofia della dattilografia, ma l'idea è di assicurarsi che una funzione (che usa scipy e numpy) non restituisca mai un tipo numpy a meno che non venga chiamata con un tipo numpy. Questo emerge nella soluzione di un'altra domanda, ma penso che il problema generale di determinare se un oggetto ha un tipo insensibile è abbastanza lontano da quella domanda originale che dovrebbero essere separati.


Una domanda: se tu (o, diciamo, scipy) definisci un tipo che sottoclasse un tipo numpy, dovrebbe contare o no? (Credo che non puoi sottoclassare i tipi numpy in Python, ma puoi farlo in un modulo C, e penso che tu possa anche sottoclassare i tipi numpypy in PyPy ... quindi probabilmente non importa, ma non è inconcepibile che possa farlo.)
abarnert

Non ci avevo pensato; fondamentalmente il tuo commento fa notare che la domanda è più difficile del previsto. Onestamente quel tipo di considerazione di alto livello è decisamente eccessivo per la mia situazione. Per la risposta generale e portatile, direi che finché il comportamento è definito, allora va bene.
Douglas B. Staple

Risposte:


116

Usa la typefunzione incorporata per ottenere il tipo, quindi puoi usare la __module__proprietà per scoprire dove è stata definita:

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

numpy.ma.MaskedArray non è ad esempio un tipo abbastanza numpy?
panda-34

Se vuoi qualcosa in numpy. * Basta camminare nel pacchetto genitore del modulo. (A quel punto, ovviamente vuoi racchiuderlo in una funzione.) E se vuoi che i DataFrames dei panda contino come numpyish, aggiungi un o per testarlo. E così via. Il punto è che devi sapere cosa stai effettivamente chiedendo quando vuoi fare qualcosa di insolito come il cambio di tipo manuale, ma una volta che lo sai, è facile da implementare.
abarnert

1
Questa soluzione sembra molto poco pitonica, basandosi su attributi nascosti. Ma forse è solo una questione di gusti?
j08lue

2
@ j08lue Non sono attributi nascosti, sono attributi speciali documentati. Tuttavia, non è mitico, ma penso che sia inerente al problema. (E penso che sia un punto di forza di Python il fatto che quando vuoi fare qualcosa che il linguaggio scoraggia, la soluzione migliore è di solito visibilmente abbastanza brutta da far capire che stai facendo qualcosa che normalmente è una cattiva idea.)
abarnert

69

La soluzione che ho trovato è:

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

Tuttavia, non è chiaro al 100% che tutti i tipi di numpy siano garantiti np.ndarrayo np.generic, e questa probabilmente non è robusta.


1
Suppongo che potresti filtrare dir(numpy)su tipi e funzioni incorporate (e classi, ma non penso che ne abbia) e usarlo per generare una tupla to isinstanceagainst, che sarebbe robusta. (Credo che tu possa passare funzioni incorporate a isinstance che siano effettivamente costruttori di tipo o meno, ma dovresti controllarlo.)
abarnert

Sì, dovrebbero essere tutte sottoclassi di quei due AFAIK.
seberg

@seberg Grazie. Sicuramente sembra essere il caso per ora, ma la documentazione di Python non è molto chiara su questo e potrebbe plausibilmente cambiare in futuro.
Douglas B. Staple,

19

Vecchia domanda ma ho trovato una risposta definitiva con un esempio. Non posso far male a mantenere le domande fresche perché ho avuto lo stesso problema e non ho trovato una risposta chiara. La chiave è assicurarsi di aver numpyimportato e quindi eseguire il isinstancebool. Anche se questo può sembrare semplice, se stai eseguendo alcuni calcoli su diversi tipi di dati, questo piccolo controllo può servire come un rapido test prima di iniziare qualche operazione vettorizzata 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)

9

In realtà dipende da cosa stai cercando.

  • Se vuoi verificare se una sequenza è effettivamente a ndarray, a isinstance(..., np.ndarray)è probabilmente la più semplice. Assicurati di non ricaricare numpy in background poiché il modulo potrebbe essere diverso, ma altrimenti dovresti stare bene. MaskedArrays, matrix, recarraySiete tutte le sottoclassi di ndarray, quindi si dovrebbe essere impostato.
  • Se vuoi verificare se uno scalare è uno scalare numpy, le cose si complicano un po '. Puoi controllare se ha shapeun dtypeattributo e. Puoi confrontarlo dtypecon i dtypes di base, il cui elenco puoi trovare in np.core.numerictypes.genericTypeRank. Nota che gli elementi di questo elenco sono stringhe, quindi dovresti fare un tested.dtype is np.dtype(an_element_of_the_list)...

+1. Se stai effettivamente cercando qualcosa oltre a "è un numpytipo" e puoi definire cos'è quel qualcosa, questa è migliore delle altre risposte. E nella maggior parte dei casi, dovresti cercare qualcosa di specifico che puoi definire.
abarnert

8

Per ottenere il tipo, usa la typefunzione incorporata . Con l' inoperatore, puoi verificare se il tipo è un tipo numpy controllando se contiene la stringa 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

(Questo esempio è stato eseguito in IPython , tra l'altro. Molto utile per l'uso interattivo e test rapidi.)


2
Funziona, ma se definisci un tipo chiamato, ad esempio, "numpygroup", otterrai falsi positivi. Inoltre, dipendere dalla rappresentazione di stringa dei tipi è una cattiva idea se puoi evitarlo, e in questo caso puoi. Guarda invece il suo modulo.
abarnert

L'utilizzo del modulo è davvero una soluzione migliore.
Roland Smith

È possibile utilizzare l'
espressione regolare

@ Omkaar.K Regex potrebbe essere usato per cosa? Per fare lo stesso identico controllo in un modo leggermente più complicato?
abarnert il

@abamert "Could" è quello che ho detto, anche la regex potrebbe sembrare complicata per compiti semplici come questi, ma è estremamente utile per compiti di elaborazione di stringhe di grandi dimensioni, quindi non è una cattiva idea impararla. Immagino che tu lo sappia già da quando il tuo portfolio ti ritrae come un programmatore senior?
omkaartg

3

Nota che type(numpy.ndarray)è a typese stesso e fai attenzione ai tipi booleani e scalari. Non scoraggiarti troppo se non è intuitivo o facile, all'inizio è un dolore.

Vedi anche: - 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

Divertimento con i booleani:

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

Più divertimento con i tipi scalari, vedi: - 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!
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.