有效地处理Python列表中的重复项

时间:2016-10-18 15:22:35

标签: python algorithm numpy grouping graph-algorithm

我希望在Python list / 1D numpy数组中紧凑地表示重复项。例如,假设我们有

 x = np.array([1, 0, 0, 3, 3, 0])

这个数组有几个重复的元素,可以用

表示
 group_id = np.array([0, 1, 1, 2, 2, 1])

以便在x[group_id==<some_id>]找到给定群集中的所有重复项。

可以使用排序有效地计算重复对的列表,

s_idx = np.argsort(x)
diff_idx = np.nonzero(x[s_idx[:-1]] == x[s_idx[1:]])[0]

其中s_idx[diff_idx]&lt; - &gt;对s_idx[diff_idx+1]对应于原始数组中重复的索引。 (此处array([1, 2, 3])&lt; - &gt; array([2, 5, 4]))。

但是,我不确定如何从大型数组大小(cluster_id)的链接信息中有效地计算N > 10⁶

@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。

2 个答案:

答案 0 :(得分:1)

您可以使用numpy.unique

In [13]: x = np.array([1, 0, 0, 3, 3, 0])

In [14]: values, cluster_id = np.unique(x, return_inverse=True)

In [15]: values
Out[15]: array([0, 1, 3])

In [16]: cluster_id
Out[16]: array([1, 0, 0, 2, 2, 0])

(群集ID按排序的唯一值的顺序分配,而不是按照值在输入中首次出现的顺序分配。)

群集0中项目的位置:

In [22]: cid = 0

In [23]: values[cid]
Out[23]: 0

In [24]: (cluster_id == cid).nonzero()[0]
Out[24]: array([1, 2, 5])

答案 1 :(得分:1)

这是一种使用np.unique根据数字的第一个外观保留订单的方法 -

unq, first_idx, ID = np.unique(x,return_index=1,return_inverse=1)
out = first_idx.argsort().argsort()[ID]

示例运行 -

In [173]: x
Out[173]: array([1, 0, 0, 3, 3, 0, 9, 0, 2, 6, 0, 0, 4, 8])

In [174]: unq, first_idx, ID = np.unique(x,return_index=1,return_inverse=1)

In [175]: first_idx.argsort().argsort()[ID]
Out[175]: array([0, 1, 1, 2, 2, 1, 3, 1, 4, 5, 1, 1, 6, 7])