В Numpy 2 есть отдельный float64(nan) – как от него избавиться?

Похоже, что в Numpy 2 появился свой отдельный float64(nan), отличный от np.nan. Теперь регрессионные тесты терпят неудачу, потому что пока

>>> np.nan is np.nan
True

у нас теперь есть

>>> np.nan is np.float64("nan")
False

(также json не может сериализовать эти новые NaN).

Почему они внесли это изменение?

Есть ли способ автоматически преобразовать числа с плавающей запятой в обычные числа с плавающей запятой?

🤔 А знаете ли вы, что...
Python популярен в машинном обучении и искусственном интеллекте.


1
67
1

Ответ:

Решено

Существует несколько NaN (см. ниже и NaN в качестве ссылки), и Python может повторно использовать объекты или нет. Использование X is Y в рамках модульного теста является здесь основной проблемой.

Например, np.inf - np.inf дает np.nan:

np.inf-np.inf
# nan

И все еще:

np.nan is (np.inf-np.inf)
# False

Если вы хотите узнать, является ли объект NaN, всегда используйте np.isnan (или эквивалент math или pandas), никогда не сравнивайте объекты или is:

np.isnan((np.inf-np.inf))
# True

подробнее о NaN и объектах Python

NaN не кодируются одним способом. Могут быть тихие NaN (неоднозначная операция) или сигнальные NaN (ошибочная операция). Кроме того, Python может повторно использовать объекты… или нет.

При запуске np.nan is np.nan Python использует один и тот же объект для обоих. Если вы запускаете np.log(-1) is np.log(-1) на моей машине, это создает два разных объекта, и результат False:

np.log(-1) is np.log(-1)
# False

Чтобы дать вам более сложный пример, на моей машине np.nan всегда выдается один и тот же объект. Тихие/сигнальные NaN всегда создают разные объекты. Последовательное создание одного типа NaN иногда приводит к повторному использованию объекта, а иногда нет:

(id(np.nan),        # 135051355677520
 id(np.inf-np.inf), # 135046756258928
 id(float('nan')),  # 135046756258928
 id(np.log(-1)),    # 135046756256624  # triggers warning
 id(np.sqrt(-1)),   # 135046756256624  # triggers warning # same as previous
 id(float('nan')),  # 135046756258928                     # same as before
 id(np.sqrt(-1)),   # 135046756261584  # triggers warning # different
 id(np.nan),        # 135051355677520                     # same as before
)

При повторном запуске все идентификаторы меняются, но по той же схеме. np.nan остается стабильным:

(id(np.nan),        # 135051355677520
 id(np.inf-np.inf), # 135046756261872
 id(float('nan')),  # 135046756261872
 id(np.log(-1)),    # 135046756262736  # triggers warning
 id(np.sqrt(-1)),   # 135046756262736  # triggers warning # same as previous
 id(float('nan')),  # 135046756261872                     # same as before
 id(np.sqrt(-1)),   # 135046756262640  # triggers warning # different
 id(np.nan),        # 135051355677520                     # same as before
)

Короче говоря, не делайте этого. Используйте np.isnan