在Python中对数字进行分组/聚类
我GOOGLE了,我testing了,这让我在我的智慧结束。 我有一个我需要按照相似性分组的数字列表。 例如,在[1,6,9,100,102,105,109,134,139]的列表中,1 6 9将被放入列表中,100,102,105和109将被放入名单,134和139.我在math上很糟糕,我尝试了这个,但是我不能使它工作。 为了尽可能明确,我希望将相距10个数值的数字进行分组。 谁能帮忙? 谢谢。
有很多方法可以进行聚类分析 。 一个简单的方法是查看连续数据元素之间的间隙大小:
def cluster(data, maxgap): '''Arrange data into groups where successive elements differ by no more than *maxgap* >>> cluster([1, 6, 9, 100, 102, 105, 109, 134, 139], maxgap=10) [[1, 6, 9], [100, 102, 105, 109], [134, 139]] >>> cluster([1, 6, 9, 99, 100, 102, 105, 134, 139, 141], maxgap=10) [[1, 6, 9], [99, 100, 102, 105], [134, 139, 141]] ''' data.sort() groups = [[data[0]]] for x in data[1:]: if abs(x - groups[-1][-1]) <= maxgap: groups[-1].append(x) else: groups.append([x]) return groups if __name__ == '__main__': import doctest print(doctest.testmod())
这将find组:
nums = [1, 6, 9, 100, 102, 105, 109, 134, 139] for k, g in itertools.groupby(nums, key=lambda n: n//10): print k, list(g) 0 [1, 6, 9] 10 [100, 102, 105, 109] 13 [134, 139]
请注意,如果nums实际上未按照您的示例显示sorting,则需要先对其进行sorting。
首先,你可以很容易地将任何序列转换成一系列相邻的项目。 只要开球,将其向前移动,然后压缩未转移和未转移的副本。 唯一的技巧是你需要从(<something>, 1)
或(139, <something>)
,因为在这种情况下,我们不需要每对元素,而是每对元素:
def pairify(it): it0, it1 = itertools.tee(it, 2) first = next(it0) return zip(itertools.chain([first, first], it0), it1)
(这不是编写它的最简单的方法,但是我认为这可能是对不熟悉itertools
人最易读的方式。)
>>> a = [1, 6, 9, 100, 102, 105, 109, 134, 139] >>> list(pairify(a)) [(1, 1), (1, 6), (6, 9), (9, 100), (100, 102), (102, 105), (105, 109), (109, 134), (134, 139)]
然后,用Ned Batchelder的一个稍微复杂的版本,你可以使用groupby
。
不过,我认为在这种情况下,这最终会比做同样事情的显式生成器更复杂。
def cluster(sequence, maxgap): batch = [] for prev, val in pairify(sequence): if val - prev >= maxgap: yield batch batch = [] else: batch.append(val) if batch: yield batch