Идея состоит в том, чтобы переиндексировать DataFrame
, чтобы заполнить имеющиеся у вас пробелы.
Установить DataFrame
, сгенерированный с использованием вашего образца:
from io import StringIO
buffer = StringIO()
buffer.write('''\
date|timestamp|pid|delta_qty|resulting_qty
2017-03-06|2017-03-06 12:24:22|A|0|0.0
2017-03-31|2017-03-31 02:43:11|A|3|3.0
2017-04-08|2017-04-08 22:04:35|A|-1|2.0
2017-04-12|2017-04-12 18:26:39|A|-1|1.0
2017-04-19|2017-04-19 09:15:38|A|-1|0.0
2019-01-16|2019-01-16 23:37:17|B|0|0.0
2019-01-19|2019-01-19 09:40:38|C|0|0.0
2019-04-05|2019-04-05 16:40:32|B|2|2.0
2019-04-22|2019-04-22 11:06:33|B|-1|1.0
2019-04-23|2019-04-23 13:23:17|B|-1|0.0
2019-05-09|2019-05-09 16:25:41|C|2|2.0
''')
buffer.seek(0)
df = pd.read_csv(buffer, sep='|', parse_dates=['date', 'timestamp'])
Сначала мы сгенерируемновый, без пропуска индекс между минимальной и максимальной датами для каждого продукта.Это приводит к отсутствию строк для продукта после последнего существующего обновления, согласно вашему примеру.Тем не менее, этот шаг легко настраивается в соответствии с вашими требованиями.Например, если вы хотите, чтобы даты охватывали период от первой записи продукта до сегодняшнего дня, вы можете просто установить start
и end
вручную.
from itertools import chain, cycle
date_ranges = df.groupby('pid').agg({'date': ['min', 'max']})
pairs = (zip(cycle([pid]), pd.date_range(start, end))
for pid, (start, end) in date_ranges.iterrows())
new_index = pd.Index(chain.from_iterable(pairs), name=['pid', 'date'])
Затем мы применяем новый индекс.Здесь у нас есть два варианта:
- В соответствии с вашим примером, мы продолжаем заполнение на основе последнего обновления точно так же, как
- Заполните
delta_qty
0
и оставшимися столбцами впоследнее обновление (это отклонение от вашего запроса, но кажется логичным и является лишь незначительным изменением)
В любом случае двумя основными понятиями являются метод .reindex
и метод .fillna
,Мы можем использовать reindex
, чтобы расширить плотную DataFrame
, чтобы включить все даты, но иметь разреженные данные.Затем мы заполняем nan
с правильными данными.Поскольку мы добавляем вперед после последнего обновления, мы хотим указать method='ffill'
для документов
Метод 1:
# this fills the rows per last update
results = df.set_index(['pid', 'date'])\
.reindex(new_index).reset_index()
results.fillna(method='ffill', inplace=True)
Возвращает
pid date timestamp delta_qty resulting_qty
0 A 2017-03-06 2017-03-06 12:24:22 0.0 0.0
1 A 2017-03-07 2017-03-06 12:24:22 0.0 0.0
2 A 2017-03-08 2017-03-06 12:24:22 0.0 0.0
3 A 2017-03-09 2017-03-06 12:24:22 0.0 0.0
.. .. ... ... ... ...
24 A 2017-03-30 2017-03-06 12:24:22 0.0 0.0
25 A 2017-03-31 2017-03-31 02:43:11 3.0 3.0
.. .. ... ... ... ...
29 A 2017-04-04 2017-03-31 02:43:11 3.0 3.0
для pid == 'A'
Метод 2:
results = df.set_index(['pid', 'date'])\
.reindex(new_index).reset_index()
results['delta_qty'].fillna(0, inplace=True)
results.fillna(method='ffill', inplace=True)
Возвращает:
pid date timestamp delta_qty resulting_qty
0 A 2017-03-06 2017-03-06 12:24:22 0.0 0.0
1 A 2017-03-07 2017-03-06 12:24:22 0.0 0.0
2 A 2017-03-08 2017-03-06 12:24:22 0.0 0.0
3 A 2017-03-09 2017-03-06 12:24:22 0.0 0.0
.. .. ... ... ... ...
24 A 2017-03-30 2017-03-06 12:24:22 0.0 0.0
25 A 2017-03-31 2017-03-31 02:43:11 3.0 3.0
.. .. ... ... ... ...
29 A 2017-04-04 2017-03-31 02:43:11 0.0 3.0