2dのnumpy.ndarrayをソートするPythonicな方法

参考:
sort 2d numpy array lexicographically – StackOverflow
 
 
 

2Dのnumpy配列を普通にnumpy.sort()すると,行列方向にソートされる.

単に,行方向に属性(例えば日別),列方向に時系列(例えばその日の売上)であれば,column-wise(axis=1)のソートをすれば良いし,行構造についてソートしたければ,axis=0(row-wise)のソートをすれば良い.
(axis=-1:行列方向のソート,axis=0:row-wiseのソート,axis=1:column-wiseのソート)

import numpy as np

a = np.array([ [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) 
np.sort(a)

array([[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 0, 1]])

np.sort(a, axis=1)

array([[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 0, 1]])

np.sort(a, axis=0)

array([[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[1, 1, 1, 1]])

では,配列間の関係性に着目したければ(或いは他の配列をキーにしてソートしたい場合).

numpyには複数のkeyに基づいてソートするインデックスを返す関数として,numpy.lexsort(key)がある.sort orderはkey=(…, secodary, primary)の順番で,1列目,2列目,3列目,4列目をそれぞれkeyにみたてれば,降順(ソートの優先順:列4,3,2,1)の場合,

a[np.lexsort(a.T)]

array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])

昇順(ソートの優先順:列1,2,3,4)の場合,

a[np.lexsort(np.rot90(a))]

array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 0]])
 
 
 

後,僕がよくやる方法としては,convolutionを取ると云う基本的な発想だけど,

a[np.argsort(np.dot(a, np.arange(1, a.shape[1]+1)))]

array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])

a[np.argsort(np.dot(a, np.arange(a.shape[1], 0, -1)))]

array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 0]])

%timeit a[np.lexsort(np.rot90(a))]
%timeit a[np.argsort(np.dot(a, np.arange(a.shape[1], 0, -1)))]
%timeit a[np.lexsort(a.T)]
%timeit a[np.argsort(np.dot(a, np.arange(1, a.shape[1]+1)))]

38.3 µs ± 4.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
18.4 µs ± 1.93 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
9.94 µs ± 1.04 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
17.1 µs ± 793 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

悪くないと思う.というか,

b = np.eye(10, 10)
print('------ 10 x 10 ------')
%timeit b[np.lexsort(np.rot90(b))]
%timeit b[np.argsort(np.dot(b, np.arange(b.shape[1], 0, -1)))]
%timeit b[np.lexsort(b.T)]
%timeit b[np.argsort(np.dot(b, np.arange(1, b.shape[1]+1)))]

b = np.eye(100, 100)
print('------ 100 x 100 ------')
%timeit b[np.lexsort(np.rot90(b))]
%timeit b[np.argsort(np.dot(b, np.arange(b.shape[1], 0, -1)))]
%timeit b[np.lexsort(b.T)]
%timeit b[np.argsort(np.dot(b, np.arange(1, b.shape[1]+1)))]

b = np.eye(1000, 1000)
print('------ 1000 x 1000 ------')
%timeit b[np.lexsort(np.rot90(b))]
%timeit b[np.argsort(np.dot(b, np.arange(b.shape[1], 0, -1)))]
%timeit b[np.lexsort(b.T)]
%timeit b[np.argsort(np.dot(b, np.arange(1, b.shape[1]+1)))]

—— 10 x 10 ——
33.3 µs ± 1.83 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
16.2 µs ± 408 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
11.3 µs ± 520 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
16.4 µs ± 1.04 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
—— 100 x 100 ——
252 µs ± 29.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
37.5 µs ± 970 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
201 µs ± 2.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
37.1 µs ± 511 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
—— 1000 x 1000 ——
32.5 ms ± 1.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
6.15 ms ± 78.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
32.4 ms ± 377 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
6.42 ms ± 244 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

うまくできるなら,その方が速い.
 
 
 
関連:

任意の要素をシャッフル

任意の要素だけソートしてそれ以外は元の位置を維持

トポロジカルソート

Pythonでソート(sorted()/list.sort(), numpy.sort())

広告
カテゴリー: 未分類 パーマリンク

2dのnumpy.ndarrayをソートするPythonicな方法 への1件のフィードバック

  1. ピンバック: Python heapq : How do I sort the heap using nth element of the list of lists? | 粉末@それは風のように (日記)

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中