NumPyの配列をn列目でソートするにはどうすればよいですか?
例えば、
a = array([[9, 2, 3],
[4, 5, 6],
[7, 0, 5]])
戻ってくるように、2列目で行を並べ替えたいのですが。
array([[7, 0, 5],
[9, 2, 3],
[4, 5, 6]])
@ steve が実際に最もエレガントな方法です。
「正しい」方法については、 numpy.ndarray.sort のorderキーワード引数を参照してください。
ただし、配列はフィールドを持つ配列(構造化配列)として表示する必要があります。
あなたが最初にフィールドであなたの配列を定義しなかったならば、「正しい」方法はかなり醜いです...
簡単な例として、並べ替えてコピーを返すには、次のようにします。
In [1]: import numpy as np
In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])
In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
その場でソートするには:
In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None
In [7]: a
Out[7]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
私が知っている限りでは、@ Steveは本当にそれを行うための最もエレガントな方法です...
このメソッドの唯一の利点は、 "order"引数が検索を順序付けるためのフィールドのリストであるということです。たとえば、order = ['f1'、 'f2'、 'f0']を指定すると、2列目、3列目、1列目の順に並べ替えることができます。
私はこれがうまくいくと思います:a[a[:,1].argsort()]
これはa
の2列目を示し、それに基づいてソートします。
Steve Tjoaの方法に従って、マージソートのような安定したソートを使用し、インデックスを最下位から最上位の列にソートすることで、複数の列をソートできます。
a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]
これは、列0、次に1、次に2の順にソートされます。
Python documentation wiki から、私はあなたができると思います:
a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]);
a = sorted(a, key=lambda a_entry: a_entry[1])
print a
出力は以下のとおりです。
[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]
誰かが自分のプログラムの重要な部分でソートを利用したい場合は、さまざまな提案に対するパフォーマンスの比較を次に示します。
import numpy as np
table = np.random.Rand(5000, 10)
%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop
%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop
import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop
ですから、 argsort でインデックスを付けるのが一番早い方法です...
NumPyメーリングリスト から、もう一つの解決策があります:
>>> a
array([[1, 2],
[0, 0],
[1, 0],
[0, 2],
[2, 1],
[1, 0],
[1, 0],
[0, 0],
[1, 0],
[2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
[0, 0],
[0, 2],
[1, 0],
[1, 0],
[1, 0],
[1, 0],
[1, 2],
[2, 1],
[2, 2]])
私は同様の問題を抱えていました。
私の問題:
SVDを計算したいので、 固有値 を降順に並べ替える必要があります。しかし、私は固有値と固有ベクトルの間の写像を保ちたいのです。私の固有値は最初の行にあり、その下の対応する固有ベクトルは同じ列にあります。
そのため、2次元配列を最初の行で降順に列方向にソートしたいと思います。
私の解決策
a = a[::, a[0,].argsort()[::-1]]
それで、これはどのように機能しますか?
a[0,]
は、並べ替えたい最初の行です。
今度はargsortを使ってインデックスの順序を取得します。
降順が必要なので[::-1]
を使用します。
最後にa[::, ...]
を使用して、正しい順序で列を含むビューを取得します。
もう少し複雑なlexsort
の例 - 1列目で降順、2番目で昇順。 lexsort
のコツは、行順(つまり.T
)でソートし、最後に優先することです。
In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]:
array([[1, 2, 1],
[3, 1, 2],
[1, 1, 3],
[2, 3, 4],
[3, 2, 5],
[2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]:
array([[3, 1, 2],
[3, 2, 5],
[2, 1, 6],
[2, 3, 4],
[1, 1, 3],
[1, 2, 1]])
これは、すべての列を考慮した別の解決策です( J.J の答えのより簡潔な方法)。
ar=np.array([[0, 0, 0, 1],
[1, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[0, 0, 1, 0],
[1, 1, 0, 0]])
Lexsortで並べ替え
ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]
出力:
array([[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]])