私はPythonリスト/ 1D numpy配列で重複をコンパクトに表現しようとしています。例えば、我々はPythonリストで重複を効率的に処理する
x = np.array([1, 0, 0, 3, 3, 0])
この配列は、特定のクラスタ内のすべての重複がx[group_id==<some_id>]
で発見されたように、
group_id = np.array([0, 1, 1, 2, 2, 1])
で表すことができ、いくつかの重複要素を持っている持っていると言います。
重複ペアのリストを効率的に選別して計算することができる、
s_idx = np.argsort(x)
diff_idx = np.nonzero(x[s_idx[:-1]] == x[s_idx[1:]])[0]
ここ一対s_idx[diff_idx]
< - >s_idx[diff_idx+1]
は重複している元の配列内のインデックスに対応します。 (ここではarray([1, 2, 3])
< - >array([2, 5, 4])
)。
しかし、大きな配列サイズ(N > 10⁶
)のこのリンケージ情報からcluster_id
を効率的に計算する方法がわかりません。
編集:@Chris_Randsにより示唆されるように、これは確かにitertools.groupby
で行うことができ、
import numpy as np
import itertools
def get_group_id(x):
group_id = np.zeros(x.shape, dtype='int')
for i, j in itertools.groupby(x):
j_el = next(j)
group_id[x==j_el] = i
return group_id
しかしスケーリングがはO(n^2)ように見える、これはないだろう(N > 10⁶
)、
for N in [50000, 100000, 200000]:
%time _ = get_group_id(np.random.randint(0, N, size=N))
CPU times: total: 1.53 s
CPU times: total: 5.83 s
CPU times: total: 23.9 s
私はユースケースにスケールしましたN=200000
の重複ペアの計算が比較でわずか6.44μsで済むので、より効率的です。
あなたは 'itertools.groupby'見てきましたか? –
'np.bincount'を使うのはどうですか? – fstab
@Chris_Rands提案してくれてありがとう、私はちょうど、上記の私の編集を参照してください。 – rth