Предположим, у меня есть следующий простой словарь:
dictionary = {'a':3, 'b':4, 'c':float('NaN')}
Если я использую функцию max() для возврата ключа с максимальным значением...
key_maxvalue = max(dictionary, key=dictionary.get)
print(key_maxvalue)
... python выводит это:
b
Однако, когда я переставляю значения ключей "a" и "c"...
dictionary = {'a':float('NaN'), 'b':4, 'c':3}
key_maxvalue = max(dictionary, key=dictionary.get)
print(key_maxvalue)
... Я получаю неожиданный результат:
a
Я ожидал, что python выведет «b», так как этот ключ по-прежнему имеет максимальное значение в словаре. Почему изменение порядка значений изменило вывод функции max()? Кроме того, как я могу предотвратить это (неожиданное) событие?
Ответ: «Не используйте NaN». Смысл NaN в том, что это не число, и на него нельзя полагаться, что оно действует как число каким-либо рациональным образом. Вы видите, что сравнения с NaN не коммутативны.
Обратите внимание на это:
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x = float('NaN')
>>> 1 < x
False
>>> x < 1
False
>>>
Любое сравнение с NaN ложно. Это делает их сортировку неопределенной.
Смотрите также обсуждение здесь github.com/python/cpython/issues/80276
Можете ли вы продемонстрировать, что они не транзитивны? Транзитивность означает, что xRy и yRz влекут за собой xRz. Какие x, y, z, R с участием NaN нарушают это?
Вы правы, я должен был сказать "коммутативный".
Я думаю, вы можете рассматривать отношение как операцию, но даже тогда сравнения с «нормальными» числами уже не коммутативны. Например, 1 < 2
не равно 2 < 1
.
Если бы вы написали свою собственную функцию, она могла бы выглядеть так:
def max(nums):
largest = nums[0]
for item in nums:
if item > largest:
largest = item
return largest
Проблема в этом сравнении item > largest
. Посмотрите, что происходит, когда вы сравниваете число с np.nan
.
Ввод: np.nan > 4
Выход: False
Ввод: 4 > np.nan
Выход: False
Любое сравнение со знаком NaN
будет ложным. Если max
работает как наша написанная функция, то происходит то, что происходит в обоих ваших случаях. Это не больше 4, поэтому b
по-прежнему является максимальным. Однако, когда по умолчанию используется a
во втором случае, никакое другое число не больше NaN
, поэтому a
остается максимальным.
Также см. <lwn.net/Articles/869231>