Python: Сортировать функцию разрывы в присутствии NAN

StackOverflow https://stackoverflow.com/questions/4240050

  •  27-09-2019
  •  | 
  •  

Вопрос

sorted([2, float('nan'), 1]) возвращается [2, nan, 1]

(По крайней мере, на реализации ActiveState Python 3.1.)

я понимаю nan Это странный объект, поэтому я не был удивлен, если он появится в случайных местах в результате своего рода. Но он также испортил сортировку для ненанских чисел в контейнере, который действительно неожиданна.

Я спросил А. Похожие вопросы о max, и основываясь на том, что я понимаю, почему sort Работает так. Но следует ли это считаться ошибкой?

Документация только говорит «Верните новый отсортированный список [...]», не указав никаких деталей.

Редактировать: Я сейчас согласен, что это не нарушает стандарт IEEE. Тем не менее, это ошибка из любого общего смысла обзора, я думаю. Даже Microsoft, которая не известна, что часто признает свои ошибки, признал этот как ошибку, и исправил его в последней версии: http://connect.microsoft.com/visualstudio/feedback/details/363379/bug-in-list-double-sort-in-list-which-contains-Double-Nan.

Во всяком случае, я оказался после ответа @ Хачика:

sorted(list_, key = lambda x : float('-inf') if math.isnan(x) else x)

Я подозреваю, что это приводит к попаданию производительности по сравнению с языком, делающим это по умолчанию, но, по крайней мере, он работает (забавите любые ошибки, которые я ввел).

Это было полезно?

Решение

Предыдущие ответы полезны, но, возможно, не ясно относительно корня проблемы.

На любом языке сортировка применяет данный приказ, определяемый функцией сравнения или каким-либо другим способом, по домену входных значений. Например, менее, ака operator <, Можно использовать во все возможности и только тогда, когда меньше, чем определяет подходящее упорядочение по входным значениям.

Но это конкретно не соответствует ценностям с плавающей запятой и меньше, чем: «NAN неупорядован: он не равен, больше или меньше всего, включая себя». (Очистить прозу в Руководстве GNU C, Но относится ко всем современному IEEE754 основанный плавающая точка)

Таким образом, возможные решения:

  1. Сначала удалите Nans, сделав входной домен, хорошо определенный через <(или другую функцию сортировки)
  2. Определите пользовательскую функцию сравнения (предикат AKA), которая определяет упорядочение для NAN, например, меньше, чем любое число или больше, чем любое число.

Любой подход можно использовать на любом языке.

Практически, учитывая Python, я бы предпочел удалить Nans, если вам либо не заботится о самых быстрых производительности, либо при удалении Nans - это желаемое поведение в контексте.

В противном случае вы можете использовать подходящую функцию предикатов через «CMP» в более старых версиях Python или через это и functools.cmp_to_key(). Отказ Последнее немного более неловко, естественно, чем сначала удаляя назы. И уход потребуется избегать хуже производительность при определении этой функции предиката.

Другие советы

Проблема в том, что нет правильного порядка, если список содержит NAN, поскольку последовательность A1, A2, A3, ..., AN отсортирована, если A1 <= A2 <= A3 <= ... <= An. Если какое-либо из этих значений является NAN, то сортированные разрывы свойства, поскольку для всех A, A <= Nan и NAN <= A - обои и ложные.

Я не уверен в ошибке, но обходной путь может быть следующим:

sorted(
    (2, 1, float('nan')),
    lambda x,y: x is float('nan') and -1 
                or (y is float('nan') and 1
                or cmp(x,y)))

который приводит к:

('nan', 1, 2)

Или удалить nanS перед сортировкой или чем-то еще.

IEEE754 - это стандарт, который определяет операции с плавающей запятой в этом случае. Этот стандарт определяет операцию сравнения операндов, по крайней мере, одной из которых является NAN, чтобы быть ошибкой. Следовательно, это не ошибка. Вам нужно разобраться с Nans, прежде чем работать в вашем массиве.

Предполагая, что вы хотите сохранить Nans и заказывать их как самые низкие «ценности», вот обходной путь работает как с не уникальный нан, Уникальный NAN NAN, численность а также не численно объекты:

def is_nan(x):
    return (x is np.nan or x != x)

list_ = [2, float('nan'), 'z', 1, 'a', np.nan, 4, float('nan')]
sorted(list_, key = lambda x : float('-inf') if is_nan(x) else x)
# [nan, nan, nan, 1, 2, 4, 'a', 'z']
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top