6 列の整数配列の小さなサンプルを考えてみましょう。
import numpy as np
J = np.array([[1, 3, 1, 3, 2, 5],
[2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2],
[0, 3, 0, 3, 0, 3],
[2, 2, 3, 3, 2, 3],
[4, 3, 4, 3, 3, 4])
J から削除したい:
a) 要素の最初と 2 番目のペアが完全に一致するすべての行
(これにより、[1,3, 1,3, 2,5] のような行が削除されます)
b) 要素の 2 番目と 3 番目のペアが完全に一致するすべての行
(これにより、[1,7, 2,5, 2,5] のような行が削除されます)
他のペア間の一致は問題ありません。
以下に解決策がありますが、これは 2 つのステップで処理されます。もっと直接的で、クリーンで、より簡単に拡張可能なアプローチがあれば、非常に興味があります。
K = J[~(np.logical_and(J[:,0] == J[:,2], J[:,1] == J[:,3]))]
L = K[~(np.logical_and(K[:,2] == J[:,4], K[:,3] == K[:,5]))]
K は J から 1 行目、5 行目、7 行目を削除し、残ります
K = [[2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
L は K から 2 行目を削除し、最終結果が得られます。
L = [[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
この問題から学んでいるから、効率的な解決策を期待しています。うーん、これらのアイデアを 8 列の配列に拡張する必要があります。
1 番目と 2 番目のペア、2 番目と 3 番目のペア、3 番目と 4 番目のペアの間で完全に一致する行を削除します。
------------------------
隣接するペアが等しいかどうかをチェックしているため、3D 再整形データの差分処理は、よりクリーンなベクトル化データを実現する 1 つの方法であると思われます -
# a is input array
In [117]: b = a.reshape(a.shape[0],-1,2)
In [118]: a[~(np.diff(b,axis=1)==0).all(2).any(1)]
Out[118]:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
パフォーマンスを重視する場合は、差分をスキップして、スライスされた等価性を追求してください -
In [142]: a[~(b[:,:-1] == b[:,1:]).all(2).any(1)]
Out[142]:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])
一般番号コル
一般的な番号でも同様に拡張します。列数 -
In [156]: a
Out[156]:
array([[1, 3, 1, 3, 2, 5, 1, 3, 1, 3, 2, 5],
[2, 6, 3, 4, 2, 6, 2, 6, 3, 4, 2, 6],
[1, 7, 2, 5, 2, 5, 1, 7, 2, 5, 2, 5],
[4, 2, 8, 3, 8, 2, 4, 2, 8, 3, 8, 2],
[0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3],
[2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 2, 3],
[4, 3, 4, 3, 3, 4, 4, 3, 4, 3, 3, 4]])
In [158]: b = a.reshape(a.shape[0],-1,2)
In [159]: a[~(b[:,:-1] == b[:,1:]).all(2).any(1)]
Out[159]:
array([[4, 2, 8, 3, 8, 2, 4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3, 2, 2, 3, 3, 2, 3]])
もちろん、列の数がペアリングを可能にすると想定しています。
6
おそらく、axis=2 と axis=1 の代わりに、一貫して axis=-1 を使用する方がよいでしょう。
– マティーン・ウルハク
2020 年 9 月 4 日 19:05
@MateenUlhaq より正確です。ディムが高くなると、より多くのコロンを追加することになるため、とにかく。
– ディバカール
2020 年 9 月 4 日 19:07
特に 2 番目のソリューションは非常に効率的です。比較的初心者なので、それを 8 列のケースに適用したところを示してもらえますか? (例: 1 番目と 2 番目の一致するペア、2 番目と 3 番目の一致するペア、3 番目と 4 番目の一致するペアを削除します)
– user109387
2020 年 9 月 4 日 19:43
@user109387 任意の数の列で機能しますコードの変更を監視してください。それとも、サンプルケースの実行としてそれを見せてほしいですか?
– ディバカール
2020 年 9 月 4 日 19:50
@user109387 追加されました。
– ディバカール
2020 年 9 月 4 日 20:00
------------------------
あなたが持っているものは非常に合理的です。私なら次のように書きます。
def eliminate_pairs(x: np.ndarray) -> np.ndarray:
first_second = (x[:, 0] == x[:, 2]) & (x[:, 1] == x[:, 3])
second_third = (x[:, 1] == x[:, 3]) & (x[:, 2] == x[:, 4])
return x[~(first_second | second_third)]
ドモルガンの定理を適用して消去することもできます。これは追加の操作ではありませんが、明確さほど重要ではありません。
2
これが、たとえば、1 番目から 2 番目、2 番目から 3 番目、3 番目から 4 番目がある 8 列の配列に拡張された場合、Return ステートメントはどのように処理しますか?
– user109387
2020 年 9 月 4 日 19:10
@user109387 その時点で、私ならこうしますDivakar の回答に似たものに切り替えて、再形成後にスライスを介して比較するだけです (「ペアリング」構造を強制するために必要です)。
– マティーン・ウルハク
2020 年 9 月 4 日 19:11
------------------------
ループを試してみましょう:
mask = False
for i in range(0,3,2):
mask = (J[:,i:i+2]==J[:,i+2:i+4]).all(1) | mask
J[~mask]
出力:
array([[2, 6, 3, 4, 2, 6],
[4, 2, 8, 3, 8, 2],
[2, 2, 3, 3, 2, 3]])