Преобразуйте pandas df с данными в столбце списка во временные ряды в длинном формате. Используйте три столбца: [список данных] + [отметка времени] + [продолжительность]

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

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

df_test = pd.DataFrame({'timestamp': [1462352000000000000, 1462352100000000000, 1462352200000000000, 1462352300000000000],
                'list': [[1,2,1,9], [2,2,3,0], [1,3,3,0], [1,1,3,9]],
                'duration_sec': [3.0, 3.0, 3.0, 3.0]})

tdi = pd.DatetimeIndex(df_test.timestamp)
df_test.set_index(tdi, inplace=True)
df_test.drop(columns='timestamp', inplace=True)
df_test.index.name = 'datetimeindex'

Из:

                             list  duration_sec
datetimeindex                                      
2016-05-04 08:53:20  [1, 2, 1, 9]           3.0
2016-05-04 08:55:00  [2, 2, 3, 0]           3.0
2016-05-04 08:56:40  [1, 3, 3, 0]           3.0
2016-05-04 08:58:20  [1, 1, 3, 9]           3.0

Целью является:

                     value
datetimeindex
2016-05-04 08:53:20  1
2016-05-04 08:53:21  2
2016-05-04 08:53:22  1
2016-05-04 08:53:23  9
2016-05-04 08:55:00  2
2016-05-04 08:55:01  2
2016-05-04 08:55:02  3
2016-05-04 08:55:03  0
2016-05-04 08:56:40  1
2016-05-04 08:56:41  3
2016-05-04 08:56:42  3
2016-05-04 08:56:43  0
2016-05-04 08:58:20  1
2016-05-04 08:58:21  1
2016-05-04 08:58:22  3
2016-05-04 08:58:23  9

Имейте в виду, что это означает, что на каждый элемент нужно не просто отводить 1 секунду, это было сделано только для упрощения примера. Вместо этого это около 4 элементов в последовательности, которые имеют заданную продолжительность, например, 3,0 секунды (которая также может варьироваться от строки к строке), и где первый элемент каждой последовательности всегда начинается в момент времени 0, что означает, что секунды на элемент следует рассчитывать как [3,0 сек / (4-1) элементов] = 1 сек.

####

Контекст:

В примере показано преобразование в Datetimeindex, поскольку это делает его подходящим для Season_decompose (), см. https://www.machinelearningplus.com/time-series/time-series-analysis-python/ первое попадание в поиск.

Там результирующий df выглядит так:

df_test2 = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')

Из:

                value
date                 
1991-07-01   3.526591
1991-08-01   3.180891
1991-09-01   3.252221
1991-10-01   3.611003
1991-11-01   3.565869
              ...
2008-02-01  21.654285
2008-03-01  18.264945
2008-04-01  23.107677
2008-05-01  22.912510
2008-06-01  19.431740

[204 rows x 1 columns]

А затем легко применить seaonal_decompose () - ›Аддитивное разложение:

result_add = seasonal_decompose(df_test2['value'], model='additive', extrapolate_trend='freq')

Участок:

plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()

введите описание изображения здесь

Теперь то же самое необходимо для df_test выше.


person questionto42    schedule 04.08.2020    source источник
comment
Имеет ли значение столбец duration_sec в этом вопросе?   -  person EddyG    schedule 04.08.2020
comment
@EddyG Это необходимо, потому что вам нужно каким-то образом узнать, какая временная метка будет следующей после начала, которую вы знаете только один раз для каждой строки. У меня нет другой информации о времени между элементами в каждой последовательности. Таким образом, следующая временная метка может быть рассчитана только с помощью + duration / len (sequence), я думаю.   -  person questionto42    schedule 04.08.2020


Ответы (1)


Сначала используйте DataFrame.explode, а затем добавьте счетчик _2 _ и to_timedelta на df.index:

df_test = df_test.explode('nestedList')
df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount(), unit='s')

print (df_test)
                    nestedList  duration_sec
2016-05-04 08:53:20          1           3.0
2016-05-04 08:53:21          2           3.0
2016-05-04 08:53:22          1           3.0
2016-05-04 08:53:23          9           3.0
2016-05-04 08:55:00          2           3.0
2016-05-04 08:55:01          2           3.0
2016-05-04 08:55:02          3           3.0
2016-05-04 08:55:03          0           3.0
2016-05-04 08:56:40          1           3.0
2016-05-04 08:56:41          3           3.0
2016-05-04 08:56:42          3           3.0
2016-05-04 08:56:43          0           3.0
2016-05-04 08:58:20          1           3.0
2016-05-04 08:58:21          1           3.0
2016-05-04 08:58:22          3           3.0
2016-05-04 08:58:23          9           3.0

РЕДАКТИРОВАТЬ:

df_test = df_test.explode('nestedList') 
sizes = df_test.groupby(level=0)['nestedList'].transform('size').sub(1)
duration = df_test['duration_sec'].div(sizes) 
df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount() * duration, unit='s') 

EDIT2 по запросу:

С полученным df теперь возможно это простое применение Decpose (), что и было конечной целью:

result_add = seasonal_decompose(x=df_test['nestedList'], model='additive', extrapolate_trend='freq', period=int(len(df_test)/2))
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()

простое приложение, вставленное пользователем

person jezrael    schedule 04.08.2020
comment
Что касается комментария @ EddyG, на данный момент это только отсчет секунд. Если бы у меня было 50 элементов в последовательности и продолжительность 30 секунд, это больше не сработало бы. Мне пришлось бы добавить 30/50 вместо полной секунды для каждого счета. Я принял это сейчас слишком рано, мой вопрос был непонятен. Хотя сейчас уже есть блестящий ответ относительно тех нескольких минут, в которые был опубликован вопрос. - person questionto42; 04.08.2020
comment
@Lorenz - Мне непонятно одно, в подсписках 4 значения, но есть столбец duration_sec, разделенный на 3? Значит, по умолчанию длина вычитается на 1? Итак, решение df_test = df_test.explode('nestedList') sizes = df_test.groupby(level=0)['nestedList'].transform('size').sub(1).div(df_test['duration_sec']) df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount() * sizes, unit='s') - person jezrael; 04.08.2020
comment
Продолжительность составляет 3,0 секунды для всех 4 элементов (но это только пример, который я выбрал), я подумал, что это будет, если первый элемент запустится сразу, а затем остальные с расстояния в 1 секунду. Я думаю, это сбивает с толку, я должен это изменить. Я взял это, чтобы получить простой пример. На самом деле время на единицу намного меньше. Предположим, каждый элемент занимает 0,05 секунды, не могли бы вы мне помочь, как это будет сгруппировано? Я думаю, это то, что вы предлагаете здесь с * sizes, позвольте мне проверить. Великолепно, это работает. Не могли бы вы добавить это в ответ, а я поменяю вопрос на переменную размеров? - person questionto42; 04.08.2020
comment
@Lorenz - Возможно ли изменить выборку данных на другой срок с ожидаемым результатом? - person jezrael; 04.08.2020
comment
Я изменю вопрос так, чтобы продолжительность больше не учитывала роль, а была обычно установленной продолжительностью для каждого элемента, в какой бы последовательности она ни была. Дай мне пару минут. - person questionto42; 04.08.2020
comment
Хорошо, готово, теперь в вопрос включена глобальная переменная продолжительности. Пожалуйста, просто измените свою идею, используя groupby(level=0).cumcount() * sizes на groupby(level=0).cumcount() * duration в своем ответе, введите duration = 1 прямо перед этим и удалите теперь ненужный столбец duration_sec вывода. Спасибо - person questionto42; 04.08.2020
comment
Я проверю. Я дам вам знать, если это решит проблему, это может помочь определить продолжительность каждого элемента, который вы, кажется, предлагаете сейчас. Кажется многообещающим, дайте мне немного времени. - person questionto42; 04.08.2020
comment
У вас должно быть наоборот, df_test['duration_sec'].div(sizes) будет длительностью для каждого элемента. В остальном все в порядке, проверка правдоподобна. Вы сознательно игнорируете один элемент, чтобы получить, например: длительность последовательности 5 секунд и последовательность из 4 элементов - ›длительность элемента 5/3 секунды. Мне нужно будет проверить это в более крупном наборе данных, но это должно быть так. Я откатываю вопрос, чтобы снова иметь столбец duration_sec в качестве требования. - person questionto42; 04.08.2020