数値リストがあります:
myList = [1, 2, 3, 100, 5]
ここで、このリストを並べ替えて取得し[1, 2, 3, 5, 100]
ます。私が欲しいのは、元のリストの要素のインデックスを並べ替えられた順序、つまり[0, 1, 2, 4, 3]
値とインデックスの両方を返すMATLABのsort関数です。
数値リストがあります:
myList = [1, 2, 3, 100, 5]
ここで、このリストを並べ替えて取得し[1, 2, 3, 5, 100]
ます。私が欲しいのは、元のリストの要素のインデックスを並べ替えられた順序、つまり[0, 1, 2, 4, 3]
値とインデックスの両方を返すMATLABのsort関数です。
回答:
numpyを使用している場合は、argsort()関数を使用できます。
>>> import numpy
>>> numpy.argsort(myList)
array([0, 1, 2, 4, 3])
http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html
これは、配列またはリストをソートする引数を返します。
次のようなもの:
>>> myList = [1, 2, 3, 100, 5]
>>> [i[0] for i in sorted(enumerate(myList), key=lambda x:x[1])]
[0, 1, 2, 4, 3]
enumerate(myList)
(index、value)のタプルを含むリストを提供します:
[(0, 1), (1, 2), (2, 3), (3, 100), (4, 5)]
リストに渡しsorted
、ソートキーを抽出する関数を指定してリストをソートします(各タプルの2番目の要素です。それが何のlambda
ためにあるのかです。最後に、リストの内包を使用して、ソートされた各要素の元のインデックスが抽出され[i[0] for i in ...]
ます。
itemgetter(1)
ラムダ関数の代わりに使用できます
sorted_items, sorted_inds = zip(*sorted([(i,e) for i,e in enumerate(my_list)], key=itemgetter(1)))
x = [3,1,2]; numpy.argsort(x)
[1,2,0]が得られます。
myList = [1, 2, 3, 100, 5]
sorted(range(len(myList)),key=myList.__getitem__)
[0, 1, 2, 4, 3]
答えを更新enumerate
してitemgetter
:
sorted(enumerate(a), key=lambda x: x[1])
# [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]
リストを一緒に圧縮する:タプルの最初の要素がインデックスになり、2番目が値になります(次に、タプルの2番目の値を使用してソートしますx[1]
。xはタプルです)
またはモジュールitemgetter
から使用operator
`:
from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
私はこれらについてperfplot(私のプロジェクト)で簡単なパフォーマンスチェックを行いましたが、numpy(ログスケールに注意)以外は何も推奨するのは難しいことがわかりました。
プロットを再現するコード:
import perfplot
import numpy
def sorted_enumerate(seq):
return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]
def sorted_enumerate_key(seq):
return [x for x, y in sorted(enumerate(seq), key=lambda x: x[1])]
def sorted_range(seq):
return sorted(range(len(seq)), key=seq.__getitem__)
def numpy_argsort(x):
return numpy.argsort(x)
perfplot.save(
"argsort.png",
setup=lambda n: numpy.random.rand(n),
kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, numpy_argsort],
n_range=[2 ** k for k in range(15)],
xlabel="len(x)",
)
基本的にargsort
、外部ライブラリ(NumPyなど)を使用する場合、または依存関係のない純粋なPythonを維持する場合は、どの実装が必要かによって異なります。
あなたが自問する必要がある質問は、次のとおりです。
残念ながら、質問の例ではどちらも同じ結果が得られるため、何が望ましいのか明確にされていません。
>>> arr = np.array([1, 2, 3, 100, 5])
>>> np.argsort(np.argsort(arr))
array([0, 1, 2, 4, 3], dtype=int64)
>>> np.argsort(arr)
array([0, 1, 2, 4, 3], dtype=int64)
argsort
実装の選択NumPyを自由に使用できる場合は、関数numpy.argsort
またはメソッドを使用できますnumpy.ndarray.argsort
。
NumPyを使用しない実装は他のいくつかの回答ですでに言及されているので、ここでのベンチマークの回答に従って、最速のソリューションを要約します
def argsort(l):
return sorted(range(len(l)), key=l.__getitem__)
配列/リストをソートするインデックスを取得するargsort
には、配列またはリストを呼び出すだけです。ここではNumPyバージョンを使用していますが、Python実装でも同じ結果が得られるはずです
>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(arr)
array([1, 2, 0, 3], dtype=int64)
結果には、ソートされた配列を取得するために必要なインデックスが含まれています。
ソートされた配列は[1, 2, 3, 4]
argsorted 配列になるため、元の配列のこれらの要素のインデックスが含まれます。
1
インデックス1
にあるため、結果の最初の要素は1
です。2
指標である2
結果の2番目の要素であるので、元に2
。3
指標である0
結果の第三の要素であるので、元に0
。4
あり3
、元のインデックスにあるため、結果の最後の要素は3
です。この場合、argsort
2回適用する必要があります。
>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(np.argsort(arr))
array([2, 0, 1, 3], dtype=int64)
この場合 :
3
であり、これは3番目に大きい値であるため2
、ソートされた配列/リストにインデックスがあり、最初の要素は2
です。1
であり、これは最小値であるため0
、ソートされた配列/リストにインデックスがあり、2番目の要素はになり0
ます。2
であり、これは2番目に小さい値であるため1
、ソートされた配列/リストにインデックスがあり、3番目の要素は1
です。4
これが最大の値であるため3
、ソートされた配列/リストにインデックスがあり、最後の要素はになり3
ます。他の答えは間違っています。
argsort
1回実行するだけでは解決できません。たとえば、次のコード:
import numpy as np
x = [3,1,2]
np.argsort(x)
array([1, 2, 0], dtype=int64)
私たちが望むものではない利回り。
答えはargsort
2回実行する必要があります。
import numpy as np
x = [3,1,2]
np.argsort(np.argsort(x))
array([2, 0, 1], dtype=int64)
期待どおりに与えます。
x[2]
(3)最小の要素、およびx[1]
(1)最大の要素にします(整数を並べ替えると、最小値から最大値に並べ替えられるため)。また、OPの例では、単一のnp.argsort([1, 2, 3, 100, 5])
yieldsがarray([0, 1, 2, 4, 3])
、OPが必要とするインデックスのように見えます。
arr = [1,2,3,100, 5, 9] res = np.argsort(arr) print(res)
、[0 1 2 4 5 3]
どちらが間違っているかがわかります。
arr[res]
わかりarray([ 1, 2, 3, 5, 9, 100])
ません。
arr=[1,2,3,100, 5, 9]
、inds=[0,1,2,5,3,4]
これは要素を(次第に)順序付ける順序であるため、出力はになると期待しています。 3位と4位の9。その出力(inds
)を取得するには、argsort
前述のように2回実行する必要があります。
sort
言及していることを考えると、np.argsort
通常使用されるのと同じように、OPが他の機能を必要としていると考えます(arr[np.argsort[arr]]
最後のMATLABの例のように、ソートされた配列を取得するために使用できます)。あなたの答えはこのケース/質問に代わりに適用されます。