リストがどのようにソートされているかを測定する方法はありますか?


161

リストがどのようにソートされているかを測定する方法はありますか?

つまり、リストが並べ替えられているかどうか(ブール値)を知ることではなく、「並べ替え」の比率のようなもの、統計における相関係数のようなものです。

例えば、

  • リストのアイテムが昇順の場合、そのレートは1.0になります。

  • リストが降順でソートされている場合、そのレートは-1.0になります

  • リストがほとんど昇順でソートされている場合、そのレートは0.9または1に近い値になります。

  • リストがまったくソートされていない場合(ランダム)、そのレートは0に近い

練習のために、Scalaの小さなライブラリーを作成しています。ソート率は役に立つと思いますが、そのようなことについての情報は見つかりません。たぶん、コンセプトの適切な用語がわかりません。



4
これを使用して、リストをソートするための理想的なアルゴリズムを決定しますか?たとえば、0に近い値の場合、QuickSortが理想的ですが、スケールの両端(ほぼソートまたはほぼ逆ソート)の値では、QCがO(N ^ 2)にデボルブされるため、MergeSortははるかに高速になります。
ダレルホフマン

8
「sortessの比率」の+1
0x499602D2

1
@Fuhrmanatorアルゴリズムの確率的バージョンは、ソートの確率的推定に到達するためにソートを実行する必要はありません。ソートを実行する必要があるのは、正確な測定値を取得する場合のみです。
ティモシーシールド

1
皮肉ですが面白い最初の本能:リストを挿入ソートして所要時間を確認し、それをソート(現在ソートされている)リストにかかる所要時間とその逆と比較できます。
kqr 2013年

回答:


142

リストの反転数を数えるだけです。

反転

型の要素のシーケンスの反転はT、いくつかの順序に従った順序で表示されて配列要素のペアで<のセットでTの。

ウィキペディアから:

正式にはA(1), A(2), ..., A(n)、一連のn数値とします。
場合i < jA(i) > A(j)、そのペアが(i,j)呼び出された反転A

シーケンスの反転番号は、その並べ替えの一般的な指標の1つです。
正式には、反転数は反転数として定義されます。つまり、

定義

これらの定義をより明確にするために、シーケンスの例を検討してください9, 5, 7, 6。このシーケンスには、反転 (0,1), (0,2), (0,3), (2,3)反転番号があり 4ます。

0との間の値が必要な場合は1、反転数をで除算できますN choose 2

リストがどのようにソートされているかについてこのスコアを計算するアルゴリズムを実際に作成するには、2つの方法があります。

アプローチ1(確定的)

実行中に修正する反転の数を追跡するために、お気に入りのソートアルゴリズムを変更します。これは重要なことではなく、選択した並べ替えアルゴリズムに応じて実装が異なりますが、最初に行った並べ替えアルゴリズムよりも(複雑さの点で)費用がかからないアルゴリズムになります。

この方法をとる場合は、「スワップ」を数えるほど簡単ではないことに注意してください。たとえば、Mergesortは最悪のケースですがO(N log N)、降順で並べ替えられたリストで実行すると、すべてのN choose 2反転が修正されます。それO(N^2)O(N log N)操作で修正された反転です。したがって、一部の操作では、必然的に一度に複数の反転を修正する必要があります。実装には注意が必要です。注:これはO(N log N)複雑な方法でも実行できますが、注意が必要です。

関連:順列の「反転」数の計算

アプローチ2(確率的)

  • ランダムにサンプルのペア(i,j)、ここでi != j
  • 各ペアについて、list[min(i,j)] < list[max(i,j)](0または1)かどうかを決定します
  • これらの比較の平均を計算し、次に正規化します N choose 2

正確さの要件がない限り、私は個人的に確率論的アプローチを採用します。


(降順で並べ替え)から(昇順で並べ替えz')の間の値()が本当に必要な場合は、この数式を使用して、(昇順で並べ替え)と(降順で並べ替え)の間の()の上にある値をこの範囲に簡単にマッピングできます:-11z01

z' = -2 * z + 1

2
リストの並べ替えが(通常)O(n * logn)であり、反転を計算する素朴で自明な方法がO(n ^ 2)であることは、私にとって一種の魅力です。逆転の数を計算するためのより良いアルゴリズムがあるのだろうか?
Mark Bessey 2013年

5
このSOの質問には、興味深いアプローチがいくつかあります。stackoverflow.com/ questions / 6523712 / 基本的に、それらは、反転の数を把握するために配列をソートすることになります。
Mark Bessey 2013年

4
私は単純に、あなたが順不同である隣接するペアを数えることができると思った。しかし、それはひどく過小評価されます。12 3 1 2 3には隣接する反転が1つしかありませんが、より正確な測定によって50%反転されます。
Barmar 2013年

2
@Barmar私は、リスト1 2 3 1 2 3がsortaソート済みと見なされると思います;-)
scunliffe 2013年

2
@TimothyShields、まあ、いや、そうではありません。しかし、私は要点を説明しません。象徴的な傾向があまりない人にとってよりアクセスしやすい非公式の定義を追加するための単なる提案です。
Chris Calo 2013年

24

リスト(またはその他の順次構造)のソート方法の従来の測定は、反転の数です。

反転の数は、a <b AND b aのペア(a、b)stインデックスの数です<<。これらの目的の<<ために、特定の並べ替えに対して選択した順序関係を表します。

完全にソートされたリストには反転がなく、完全に反転したリストには反転の最大数があります。


5
技術的に5 4 3 2 1は、順序が指定されていないため完全にソートされますが、私は
知識を深め

7
@paxdiabloそれはの定義に依存し<ます。
Marcinは2013年

@paxdiablo、まあ、逆転の数から最も近い0またはまでの距離でソートを測定できn choose 2ます。
huon 2013年

17

実際の相関を使用できます。

ソートされたリストの各アイテムに、ゼロから始まる整数のランクを割り当てるとします。要素の位置インデックスとランクのグラフは、直線の点のようになります(位置とランクの間の相関は1.0)。

このデータの相関を計算できます。逆の並べ替えの場合、-1などになります。


1
申し訳ありませんが、整数の割り当て方法など、説明が不十分です。
Marcinは2013年

2
整数を割り当てるには、ソートされたリストが必要です。その後、それはアイテムの単なる列挙です。
Kaz

1
まさに私が提案しようとしていたこと。元のリストでのオブジェクトの位置と、並べ替えられたリストでのオブジェクトの位置との相関関係を決定します。悪いニュースは、相関ルーチンがおそらくO(n ^ 2)で実行されることです。良い知らせは、それらはおそらくあなたの環境にとって既製であることです。
Peter Webb 2013年

2
うん、ちょうどスピアマンのrhoのen.wikipedia.org/wiki/...
ルーカス

私は好奇心が強い...このアプローチは、反転数のカウントをスケーリングすることと同等ですか?
クレイトンスタンレー

4

素晴らしい答えがありました、そして私は完全性のために数学的な側面を追加したいと思います:

  • リストがソートされたリストとどの程度相関しているかを測定することで、リストがソートされた方法を測定できます。これを行うには、通常の相関とまったく同じであるランク相関(最もよく知られているのはスピアマンのもの)を使用できますが、アイテムのアナログ値の代わりにリスト内の要素のランクを使用します。

  • 相関係数のような多くの拡張が存在します(正確なソートの場合は+1、完全な逆の場合は-1)

  • これにより、ランダムなリストに対するこのメジャーの分布を知ることができる順列中心極限定理など、このメジャーの統計プロパティを使用できます。


3

数値リストの場合、反転カウントとは別に、ソートされた状態からの平均二乗距離が考えられます。

#! ruby
d = -> a { a.zip( a.sort ).map { |u, v| ( u - v ) ** 2 }.reduce( :+ ) ** 0.5 }

a = 8, 7, 3, 4, 10, 9, 6, 2, 5, 1
d.( a ) #=> 15.556
d.( a.sort ) #=> 0.0
d.( a.sort.reverse ) # => 18.166 is the worrst case

これが標準の相関関数の2乗だと思います。en.wikipedia.org/ wiki / Correlation_ratioを参照してください。また、数値以外のリストにも同様に適用されます。比較される2つの値は、2つのリスト内のオブジェクトの位置です。
Peter Webb 2013年

私はシンプルトンです。私は相関比が何であるかさえ知りません。そのWikipediaの記事の一番上を読むと、「統計的分散」、「標準偏差」、「変動」、「クラス間相関係数」について理解するように求められます。私はそれをすべて何度も学びました、そして何度か、私はそれを再び忘れました。私のこの実用的な答えでは、小学校で覚えているピタゴラスの定理で2つのベクトル間の距離を測定するだけです。
Boris Stitnicky 2013年

1

「最良の」方法はわかりませんが、単純な方法は、すべての要素をその後の要素と比較し、element2> element 1(またはテストするもの)の場合にカウンターをインクリメントしてから、総数で除算することです要素の。パーセンテージが表示されます。


1

比較をカウントして、それを比較の総数に分割します。これは簡単なPythonの例です。

my_list = [1,4,5,6,9,-1,5,3,55,11,12,13,14]

right_comparison_count = 0

for i in range(len(my_list)-1):
    if my_list[i] < my_list[i+1]: # Assume you want to it ascending order
        right_comparison_count += 1

if right_comparison_count == 0:
    result = -1
else:
    result = float(right_comparison_count) / float((len(my_list) - 1))

print result

0

このようなものはどうですか?

#!/usr/bin/python3

def sign(x, y):
   if x < y:
      return 1
   elif x > y:
      return -1
   else:
      return 0

def mean(list_):
   return float(sum(list_)) / float(len(list_))

def main():
   list_ = [ 1, 2, 3, 4, 6, 5, 7, 8 ]
   signs = []
   # this zip is pairing up element 0, 1, then 1, 2, then 2, 3, etc...
   for elem1, elem2 in zip(list_[:-1], list_[1:]):
      signs.append(sign(elem1, elem2))

   # This should print 1 for a sorted list, -1 for a list that is in reverse order
   # and 0 for a run of the same numbers, like all 4's
   print(mean(signs))

main()

2
これは隣接する反転のみをカウントします。他の回答を見ると、これでは不十分であることがわかります。
Konrad Rudolph

1
@KonradRudolph:この答えは、尋ねられた質問を満たしていると思います。他の回答がより包括的であるという事実は、これが不十分であることを意味しません。OPの要件によって異なります。
LarsH 2013年

0

リストを取得し、そのリスト内の値のランクを計算し、ランクのリストと、からまでの整数を含むY別のリストを呼び出すと、相関係数を計算することで、探しているソートの測定値を正確に取得できます、、二つのリストの間で。X1length(Y)r

r = \frac{\sum ^n _{i=1}(X_i - \bar{X})(Y_i - \bar{Y})}{\sqrt{\sum ^n _{i=1}(X_i - \bar{X})^2} \sqrt{\sum ^n _{i=1}(Y_i - \bar{Y})^2}} 

完全に並べ替えられたリストの場合r = 1.0、逆に並べ替えられたリストの場合r=-1.0、および、並べ替えのr度合いが異なるため、これらの制限の間で変化します。

アプリケーションに応じて、このアプローチで起こりうる問題は、リスト内の各アイテムのランクを計算することは、それを並べ替えることと同じであるため、O(n log n)操作であることです。


しかし、それは曲線の形状を無視しません。彼の配列がソートされているが、たとえば、指数関数的に増加する値が含まれている場合、相関を小さくして、1.0にしたいとします。
リーダニエルクロッカー

@LeeDanielCrocker:はい、それは良い点です。値のランクを取ることでこれに対処するために私の回答を修正しました。
Simon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.