Разные кусочки дают разные неравенства для одинаковых элементов - PullRequest
5 голосов
/ 28 марта 2020
import numpy as np

a = np.array([.4], dtype='float32')
b = np.array([.4, .6])

print(a > b)
print(a > b[0], a > b[1])
print(a[0] > b[0], a[0] > b[1])
[ True False]
[False] [False]
True False

В чем дело? Да, b.dtype == 'float64', но его ломтики b[0] & b[1], а a остается 'float32'.

Примечание : я спрашиваю почему это происходит, а не как обойти это, что я знаю (например, приведение обоих к 'float64').

1 Ответ

2 голосов
/ 28 марта 2020

Как я заметил в другом ответе , приведение типов в numpy довольно сложно, и это root причина поведения, которое вы видите. Документы, связанные в этом ответе, ясно дают понять, что скаляры (/ 0d-массивы) и 1d-массивы отличаются в преобразованиях типов, поскольку последние не рассматриваются как значение по значению.

Первая половина проблемы, которую вы уже знаете : проблема в том, что преобразование типов происходит по-разному для ваших двух случаев:

>>> (a + b).dtype
dtype('float64')

>>> (a + b[0]).dtype
dtype('float32')

>>> (a[0] + b[0]).dtype
dtype('float64')

Я полагаю, что мы можем понять, что происходит в вашем примере, если мы рассмотрим таблицы преобразования типов:

>> from numpy.testing import print_coercion_tables
can cast
[...]

In these tables, ValueError is '!', OverflowError is '@', TypeError is '#'

scalar + scalar
+ ? b h i l q p B H I L Q P e f d g F D G S U V O M m 
? ? b h i l q l B H I L Q L e f d g F D G # # # O ! m 
b b b h i l q l h i l d d d e f d g F D G # # # O ! m 
h h h h i l q l h i l d d d f f d g F D G # # # O ! m 
i i i i i l q l i i l d d d d d d g D D G # # # O ! m 
l l l l l l q l l l l d d d d d d g D D G # # # O ! m 
q q q q q q q q q q q d d d d d d g D D G # # # O ! m 
p l l l l l q l l l l d d d d d d g D D G # # # O ! m 
B B h h i l q l B H I L Q L e f d g F D G # # # O ! m 
H H i i i l q l H H I L Q L f f d g F D G # # # O ! m 
I I l l l l q l I I I L Q L d d d g D D G # # # O ! m 
L L d d d d d d L L L L Q L d d d g D D G # # # O ! m 
Q Q d d d d d d Q Q Q Q Q Q d d d g D D G # # # O ! m 
P L d d d d d d L L L L Q L d d d g D D G # # # O ! m 
e e e f d d d d e f d d d d e f d g F D G # # # O ! # 
f f f f d d d d f f d d d d f f <b>d</b> g F D G # # # O ! # 
d d d d d d d d d d d d d d d d d g D D G # # # O ! # 
g g g g g g g g g g g g g g g g g g G G G # # # O ! # 
F F F F D D D D F F D D D D F F D G F D G # # # O ! # 
D D D D D D D D D D D D D D D D D G D D G # # # O ! # 
G G G G G G G G G G G G G G G G G G G G G # # # O ! # 
S # # # # # # # # # # # # # # # # # # # # # # # O ! # 
U # # # # # # # # # # # # # # # # # # # # # # # O ! # 
V # # # # # # # # # # # # # # # # # # # # # # # O ! # 
O O O O O O O O O O O O O O O O O O O O O O O O O ! # 
M ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 
m m m m m m m m m m m m m m # # # # # # # # # # # ! m 

scalar + neg scalar
[...]

array + scalar
+ ? b h i l q p B H I L Q P e f d g F D G S U V O M m 
? ? b h i l q l B H I L Q L e f d g F D G # # # O ! m 
b b b b b b b b b b b b b b e f d g F D G # # # O ! m 
h h h h h h h h h h h h h h f f d g F D G # # # O ! m 
i i i i i i i i i i i i i i d d d g D D G # # # O ! m 
l l l l l l l l l l l l l l d d d g D D G # # # O ! m 
q q q q q q q q q q q q q q d d d g D D G # # # O ! m 
p l l l l l l l l l l l l l d d d g D D G # # # O ! m 
B B B B B B B B B B B B B B e f d g F D G # # # O ! m 
H H H H H H H H H H H H H H f f d g F D G # # # O ! m 
I I I I I I I I I I I I I I d d d g D D G # # # O ! m 
L L L L L L L L L L L L L L d d d g D D G # # # O ! m 
Q Q Q Q Q Q Q Q Q Q Q Q Q Q d d d g D D G # # # O ! m 
P L L L L L L L L L L L L L d d d g D D G # # # O ! m 
e e e e e e e e e e e e e e e e e e F F F # # # O ! # 
f f f f f f f f f f f f f f f f <b>f</b> f F F F # # # O ! # 
d d d d d d d d d d d d d d d d d d D D D # # # O ! # 
g g g g g g g g g g g g g g g g g g G G G # # # O ! # 
F F F F F F F F F F F F F F F F F F F F F # # # O ! # 
D D D D D D D D D D D D D D D D D D D D D # # # O ! # 
G G G G G G G G G G G G G G G G G G G G G # # # O ! # 
S # # # # # # # # # # # # # # # # # # # # # # # O ! # 
U # # # # # # # # # # # # # # # # # # # # # # # O ! # 
V # # # # # # # # # # # # # # # # # # # # # # # O ! # 
O O O O O O O O O O O O O O O O O O O O O O O O O ! # 
M ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 
m m m m m m m m m m m m m m # # # # # # # # # # # ! m

[...]

Вышесказанное является частью текущих рекламных таблиц для продвижения на основе стоимости. Он обозначает, как различные типы влияют на тип результата при сопряжении двух numpy объектов данного вида (см. Первый столбец и первую строку для указанных c типов). Типы следует понимать в соответствии с односимвольными спецификациями dtype (ниже "Односимвольные строки"), в частности, np.dtype('f') соответствует np.float32 (f для C -плава типа) и np.dtype('d') (d для C в стиле double) до np.float64 (см. также np.typename('f') и то же самое для 'd').

Я отметил два пункта, выделенных жирным шрифтом в приведенных выше таблицах :

скаляр f + скаляр d -> d
массив f + скаляр d -> f

Теперь давайте рассмотрим ваши случаи. Предполагается, что у вас есть 'f' массив a и 'd' массив b. Тот факт, что a имеет только один элемент, не имеет значения: это массив 1d длиной 1, а не массив 0d.

  1. Когда вы делаете a > b, вы сравниваете два массива, это не обозначено в приведенных выше таблицах. Я не уверен, что поведение здесь; я предполагаю, что a передается в форме b, а затем его тип приводится к 'd'. Я думаю, что причина в том, что np.can_cast(a, np.float64) - это True, а np.can_cast(b, np.float32) - False. Но это всего лишь предположение, что многие из этих механизмов в numpy не интуитивны для меня.

  2. Когда вы делаете a > b[0], вы сравниваете массив 'f' с 'd' скаляр, так что согласно приведенному выше вы получите массив 'f'. Вот что (a + b[0]).dtype сказал нам. (Когда вы используете a > b[0], вы не видите шаг преобразования, потому что результат всегда является логическим.)

  3. Когда вы делаете a[0] > b[0], вы сравниваете 'f' от скаляра до 'd' скаляра, поэтому в соответствии с вышеизложенным вы получите 'd' скаляр. Вот что (a[0] + b[0]).dtype сказал нам.

Так что я считаю, что все это соответствует причудам преобразования типов в numpy. Хотя это может показаться неудачным угловым случаем со значением 0.4 в двойной и одинарной точности, эта функция идет глубже, и проблема служит большим красным предупреждением о том, что вы должны быть очень осторожны при смешивании разных dtypes.

Самый безопасный способ действий - преобразовать ваши типы самостоятельно, чтобы контролировать, что происходит в вашем коде. Тем более, что обсуждается вопрос о пересмотре некоторых аспектов продвижения типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...