Как определить типы numpy в Python?

100

Как можно надежно определить, имеет ли объект тип numpy?

Я понимаю, что этот вопрос идет вразрез с философией утиной печати, но идея состоит в том, чтобы убедиться, что функция (которая использует scipy и numpy) никогда не возвращает тип numpy, если она не вызывается с типом numpy. Это возникает в решении другого вопроса, но я думаю, что общая проблема определения того, имеет ли объект тип numpy, достаточно далека от этого исходного вопроса, чтобы их следует разделять.

Дуглас Б. Стейпл
источник
Один вопрос: если вы (или, скажем, scipy) определяете тип, который является подклассом numpy-типа, должно ли это учитываться или нет? (Я считаю, что вы не можете подклассифицировать numpy-типы в Python, но вы можете создать подклассы numpypy-типов в Python, и я думаю, что вы также можете подклассифицировать numpypy-типы в PyPy ... так что это, вероятно, не имеет значения, но вполне возможно, что это возможно.)
abarnert
Я не думал об этом; в основном ваш комментарий указывает на то, что вопрос сложнее, чем ожидалось. Честно говоря, такого рода рассмотрение на высоком уровне является излишним для моей ситуации. Что касается общего и переносимого ответа, я бы сказал, что пока поведение определено, все в порядке.
Дуглас Б. Стейпл,

Ответы:

116

Используйте встроенную typeфункцию, чтобы получить тип, затем вы можете использовать __module__свойство, чтобы узнать, где он был определен:

>>> 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
источник
Например, numpy.ma.MaskedArray не является достаточно большим числом?
panda-34
Если вам нужно что-нибудь в numpy. *, Вы просто переходите по родительскому пакету модуля. (На этом этапе вы, очевидно, хотите обернуть это функцией.) И если вы хотите, чтобы pandas DataFrames считались numpyish, добавьте или, чтобы проверить это. И так далее. Дело в том, что вы должны знать, о чем на самом деле просите, когда хотите сделать что-то столь необычное, как свободное переключение типов вручную, но как только вы знаете, это легко реализовать.
abarnert
1
Это решение кажется очень непонятным, полагаясь на скрытые атрибуты. Но, может, это дело вкуса?
j08lue 05
2
@ j08lue Это не скрытые атрибуты, это задокументированные специальные атрибуты. Это, тем не менее, непифонично, но я думаю, что это неотъемлемая часть проблемы. (И я думаю, что сильная сторона Python состоит в том, что когда вы хотите сделать что-то, что язык не одобряет, лучшее решение обычно выглядит достаточно уродливым, чтобы заявить о том, что вы делаете что-то, что обычно является плохой идеей.)
abarnert
69

Решение, которое я придумал:

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

Однако не на 100% ясно, что все типы numpy гарантированно будут либо np.ndarrayили np.generic, и это, вероятно, не является устойчивым к версии.

Дуглас Б. Стейпл
источник
1
Я полагаю, вы могли бы фильтровать dir(numpy)типы и встроенные функции (и классы, но я не думаю, что они есть) и использовать это для создания кортежа для isinstanceпротив, что было бы надежным. (Я считаю, что вы можете передавать встроенные функции в isinstance, независимо от того, являются ли они конструкторами типов или нет, но вам нужно это проверить.)
abarnert
Да, все они должны быть подклассами этих двух AFAIK.
seberg
@seberg Спасибо. На данный момент это, безусловно, так, но документация python не очень ясна по этому поводу, и, возможно, это может измениться в будущем.
Дуглас Б. Стейпл
19

Старый вопрос, но я пришел к окончательному ответу на примере. Не помешает держать вопросы свежими, так как у меня была такая же проблема, и я не нашел четкого ответа. Ключ в том, чтобы убедиться, что вы numpyимпортировали, а затем запустить команду isinstancebool. Хотя это может показаться простым, если вы выполняете какие-то вычисления с разными типами данных, эта небольшая проверка может послужить быстрой проверкой перед тем, как вы начнете некоторую векторизованную операцию.

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

import numpy as np

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

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

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

isinstance(arr,np.ndarray)
Линвудc3
источник
9

На самом деле это зависит от того, что вы ищете.

  • Если вы хотите проверить, действительно ли последовательность является a ndarray, isinstance(..., np.ndarray)вероятно, самый простой вариант. Убедитесь, что вы не перезагружаете numpy в фоновом режиме, так как модуль может отличаться, но в противном случае все должно быть в порядке. MaskedArrays, matrix, recarrayВсе подклассы ndarray, так что вы должны быть установлены.
  • Если вы хотите проверить, является ли скаляр числовым скаляром, все становится немного сложнее. Вы можете проверить , имеет ли он shapeи в dtypeатрибут. Вы можете сравнить его dtypeс основными dtypes, список которых вы можете найти в np.core.numerictypes.genericTypeRank. Обратите внимание, что элементы этого списка являются строками, поэтому вам нужно будет выполнить tested.dtype is np.dtype(an_element_of_the_list)...
Пьер GM
источник
+1. Если вы действительно ищете что-то помимо «является numpyтипом» и можете определить, что это за что-то, это лучше, чем другие ответы. И в большинстве случаев вам следует искать что-то конкретное, что вы можете определить.
abarnert
8

Чтобы получить тип, используйте встроенную typeфункцию. С помощью inоператора вы можете проверить, является ли тип типом numpy, проверив, содержит ли он строку 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

(Этот пример , кстати, был запущен в IPython . Очень удобен для интерактивного использования и быстрых тестов.)

Роланд Смит
источник
2
Это работает, но если вы определите тип с именем, скажем, «numpygroup», вы получите ложные срабатывания. Кроме того, зависимость от строкового представления типов - плохая идея, если вы можете этого избежать, а в данном случае вы можете. Вместо этого посмотрите на его модуль.
abarnert
Использование модуля - действительно лучшее решение.
Роланд Смит,
Можно использовать
регулярное выражение
@ Omkaar.K Для чего можно использовать Regex? Чтобы сделать ту же самую проверку немного более сложным способом?
abarnert
@abamert "Может" - это то, что я сказал, также регулярное выражение может выглядеть сложным для простых задач, подобных этой, но оно чрезвычайно полезно для больших задач обработки строк, поэтому неплохо изучить его. Думаю, вы уже знаете об этом, поскольку в вашем портфолио вы изображены как старший программист?
omkaartg
3

Обратите внимание, что type(numpy.ndarray)это typeсамо по себе, и обратите внимание на логические и скалярные типы. Не расстраивайтесь, если это не интуитивно или просто, поначалу это неприятно.

См. Также: - 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

Развлечение с логическими значениями:

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

Больше удовольствия от скалярных типов см .: - 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!
Даррен Вебер
источник