Последовательные значения бина в списке - PullRequest
1 голос
/ 07 октября 2019

У меня есть список:

new_maks = [75, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 89, 91]

Я хочу объединить элементы в области, где следующий элемент последовательно увеличивается на 1. Моя первоначальная идея состоит в том, чтобы инициализировать два списка bin_start и bin_end и итерацию по new_maks для проверки последовательных значений.

bin_start = []
bin_end = []

counter = 0
for i in range(len(new_maks)):
    if new_maks[i] == new_maks[0]:
        bin_start.append(new_maks[i])

    elif (new_maks[i] - new_maks[i-1]) ==1:
        try:
            bin_end[counter] = new_maks[i]
        except:
            bin_end.append(new_maks[i])

    elif (new_maks[i] - new_maks[i-1]) >1:

        if new_maks[i] != new_maks[-1]:
            bin_start.append(new_maks[i])
            counter +=1

Что дает желаемый результат:

bin_start= [75, 85]
bin_end = [81, 89]

Существует ли более простой / векторизованный способ достижения этого результата?

Ответы [ 2 ]

2 голосов
/ 07 октября 2019

Для повышения эффективности работы с инструментами NumPy -

def start_stop_seq1(a):
    m = np.r_[False,np.diff(a)==1,False]
    return a[m[:-1]!=m[1:]].reshape(-1,2).T

Пробный прогон -

In [34]: a # input array
Out[34]: 
array([ 75,  76,  77,  78,  79,  80,  81,  85,  86,  87,  88,  89,  91,
        92,  93, 100, 101, 110])

In [35]: start_stop_seq1(a)
Out[35]: 
array([[ 75,  85,  91, 100],
       [ 81,  89,  93, 101]])

Альтернатива № 1: один вкладыш с еще одним np.diff

Мы можем сделать еще один шаг, чтобы достичь компактности -

In [43]: a[np.diff(np.r_[False,np.diff(a)==1,False])].reshape(-1,2).T
Out[43]: 
array([[ 75,  85,  91, 100],
       [ 81,  89,  93, 101]])
2 голосов
/ 07 октября 2019

Более простым способом может быть использование groupby и count :

from itertools import groupby, count

counter = count(1)
new_mask = [75, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 89]

generator = ((first, last) for key, (first, *_, last) in groupby(new_mask, key=lambda val: val - next(counter)))
bin_start, bin_end = zip(*generator)

print(bin_start)
print(bin_end)

Выход

(75, 85)
(81, 89)

Это основано на старом itertools рецепт . Если вам нравятся панды, вы можете сделать что-то вроде этого:

import pandas as pd

new_mask = [75, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 89]

s = pd.Series(data=new_mask)
result = s.groupby(s.values - s.index).agg(['first', 'last'])
bin_start, bin_end = zip(*result.itertuples(index=False))

print(bin_start)
print(bin_end)

Опять же, это основано на принципе, что последовательное увеличение (на 1) значения будет иметь одинаковую разницу с бегущей последовательностью. Как упомянуто в связанной документации:

Ключом к решению является различие с диапазоном, так что все последовательные числа появляются в одной группе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...