Объединить две серии временных интервалов в pandas (пересечение) - PullRequest
1 голос
/ 09 апреля 2020

У меня есть несколько списков интервалов времени, и мне нужно найти интервалы времени (пересечение), которые являются общими для всех из них.

Например,

a = [['2018-02-03 15:06:30', '2018-02-03 17:06:30'], # each line is read as [start, end]
     ['2018-02-05 10:30:30', '2018-02-05 10:36:30'],
     ['2018-02-05 11:30:30', '2018-02-05 11:42:32']]

b = [['2018-02-03 15:16:30', '2018-02-03 18:06:30'],
     ['2018-02-04 10:30:30', '2018-02-05 10:32:30']]

c = [['2018-02-01 15:00:30', '2018-02-05 18:06:30']]

Результат будет

common_intv = [['2018-02-03 15:16:30','2018-02-03 17:06:30'],
               ['2018-02-05 10:30:30','2018-02-05 10:32:30']]

Я нашел это решение, которое должно работать и для временных интервалов, но мне было интересно, есть ли более эффективный способ сделать это в pandas.

Предлагаемое решение в ссылке будет обрабатывать два списка одновременно, то есть сначала найдет общие интервалы между a и b, затем поместит эти общие интервалы в переменную common, а затем найдет общие интервалы между common и c и т. д. ...

Конечно, глобальное решение (с учетом всех интервалов одновременно) было бы еще лучше!

1 Ответ

1 голос
/ 09 апреля 2020

Вы можете использовать pandas.merge_asof в обоих направлениях, чтобы получить первый выбор, а затем тщательно очистить результирующие строки. Код может быть:

# build the dataframes and ensure Timestamp types
dfa = pd.DataFrame(a, columns=['start', 'end']).astype('datetime64[ns]')
dfb = pd.DataFrame(b, columns=['start', 'end']).astype('datetime64[ns]')
dfc = pd.DataFrame(c, columns=['start', 'end']).astype('datetime64[ns]')

# merge a and b
tmp = pd.concat([pd.merge_asof(dfa, dfb, on='start'),
                 pd.merge_asof(dfb, dfa, on='start')]
                ).sort_values('start').dropna()

# keep the minimum end and ensure end <= start
tmp = tmp.assign(end=np.minimum(tmp.end_x, tmp.end_y))[['start', 'end']]
tmp = tmp[tmp['start'] <= tmp['end']]

# merge c
tmp = pd.concat([pd.merge_asof(tmp, dfc, on='start'),
                 pd.merge_asof(dfc, tmp, on='start')]
                ).sort_values('start').dropna()

tmp = tmp.assign(end=np.minimum(tmp.end_x, tmp.end_y))[['start', 'end']]
tmp = tmp[tmp['start'] <= tmp['end']]

Дает, как и ожидалось:

                start                 end
0 2018-02-03 15:16:30 2018-02-03 17:06:30
1 2018-02-05 10:30:30 2018-02-05 10:32:30
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...