Извлечение границ плотных областей 1 с в огромный список 1 и 0 - PullRequest
4 голосов
/ 14 мая 2019

Я не уверен, как сформулировать мою проблему. Но вот оно ...

У меня огромный список единиц и нулей [Общая длина = 53820].

Пример того, как выглядит список - [0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1...........]

Визуализация приведена ниже.

Ось X: Индекс элемента (от 0 до 53820)

Ось Y: значение по этому индексу (то есть 1 или 0)

График ввода -> (http://i67.tinypic.com/2h5jq5e.png) The plots

График четко показывает 3 плотных области, где встречаемость 1 с больше. Я нарисовал поверх графика, чтобы показать визуально плотные области. (уродливые черные линии на сюжете). Я хочу знать порядковые номера по оси x плотных областей (начальная и конечная границы) на графике.

Я извлекаю куски по 1 с и сохраняю стартовые индексы каждого в новом списке с именем «старты». Эта функция возвращает список словарей, таких как:

{'start': 0, 'count': 15, 'end': 16}, {'start': 2138, 'count': 3, 'end': 2142}, {'start': 2142, 'count': 3, 'end': 2146}, {'start': 2461, 'count': 1, 'end': 2463}, {'start': 2479, 'count': 45, 'end': 2525}, {'start': 2540, 'count': 2, 'end': 2543}

Затем в пусках, после установки порога, сравниваются соседние элементы. Который возвращает видимые границы плотных областей.

THR = 2000
    results = []
    cues = {'start': 0, 'stop': 0}  
    result,starts = densest(preds) # Function that returns the list of dictionaries shown above
    cuestart = False # Flag to check if looking for start or stop of dense boundary
    for i,j in zip(range(0,len(starts)), range(1,len(starts))):
        now = starts[i]
        nextf = starts[j]

        if(nextf-now > THR):
            if(cuestart == False):
                cues['start'] = nextf
                cues['stop'] = nextf
                cuestart = True

            elif(cuestart == True): # Cuestart is already set
                cues['stop'] = now
                cuestart = False
                results.append(cues)
                cues = {'start': 0, 'stop': 0}

    print('\n',results)

Вывод и соответствующий график выглядят следующим образом.

[{'start': 2138, 'stop': 6654}, {'start': 23785, 'stop': 31553}, {'start': 38765, 'stop': 38765}]

Выходной график -> (http://i63.tinypic.com/23hom6o.png) Output plot

Этот метод не может получить последнюю плотную область, как видно на графике, а также для других данных аналогичных сортов.

P.S. Я также пробовал «KDE» на этих данных и «distplot» с использованием seaborn, но это дает мне графики напрямую, и я не могу извлечь из них граничные значения. Ссылка на этот вопрос находится здесь ( Получение значений границ плотной области из вывода графика KDE )

1 Ответ

0 голосов
/ 15 мая 2019

ОК, вам нужен ответ ...

Во-первых, импорт (мы будем использовать LineCollections)

import numpy as np ; import matplotlib.pyplot as plt ;                           
from matplotlib.collections import LineCollection                                

Далее определение констант

N = 1001 ; np.random.seed(20190515)                                              

и генерация поддельных данных

x = np.linspace(0,1, 1001)                                                       
prob = np.where(x<0.4, 0.02, np.where(x<0.7, 0.95, 0.02))                        
y = np.where(np.random.rand(1001)<prob, 1, 0)                                    

здесь мы создаем коллекцию строк, sticks - массив N×2×2 содержащие начальную и конечную точки наших вертикальных линий

sticks = np.array(list(zip(zip(x, np.zeros(N)), zip(x, y))))                                  
lc = LineCollection(sticks)                                                      

наконец, накопленная сумма, здесь нормализованная, имеет тот же масштаб, что и вертикальные линии

cs = (y-0.5).cumsum()                                                            
csmin, csmax = min(cs), max(cs)                                                  
cs = (cs-csmin)/(csmax-csmin) # normalized to 0 ÷ 1                              

Нам осталось только построить наши результаты

f, a = plt.subplots()                                                            
a.add_collection(lc)                                                             
a.plot(x, cs, color='red')                                                       
a.grid()                                                                         
a.autoscale()                                                                    

Вот это сюжет

enter image description here

и вот деталь зоны остановки .

enter image description here

Вы можете сгладить данные cs и использовать что-то от scipy.optimize до определить положение крайностей. Если у вас есть проблема в этом последнем шаг, пожалуйста, задайте еще один вопрос.

...