2013-02-09 8 views
10

Я искал googled, я протестировал, и это имеет меня в конце моего ума. У меня есть список чисел, которые мне нужно группировать по сходству. Например, в список из [1, 6, 9, 100, 102, 105, 109, 134, 139], 1 6 9 будет внесен список, 100, 102, 105 и 109 будут помещены в список и 134 и 139. Я ужасен в математике, и я пробовал и пробовал это, но я не могу заставить его работать. Чтобы быть явным, насколько это возможно, я хочу группировать числа, находящиеся в пределах 10 значений друг от друга. Может ли кто-нибудь помочь? Благодарю.Группировка/группировка чисел в Python

+4

Вам нужно будет более точно определить «подобие». Вы имеете в виду те же сотни и десятки цифр? –

+0

Я имею в виду цифры, которые находятся в пределах 10 (или сколько угодно) значений друг от друга. Извините, постарался сделать это как можно яснее. –

+1

Что делать, если возможные группы перекрываются? – millimoose

ответ

21

Существует много способов сделать cluster analysis. Один простой подход смотреть на размер зазора между последовательными элементами данных:

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()) 
+0

И есть мое решение. Спасибо большое. Я изучу каждый персонаж этого кода, ха-ха. –

3

Найдет группы:

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] 

Обратите внимание, что если НУМС на самом деле не сортируется как ваш пример показывает, вам нужно сортировать его первым.

+5

Единственное, что мне не нравится в этом подходе, состоит в том, что '' [1, 6, 9, 99, 100, 134, 139] '' группирует * 99 * и * 100 * в разные группы. Было бы лучше вычислить различия между последовательными точками данных, чтобы определить, где начинается один кластер, а другой заканчивается. –

+1

Да, к сожалению, это произошло, когда я попробовал этот код; /. Практически идеально. –

+1

Да, это было underspecified, когда я написал его. –

2

Во-первых, вы можете легко преобразовать любую последовательность в последовательность пар соседних элементов. Просто попробуйте, сдвиньте его вперед и застегните несмещенные и несмещенные копии. Единственная хитрость заключается в том, что вы должны начать с любой (<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 Батчелдера, вы можете просто использовать 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