列によるNumPyの配列の並べ替え


336

NumPyの配列をn番目の列でソートするにはどうすればよいですか?

例えば、

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

行を2番目の列で並べ替えて、次のようにしたいと思います。

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])

8
これはnp.sort(a, axis=0)、与えられた行列に対して十分な解決策になるので、本当に悪い例です。より良い例を含む編集を提案しましたが、拒否されましたが、実際には質問の方がはるかに明確です。例はa = numpy.array([[1, 2, 3], [6, 5, 2], [3, 1, 1]])、希望する出力のようなものである必要がありますarray([[3, 1, 1], [1, 2, 3], [6, 5, 2]])
David

29
デビッド、あなたは質問の要点を理解していません。彼は各行内の順序を同じに保ちたいと考えています。
marcorossi

@marcorossi私はポイントを獲得しましたが、例が非常に不適切に定式化されたのは、私が言ったように、複数の可能な回答があったためです(しかし、それはOPの要求を満たしませんでした)。私のコメントに基づく後の編集は確かに承認されました(ただし、私の鉱山は却下されました)。だから今はすべてうまくいきます。
David

回答:


140

@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番目の列の順に並べ替えることができます。


3
私のnumpy 1.6.1rc1では、それが発生しますValueError: new type not compatible with array.
Clippit

9
「正しい」方法をあまり醜くないようにする機能要求を提出することは理にかなっていますか?
エンドリス2013

4
配列の値が次の場合はどうなりますfloatか?何か変更すべきですか?
Marco

1
また、ハイブリッドタイプの場合、a = np.array([['a',1,2,3],['b',4,5,6],['c',0,0,1]])どのようなアプローチに従う必要がありますか?
ePascoalは、

10
この方法のSteveに対する主な利点の1つは、非常に大きな配列を適切に並べ替えることができることです。十分に大きな配列の場合、によって返されるインデックスはnp.argsort大量のメモリを占有する可能性があり、その上、配列を使用したインデックス付けによって、ソートされる配列のコピーも生成されます。
ali_m 2015

735

私はこれがうまくいくと思います: a[a[:,1].argsort()]

これは、2番目の列を示し、aそれに基づいてソートされます。


2
これは明確ではありません1、ここには何がありますか?ソートするインデックス?
orezvani

29
[:,1]の2列目を示しますa
スティーブTjoa 14

60
逆のソートが必要な場合は、これを次のように変更しますa[a[:,1].argsort()[::-1]]
Steven C. Howell

1
シンプルに見えて機能します!それよりも速いnp.sortですか?
ヴァーツラフPavlikの

14
私はこれが読みやすいと思います:ind = np.argsort( a[:,1] ); a = a[ind]
ポピー2017

32

マージソートのような安定したソートを使用し、最下位のカラムから最上位のカラムへとインデックスをソートすることにより、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の順にソートされます。


4
First Sortが安定している必要がないのはなぜですか?
リトルボビーテーブル

10
良い質問-安定とは、同点の場合は元の順序を維持し、ソートされていないファイルの元の順序は無関係であることを意味します。
JJ

これは本当に超重要なポイントのようです。静かにソートしないリストがあると悪いでしょう。
不器用な猫

20

Pythonドキュメントの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]]]

20
このソリューションでは、NumPy配列の代わりにリストを取得するため、これは常に便利であるとは限りません(より多くのメモリを必要とする、おそらく遅いなど)。
エリックOレビゴット2009

18

プログラムの重要な部分でソートを利用したい場合は、さまざまな提案のパフォーマンス比較を以下に示します。

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を使用したインデックス付けは、これまでで最も速い方法のようです...



5

同様の問題がありました。

私の問題:

SVDを計算し、固有値を降順に並べ替える必要があります。しかし、固有値と固有ベクトルの間のマッピングを維持したいと思います。私の固有値は最初の行にあり、その下の対応する固有ベクトルは同じ列にありました。

したがって、2次元配列を最初の行で列ごとに降順に並べ替えたいと思います。

私の解決策

a = a[::, a[0,].argsort()[::-1]]

これはどのように機能するのでしょうか?

a[0,] ソートしたい最初の行です。

次に、argsortを使用してインデックスの順序を取得します。

[::-1]降順が必要なので使用します。

最後にa[::, ...]、列を正しい順序で表示するために使用します。


1

もう少し複雑なlexsort例-1番目の列で降順、2番目の列で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]])

0

これは、すべての列を考慮した別の解決策です(JJの回答のよりコンパクトな方法)。

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]])

0

単に並べ替えを使用して、並べ替えに使用する列番号を使用します。

a = np.array([1,1], [1,-1], [-1,1], [-1,-1]])
print (a)
a=a.tolist() 
a = np.array(sorted(a, key=lambda a_entry: a_entry[0]))
print (a)

0

それは古い質問ですが、これを2次元よりも高い配列に一般化する必要がある場合は、簡単に一般化できる解決策を次に示します。

np.einsum('ij->ij', a[a[:,1].argsort(),:])

これは2次元にとってはやり過ぎであり、a[a[:,1].argsort()]@ steveの回答ごとに十分ですが、その回答をより高い次元に一般化することはできません。この質問で3D配列の例を見つけることができます

出力:

[[7 0 5]
 [9 2 3]
 [4 5 6]]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.