1. ホーム
  2. python

[解決済み] argsortを降順で使用することは可能ですか?

2022-01-28 12:57:29

質問

次のコードを考えてください。

avgDists = np.array([1, 8, 6, 9, 4])
ids = avgDists.argsort()[:n]

これは n 最小の要素です。この同じ argsort のインデックスを降順で取得します。 n 最も高い要素?

解決方法は?

配列を否定すると、最下位の要素が最上位の要素になり、その逆もまた然りです。 したがって n 最も高い要素は

(-avgDists).argsort()[:n]

で述べたような、もう一つの推論方法です。 コメント は、大きな要素が来ていることを観察することです。 最後 を指定します。 そこで、argsortの最後尾から読み込んで n が最も高い要素です。

avgDists.argsort()[::-1][:n]

どちらの方式も O(n log n) を使用するため、時間の複雑さでは argsort の呼び出しが支配的な項です。 しかし、2番目のアプローチには素晴らしい利点があります。 O(n) 配列の否定を O(1) スライスです。 ループ内で小さな配列を扱う場合は、否定を避けることでパフォーマンスが向上する可能性があります。また、巨大な配列を扱う場合は、否定が配列全体のコピーを作成するため、メモリ使用量を節約できます。

これらの方法は、常に同等の結果を与えるわけではないことに注意してください:安定したソート実装が argsort キーワード引数で kind='mergesort' の場合、最初の戦略はソートの安定性を保ちますが、2番目の戦略は安定性を壊します(つまり、同じ項目の位置が逆になる)。

タイミングの例

100 個の浮動小数点数の小さな配列と長さ 30 のテールを使用した場合、ビューメソッドは約 15% 速くなりました。

>>> avgDists = np.random.rand(100)
>>> n = 30
>>> timeit (-avgDists).argsort()[:n]
1.93 µs ± 6.68 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
1.64 µs ± 3.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
1.64 µs ± 3.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

大きな配列では、argsortが優位であり、大きなタイミングの差はない

>>> avgDists = np.random.rand(1000)
>>> n = 300
>>> timeit (-avgDists).argsort()[:n]
21.9 µs ± 51.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
21.7 µs ± 33.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
21.9 µs ± 37.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

ご注意ください nedimからのコメント は正しくありません。なぜなら、これらの操作は両方とも、配列のビューを異なる方法でストライドしているだけで、実際にデータをコピーしているわけではないためです。