47

sorted([2, float('nan'), 1])戻り値[2, nan, 1]

(少なくともActivestate Python 3.1の実装では。)

奇妙なオブジェクトだと理解しnanているので、ソート結果のランダムな場所に表示されても驚かないでしょう。しかし、それはまた、コンテナ内の非nan番号のソートを台無しにします。これは、実際には予想外のことです。

について関連する質問maxしましたが、それに基づいて、なぜsortこのように機能するのかを理解しています。しかし、これはバグと見なされるべきですか?

ドキュメントには、詳細を指定せずに「新しいソート済みリストを返す[...]」とだけ書かれています。

編集:これがIEEE標準に違反していないことに同意します。ただ、常識的にはバグだと思います。間違いを頻繁に認めることが知られていないMicrosoftでさえ、これをバグとして認識し、最新バージョンで修正しました:http: //connect.microsoft.com/VisualStudio/feedback/details/363379/bug- in-list-double-sort-in-list-which-contains-double-nan

とにかく、私は@khachikの答えに従うことになりました:

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

デフォルトでそれを実行している言語と比較して、パフォーマンスが低下する可能性がありますが、少なくとも機能します(私が導入したバグを除いて)。

4

8 に答える 8

17

以前の回答は役に立ちますが、問題の根本についてはおそらく明確ではありません。

どの言語でも、並べ替えは、入力値のドメインに対して、比較関数またはその他の方法で定義された特定の順序付けを適用します。たとえば、less-than akaoperator <,は、less than が入力値に対して適切な順序付けを定義している場合に限り、全体で使用できます。

しかし、これは特に浮動小数点値と未満には当てはまりません。( GNU C マニュアルからの明確な散文ですが、すべての最新IEEE754ベースの浮動小数点に適用されます)

したがって、可能な解決策は次のとおりです。

  1. 最初に NaN を削除し、< (または使用されている他の並べ替え関数) によって入力ドメインを適切に定義します。
  2. 任意の数より小さい、または任意の数より大きいなど、NaN の順序付けを定義するカスタム比較関数 (別名述語) を定義します。

どちらのアプローチも、どの言語でも使用できます。

実際には、Python を考えると、最速のパフォーマンスをあまり気にしない場合、またはコンテキストで NaN を削除することが望ましい動作である場合は、NaN を削除することをお勧めします。

それ以外の場合は、古い python バージョンの「cmp」を介して、または this および functools.cmp_to_key(). 後者は、当然のことながら、最初に NaN を削除するよりも少し面倒です。また、この述語関数を定義するときは、パフォーマンスが低下ないように注意する必要があります。

于 2011-08-23T17:35:20.177 に答える
10

バグについてはわかりませんが、回避策は次のとおりです。

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)

nanまたは、並べ替えなどの前に sを削除します。

于 2010-11-21T20:12:55.073 に答える
8

問題は、シーケンスが。の場合にソートされるため、がlist含まれている場合は正しい順序がないことです。これらの値のいずれかがaの場合、すべてが両方であるため、ソートされたプロパティは壊れます。NANa1, a2, a3, ..., ana1 <= a2 <= a3 <= ... <= anNANa, a <= NAN and NAN <= afalse

于 2010-11-21T21:46:04.983 に答える
5

IEEE754 は、この場合の浮動小数点演算を定義する標準です。この規格では、少なくとも 1 つが NaN であるオペランドの比較演算をエラーと定義しています。したがって、これはバグではありません。配列を操作する前に NaN を処理する必要があります。

于 2010-11-21T20:10:28.090 に答える
0

回復力のある並べ替えには、2 つの項目の比較と、少ない、等しい、大きいという戻り値が含まれます。

cmp(a,b)が「大きい」場合は、 cmp(b,a)「小さい」必要があります。

cmp(a,b)が「ゼロ」の場合、「ゼロ」でcmp(b,a)なければなりません。

これまでの回答に欠けているfloatのは、両方ともNANである 2 を比較し、上記のプロパティを保持する場合です。2 つの NAN は、ペイロードの一貫した解釈に基づいて等しいか、またはおそらくそれに基づいて比較する必要があります。

すべての NAN > +inf を配置するための代替比較アルゴリズム

if isnan(a)
  if isnan(b)
    return 0 (or maybe compare payloads/bit patterns)
  return 1
if isnan(b) return 1
if a > b return 1
if a < b return -1
return 0
于 2021-03-19T10:49:16.113 に答える
0

NA標準に関係なく、float と値のユーザー定義の順序付けが役立つ場合が多くあります。たとえば、私は株式の返品を並べ替えていて、NA最後に最高から最低を求めていました (それらは無関係だったため)。4通りの組み合わせが可能

  1. float 値の昇順、NA値は最後
  2. float 値の昇順、NA最初に値
  3. float 値の降順、NA値が最後
  4. float 値の降順、NA最初に値

NA値を条件付きで置き換えることにより、すべてのシナリオをカバーする関数を次に示します。+/- inf

import math 

def sort_with_na(x, reverse=False, na_last=True):
    """Intelligently sort iterable with NA values

    For reliable behavior with NA values, we should change the NAs to +/- inf
    to guarantee their order rather than relying on the built-in
    ``sorted(reverse=True)`` which will have no effect. To use the ``reverse``
    parameter or other kwargs, use functools.partial in your lambda i.e.

        sorted(iterable, key=partial(sort_with_na, reverse=True, na_last=False))

    :param x: Element to be sorted
    :param bool na_last: Whether NA values should come last or first
    :param bool reverse: Return ascending if ``False`` else descending
    :return bool:
    """
    if not math.isnan(x):
        return -x if reverse else x
    else:
        return float('inf') if na_last else float('-inf')

4つの組み合わせのそれぞれをテストする

from functools import partial

a = [2, float('nan'), 1]
sorted(a, key=sort_with_na)                                         # Default
sorted(a, key=partial(sort_with_na, reverse=False, na_last=True))   # Ascend, NA last
sorted(a, key=partial(sort_with_na, reverse=False, na_last=False))  # Ascend, NA first
sorted(a, key=partial(sort_with_na, reverse=True, na_last=True))    # Descend, NA last
sorted(a, key=partial(sort_with_na, reverse=True, na_last=False))   # Descend, NA first
于 2020-11-21T16:09:45.373 に答える