Я хочу построить модель прогнозирования временных рядов, используя такие функции, как неделя года, день недели, время года и т. д.
Поскольку на прогноз будут сильно влиять самые последние значения, я хочу использовать значения за последние 5 дней в качестве функций, однако у меня возникают проблемы с подготовкой данных для обучения:
Моя текущая таблица выглядит так:
date id score
0 2014-01-01 A 75
1 2014-01-01 B 1
2 2014-01-01 C 2
4 2014-01-02 A 84
5 2014-01-02 B 1
6 2014-01-02 C 3
8 2014-01-03 A 1
9 2014-01-03 B 1
10 2014-01-03 C 1
Поэтому я хочу, чтобы каждая строка выглядела так:
date id score date_1 date_2 date_3 date_4 date-5
10 2014-01-03 A 1 84 75 0 0 0
9 2014-01-03 B 1 1 1 0 0 0
Date_1 - это оценка A, за день до даты в столбце date, date_2 - за два дня до нее и так далее ...
Чтобы я мог предсказать следующий день, используя информацию за последние 5 дней и другие функции, которые не имеют отношения к этому вопросу. Нормально заполнять значения NaN 0






Вы можете использовать groupby(id) и shift. Перед использованием следующей команды вы должны отсортировать df по дате: df.sort_values('date'):
for i in range(5):
df['date_'+str(i+1)] = df.groupby('id')['score'].shift(i+1).fillna(0).astype(int)
Использование приведенной выше команды дает следующий df:
Это работает быстро и плавно, спасибо. Это можно будет реализовать, если я могу заполнить недостающие даты для каждого идентификатора продукта нулями. У вас есть идея сделать это?
Сдвиг во времени с использованием Timedelta
другой ответ сдвигается по числовому индексу. В этом случае работает, но не работает, если в датах есть пробелы или если даты не были отсортированы.
Вы можете справиться с этим, преобразовав DataFrame во временной ряд, а затем используя параметр freq в DataFrame.shift() с объектом pandas.Timedelta.
Пример данных:
import pandas as pd
df = pd.DataFrame({'date': ['2014-01-01'] * 3 +
['2014-01-02'] * 3 +
['2014-01-03'] * 3,
'id': ['A', 'B', 'C'] * 3,
'score': [75, 1, 2, 84, 1, 3, 1, 1, 1]})
df.date = pd.to_datetime(df.date)
df.set_index('date', inplace=True)
Идентификаторы означают, что нам нужна пара циклов, чтобы все было разделено:
for i in range(5):
for id in df.id.unique():
col = 'date_{}'.format(i+1)
freq = pd.Timedelta('{}d'.format(i+1))
df.loc[df.id==id, col] = df.loc[df.id==id, 'score'].shift(freq=freq)
df[col] = df[col].fillna(0).astype(int)
Это дает тот же результат, что и другой подход в этом примере, но если вы пропустите дату, она будет другой.
Вывод:
id score date_1 date_2 date_3 date_4 date_5
date
2014-01-01 A 75 0 0 0 0 0
2014-01-01 B 1 0 0 0 0 0
2014-01-01 C 2 0 0 0 0 0
2014-01-02 A 84 75 0 0 0 0
2014-01-02 B 1 1 0 0 0 0
2014-01-02 C 3 2 0 0 0 0
2014-01-03 A 1 84 75 0 0 0
2014-01-03 B 1 1 1 0 0 0
2014-01-03 C 1 3 2 0 0 0
Спасибо за обобщенный ответ, потому что да, в датах есть пробелы, и даты не нужно сортировать по индексу, так что это хорошее видение с вашей стороны. Однако, когда я запустил точный код с полной таблицей, я получил ошибку: «ValueError: не удается переиндексировать с повторяющейся оси».
Есть ли способ поделиться всеми данными в вопросе или большей частью из них? Это отлично сработало для меня, основываясь на данных примера, который я создал, но всегда легче ответить, если мы оба работаем с одними и теми же данными для начала.
Похоже, у вас, вероятно, есть повторяющиеся пары дата + идентификатор в вашей полной таблице (например, несколько записей для A в одну и ту же дату). Это выходит за рамки вопроса, но будет исправлено с помощью .drop_duplicates(['date', 'id']) до того, как вы включите 'date' в индекс (или вам может потребоваться сделать .groupby(['date', 'id']).score.sum(), в зависимости от причины проблемы. Вежливо попросите, чтобы вы проголосовали за и одобрили этот ответ, если это решит вашу проблему, так как я думаю, что это более безопасное решение, чем использование числовой индексации.
Я действительно ценю твою помощь. Я пробовал, но отбрасывал дубликаты и groupby.sum, но ничего не вышло. Ошибка все та же. Вот полный набор данных: wetransfer.com/downloads/…
drop_duplicates() исправляет ошибку, поскольку в вашем наборе данных дублируются пары дата / идентификатор. Я подозреваю, что вы неправильно выполнили drop_duplicates. После загрузки DataFrame запустите df.drop_duplicates(['date', 'id'], inplace=True), и тогда весь код будет работать правильно.
Хороший ответ - см. Ниже пример смещения с использованием timedelta.