Определить группу данных во временных сериях с разреженными нанопанелями в пандах - PullRequest
1 голос
/ 25 сентября 2019

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

  • Существует примерно одна группа данных в час, но они не строго ограничены в течение одного часа
  • Разрешение по времени составляет 5 секунд (это фиксированное значение)
  • Число данных в каждой группе не является фиксированным, но они имеют длину приблизительно 10 минут
  • Отсутствуют данныев каждой группе (примерно 10% -20%)
  • Время начала каждой группы данных может варьироваться в несколько минут (в некоторых случаях это дрейф, в других - это пошаговое изменение)

Я могу достичь этого результата, зацикливаясь на элементах кадра данных и отыскивая последовательные пропущенные данные выше определенного порога (например, 5 или 10 минут).Однако это медленное и уродливое решение.

Я проверил библиотеки itertools и more-itertools, но не нашел ни одного решения, которое могло бы удовлетворить мою задачу.Функция more_itertools.consecutive_groups делает что-то похожее, но я не знаю, как использовать ее для обработки недостающих данных в каждой группе.

Я ищу более общую схему идеи / реализации, но если вы хотитеПоиграв с некоторыми данными, вы можете генерировать случайные временные ряды с помощью кода ниже.Однако это не совсем репрезентативно, так как время начала и продолжительность каждой группы фиксированы.

import numpy as np
import pandas as pd

idx= pd.date_range(start='2019-01-01 00:00:00', end='2019-01-01 23:00:00',freq='5s')
df=pd.DataFrame(index=idx)
df['data']=np.nan
df[(df.index.minute>5)&(df.index.minute<15)]=1

idxlist=df[(df.index.minute>5)&(df.index.minute<15)].index
randidx=np.random.choice(idxlist,500)
df.loc[pd.DatetimeIndex(randidx)]=np.nan

Редактировать:

У меня нет строгого определениядля «группы», но если вы строите данные из приведенного выше примера, это должно быть очевидно.Данные поступают в сгустки и разделены длинными интервалами nan, каждая из этих сгустков является группой.Вот изображение, показывающее пример из моих реальных данных.

enter image description here

Ожидаемым результатом должен быть список, элементами которого являются индексы, соответствующие каждой группе, илиальтернативно время начала и время окончания каждой группы или что-то подобное.Опять же, меня больше интересуют идеи или предложения о том, как мне этого добиться, я сам могу позаботиться о реализации.

1 Ответ

1 голос
/ 25 сентября 2019

Вы можете отбросить все значения NaN, а затем сравнить разницу между последовательными строками, используя diff .Вы выбираете достаточно большой порог, чтобы быть уверенным, что это новая группа, а не просто несколько пропущенных значений (в следующем примере я выбираю порог в 50 минут), и если разница больше, чем порог, то это начало новойгруппа.Предыдущая строка - это конец предыдущей группы.

Например:

#replicating your data
idx= pd.date_range(start='2019-01-01 00:00:00', end='2019-01-01 23:00:00',freq='5s')
df=pd.DataFrame(index=idx)
df['data']=np.nan
df[(df.index.minute>5)&(df.index.minute<15)]=1

idxlist=df[(df.index.minute>5)&(df.index.minute<15)].index
randidx=np.random.choice(idxlist,500)
df.loc[pd.DatetimeIndex(randidx)]=np.nan

#searching for the groups
ddf = df.dropna().reset_index()
threshold = pd.Timedelta(50, 'm')
starting = ddf['index'].loc[ddf['index'].diff() > threshold]

starting is:

82     2019-01-01 01:06:05
165    2019-01-01 02:06:00
256    2019-01-01 03:06:05
344    2019-01-01 04:06:00
434    2019-01-01 05:06:00
527    2019-01-01 06:06:00
607    2019-01-01 07:06:00
699    2019-01-01 08:06:00
784    2019-01-01 09:06:00
869    2019-01-01 10:06:00
961    2019-01-01 11:06:00
1049   2019-01-01 12:06:00
1135   2019-01-01 13:06:00
1225   2019-01-01 14:06:00
1321   2019-01-01 15:06:00
1409   2019-01-01 16:06:00
1498   2019-01-01 17:06:00
1590   2019-01-01 18:06:00
1686   2019-01-01 19:06:00
1774   2019-01-01 20:06:00
1865   2019-01-01 21:06:05
1946   2019-01-01 22:06:05
dtype: datetime64[ns]

В каждой строке указывается время началановой группы.На самом деле, вам не хватает первой строки ddf, которая также является началом группы.

Чтобы пойти дальше, вы можете рассчитать время окончания.Просто возьмите предыдущую строку в ddf каждой строки, выбранной в starting.Не забудьте добавить последний ряд ddf.Делая так, вы можете иметь начальное и конечное время, и вы можете собрать их вместе в кадре данных.

ending = ddf['index'].loc[starting.index-1]

#adding first row of ddf to starting, and last row of ddf to ending
starting = pd.Series(ddf['index'].iloc[0]).append(starting)
ending = ending.append(pd.Series(ddf['index'].iloc[-1]))

#make a dataframe, each row contains starting and ending times of a group
groups = pd.DataFrame({'start':starting.reset_index(drop=True), 'end':ending.reset_index(drop=True)})

#this is groups
                 start                 end
0  2019-01-01 00:06:10 2019-01-01 00:14:55
1  2019-01-01 01:06:05 2019-01-01 01:14:50
2  2019-01-01 02:06:00 2019-01-01 02:14:55
3  2019-01-01 03:06:05 2019-01-01 03:14:55
4  2019-01-01 04:06:00 2019-01-01 04:14:55
5  2019-01-01 05:06:00 2019-01-01 05:14:50
6  2019-01-01 06:06:00 2019-01-01 06:14:45
7  2019-01-01 07:06:00 2019-01-01 07:14:50
8  2019-01-01 08:06:00 2019-01-01 08:14:55
9  2019-01-01 09:06:00 2019-01-01 09:14:55
10 2019-01-01 10:06:00 2019-01-01 10:14:55
11 2019-01-01 11:06:00 2019-01-01 11:14:55
12 2019-01-01 12:06:00 2019-01-01 12:14:55
13 2019-01-01 13:06:00 2019-01-01 13:14:55
14 2019-01-01 14:06:00 2019-01-01 14:14:55
15 2019-01-01 15:06:00 2019-01-01 15:14:55
16 2019-01-01 16:06:00 2019-01-01 16:14:55
17 2019-01-01 17:06:00 2019-01-01 17:14:55
18 2019-01-01 18:06:00 2019-01-01 18:14:55
19 2019-01-01 19:06:00 2019-01-01 19:14:55
20 2019-01-01 20:06:00 2019-01-01 20:14:55
21 2019-01-01 21:06:05 2019-01-01 21:14:55
22 2019-01-01 22:06:05 2019-01-01 22:14:55
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...