numpy - 要素間の特定の一致に基づいて配列行を削除する

okwaves2024-01-25  10

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

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。