Jak rozpoznać typy numpy w Pythonie?

100

Jak można wiarygodnie określić, czy obiekt ma typ numpy?

Zdaję sobie sprawę, że to pytanie jest sprzeczne z filozofią pisania typu kaczego, ale chodzi o to, aby upewnić się, że funkcja (która używa scipy i numpy) nigdy nie zwraca typu numpy, chyba że zostanie wywołana typem numpy. To pojawia się w rozwiązaniu innego pytania, ale myślę, że ogólny problem określenia, czy obiekt ma typ numpy, jest na tyle daleki od pierwotnego pytania, że ​​należy je oddzielić.

Douglas B. Staple
źródło
Jedno pytanie: jeśli (lub powiedzmy, scipy) zdefiniujesz typ, który jest podklasą typu numpy, czy to się liczy, czy nie? (Uważam, że w Pythonie nie można tworzyć podklasy typów numpy, ale można w module C i myślę, że w PyPy można również podklasować typy numpypy… więc prawdopodobnie nie ma to znaczenia, ale nie jest wykluczone, że może.)
abarnert
Nie pomyślałem o tym; w zasadzie twój komentarz wskazuje, że pytanie jest trudniejsze niż oczekiwano. Szczerze mówiąc, tego rodzaju rozważanie na wysokim szczeblu jest przesadą w mojej sytuacji. Dla ogólnej i przenośnej odpowiedzi powiedziałbym, że dopóki zachowanie jest zdefiniowane, jest OK.
Douglas B. Staple

Odpowiedzi:

116

Użyj typefunkcji wbudowanej, aby uzyskać typ, a następnie możesz użyć __module__właściwości, aby dowiedzieć się, gdzie został zdefiniowany:

>>> 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
źródło
czy np. numpy.ma.MaskedArray nie jest wystarczająco numpy?
panda-34
Jeśli chcesz coś w numpy. *, Po prostu przejrzyj pakiet nadrzędny modułu. (W tym momencie oczywiście chcesz zawinąć go w funkcję.) A jeśli chcesz, aby pandy DataFrames liczyły się jako numpyish, dodaj lub, aby to sprawdzić. I tak dalej. Chodzi o to, że musisz wiedzieć, o co tak naprawdę prosisz, gdy chcesz zrobić coś tak niezwykłego, jak luźne ręczne przełączanie typów, ale kiedy już wiesz, jest to łatwe do zaimplementowania.
abarnert
1
To rozwiązanie wydaje się bardzo nieszablonowe, polegające na ukrytych atrybutach. Ale może to tylko kwestia gustu?
j08lue
2
@ j08lue Nie są to atrybuty ukryte, są to udokumentowane atrybuty specjalne. Mimo wszystko jest to nie szpiegoniczne, ale myślę, że jest to nieodłącznie związane z problemem. (I myślę, że to siła Pythona to, że kiedy chcesz zrobić coś, czego język odradza, najlepsze rozwiązanie jest zwykle na tyle brzydkie, że wskazuje, że robisz coś, co zwykle jest złym pomysłem.)
abarnert
69

Rozwiązanie, które wymyśliłem, to:

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

Jednak to nie jest w 100% jasne, że wszystkie NumPy typy są gwarantowane być albo np.ndarrayalbo np.generic, i to chyba nie jest wersja wytrzymałe.

Douglas B. Staple
źródło
1
Przypuszczam, że można by filtrować dir(numpy)typy i funkcje wbudowane (i klasy, ale nie sądzę, że ma jakieś) i użyć tego do wygenerowania krotki isinstanceprzeciwko, co byłoby solidne. (Wierzę, że możesz przekazać wbudowane funkcje do instancji, niezależnie od tego, czy są one faktycznie konstruktorami typu, czy nie, ale musisz to sprawdzić.)
abarnert
Tak, wszystkie powinny być podklasami tych dwóch AFAIK.
seberg
@seberg Thanks. Na razie wydaje się, że tak jest, ale dokumentacja Pythona nie jest w tym zbyt jasna i może się to zmienić w przyszłości.
Douglas B. Staple,
19

Stare pytanie, ale ostateczną odpowiedź wymyśliłem na przykładzie. Nie zaszkodzi zachować świeżość pytań, ponieważ miałem ten sam problem i nie znalazłem jasnej odpowiedzi. Najważniejsze jest, aby upewnić się, że numpyzaimportowałeś, a następnie uruchomić isinstancebool. Chociaż może się to wydawać proste, jeśli wykonujesz obliczenia na różnych typach danych, to małe sprawdzenie może służyć jako szybki test przed rozpoczęciem jakiejś numpy wektoryzowanej operacji.

##################
# 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
źródło
9

To właściwie zależy od tego, czego szukasz.

  • Jeśli chcesz sprawdzić, czy sekwencja jest rzeczywiście a ndarray, isinstance(..., np.ndarray)prawdopodobnie najłatwiejsza jest metoda a. Upewnij się, że nie ładujesz ponownie numpy w tle, ponieważ moduł może być inny, ale w przeciwnym razie powinno być OK. MaskedArrays, matrix, recarrayTo wszystkie podklasy ndarray, tak powinno być ustawione.
  • Jeśli chcesz sprawdzić, czy skalar jest nieczułym skalarem, sprawy stają się nieco bardziej skomplikowane. Można sprawdzić, czy ma on shapea dtypeatrybut. Możesz porównać dtypeto z podstawowymi typami, których listę znajdziesz w np.core.numerictypes.genericTypeRank. Zwróć uwagę, że elementy tej listy to ciągi, więc musiałbyś wykonać tested.dtype is np.dtype(an_element_of_the_list)...
Pierre GM
źródło
+1. Jeśli faktycznie szukasz czegoś innego niż „jest numpytypem” i możesz określić, czym to coś jest, to jest to lepsze niż inne odpowiedzi. W większości przypadków powinieneś szukać czegoś konkretnego, co możesz zdefiniować.
abarnert
8

Aby uzyskać typ, użyj typefunkcji wbudowanej . Za pomocą inoperatora możesz sprawdzić, czy typ jest numpy, sprawdzając, czy zawiera ciąg 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

( Nawiasem mówiąc, ten przykład został uruchomiony w IPythonie . Bardzo przydatny do interaktywnego użytku i szybkich testów).

Roland Smith
źródło
2
To działa, ale jeśli zdefiniujesz typ o nazwie, powiedzmy, „numpygroup”, otrzymasz fałszywe alarmy. Ponadto, uzależnienie się od reprezentacji łańcuchowej typów jest złym pomysłem, jeśli możesz tego uniknąć - aw tym przypadku możesz. Zamiast tego spójrz na jego moduł.
abarnert
Korzystanie z modułu jest rzeczywiście lepszym rozwiązaniem.
Roland Smith
Można użyć Regex
omkaartg
@ Omkaar.K Regex może być używany do czego? Aby zrobić dokładnie to samo sprawdzenie w nieco bardziej skomplikowany sposób?
abarnert
@abamert „Could” jest tym, co powiedziałem, również wyrażenie regularne może wyglądać na skomplikowane w przypadku prostych zadań, takich jak te, ale jest niezwykle przydatne w przypadku zadań przetwarzania dużych ciągów, więc nauczenie się tego nie jest złym pomysłem. Chyba wiesz, że skoro twoje portfolio przedstawia cię jako starszego programistę?
omkaartg
3

Zwróć uwagę, że type(numpy.ndarray)jest typesam w sobie i uważaj na typy logiczne i skalarne. Nie zniechęcaj się, jeśli nie jest to intuicyjne lub łatwe, na początku jest to ból.

Zobacz też: - 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

Zabawa z wartościami logicznymi:

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

Więcej zabawy z typami skalarnymi, patrz: - 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
źródło