У меня есть фрейм данных ниже, и, как вы заметили, EconomicDate — это начало квартала, и иногда значения в EconomicDate отсутствуют. Я хотел бы иметь непрерывные ежемесячные даты в столбце «Эффективная дата», при этом все столбцы будут заполнены из самой последней эффективной даты.
Пример: для каждой группы = A, поскольку значения для эффективной даты = 01.02.2022 и 1.03.2022 отсутствуют, поэтому необходимо заполнить все значения столбцов с 1 января 2022 года и т. д.
Входной ДФ:
import pandas as pd
data = {
'Group': ['A'] * 24,
'EffectiveDate': [
'1/1/2022', '1/1/2022', '1/1/2022', '1/1/2022', '1/1/2022', '1/1/2022',
'4/1/2022', '4/1/2022', '4/1/2022', '4/1/2022', '4/1/2022', '4/1/2022',
'7/1/2022', '7/1/2022', '7/1/2022', '7/1/2022', '7/1/2022', '7/1/2022',
'10/1/2022', '10/1/2022', '10/1/2022', '10/1/2022', '10/1/2022', '10/1/2022'
],
'ForecastDate': [
'1/1/2022', '2/1/2022', '3/1/2022', '4/1/2022', '5/1/2022', '6/1/2022',
'4/1/2022', '5/1/2022', '6/1/2022', '7/1/2022', '8/1/2022', '9/1/2022',
'7/1/2022', '8/1/2022', '9/1/2022', '10/1/2022', '11/1/2022', '12/1/2022',
'10/1/2022', '11/1/2022', '12/1/2022', '1/1/2023', '2/1/2023', '3/1/2023'
],
'SKU': ['ABC12'] * 24,
'Source': ['fdhh'] * 24
}
df = pd.DataFrame(data)
Выходной ДФ:
| Group |EffectiveDate| ForecastDate| SKU| Source |
|-------|------------|------------|--------|--------|
| A | 1/1/2022 | 1/1/2022 | ABC12 | fdhh |
| A | 1/1/2022 | 2/1/2022 | ABC12 | fdhh |
| A | 1/1/2022 | 3/1/2022 | ABC12 | fdhh |
| A | 1/1/2022 | 4/1/2022 | ABC12 | fdhh |
| A | 1/1/2022 | 5/1/2022 | ABC12 | fdhh |
| A | 1/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 2/1/2022 | 2/1/2022 | ABC12 | fdhh |
| A | 2/1/2022 | 3/1/2022 | ABC12 | fdhh |
| A | 2/1/2022 | 4/1/2022 | ABC12 | fdhh |
| A | 2/1/2022 | 5/1/2022 | ABC12 | fdhh |
| A | 2/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 3/1/2022 | 3/1/2022 | ABC12 | fdhh |
| A | 3/1/2022 | 4/1/2022 | ABC12 | fdhh |
| A | 3/1/2022 | 5/1/2022 | ABC12 | fdhh |
| A | 3/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 4/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 5/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 7/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 8/1/2022 | ABC12 | fdhh |
| A | 4/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 5/1/2022 | 5/1/2022 | ABC12 | fdhh |
| A | 5/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 5/1/2022 | 7/1/2022 | ABC12 | fdhh |
| A | 5/1/2022 | 8/1/2022 | ABC12 | fdhh |
| A | 5/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 6/1/2022 | 6/1/2022 | ABC12 | fdhh |
| A | 6/1/2022 | 7/1/2022 | ABC12 | fdhh |
| A | 6/1/2022 | 8/1/2022 | ABC12 | fdhh |
| A | 6/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 7/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 8/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 10/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 11/1/2022 | ABC12 | fdhh |
| A | 7/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 8/1/2022 | 8/1/2022 | ABC12 | fdhh |
| A | 8/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 8/1/2022 | 10/1/2022 | ABC12 | fdhh |
| A | 8/1/2022 | 11/1/2022 | ABC12 | fdhh |
| A | 8/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 9/1/2022 | 9/1/2022 | ABC12 | fdhh |
| A | 9/1/2022 | 10/1/2022 | ABC12 | fdhh |
| A | 9/1/2022 | 11/1/2022 | ABC12 | fdhh |
| A | 9/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 10/1/2022 | 10/1/2022 | ABC12 | fdhh |
| A | 10/1/2022 | 11/1/2022 | ABC12 | fdhh |
| A | 10/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 10/1/2022 | 1/1/2023 | ABC12 | fdhh |
| A | 10/1/2022 | 2/1/2023 | ABC12 | fdhh |
| A | 10/1/2022 | 3/1/2023 | ABC12 | fdhh |
| A | 11/1/2022 | 11/1/2022 | ABC12 | fdhh |
| A | 11/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 11/1/2022 | 1/1/2023 | ABC12 | fdhh |
| A | 11/1/2022 | 2/1/2023 | ABC12 | fdhh |
| A | 11/1/2022 | 3/1/2023 | ABC12 | fdhh |
| A | 12/1/2022 | 12/1/2022 | ABC12 | fdhh |
| A | 12/1/2022 | 1/1/2023 | ABC12 | fdhh |
| A | 12/1/2022 | 2/1/2023 | ABC12 | fdhh |
| A | 12/1/2022 | 3/1/2023 | ABC12 | fdhh |






Вы можете преобразовать EffectiveDate в месячные периоды с помощью Serie.dt.to_ period , переделать с помощью GroupBy.cumcount и DataFrame.pivot , поэтому можно использовать DataFrame.reindex для каждой группы. Затем измените форму обратно с помощью DataFrame.stack, преобразуйте MultiIndex в столбцы и отфильтруйте ForecastDate, если они больше или равны, на EffectiveDate:
df['EffectiveDate'] = pd.to_datetime(df['EffectiveDate']).dt.to_period('m')
df['ForecastDate'] = pd.to_datetime(df['ForecastDate'])
out = (df.assign(g = df.groupby(['Group','EffectiveDate']).cumcount())
.pivot(index=['Group','EffectiveDate'], columns='g')
.reset_index(level=0)
.groupby('Group')
.apply(lambda x: x.reindex(pd.period_range(x.index.min(),
pd.Period(f'{x.index.max().year}-12')),
method='ffill'))
.drop('Group', axis=1)
.stack()
.droplevel(2)
.rename_axis(['Group','EffectiveDate'])
.reset_index()
.assign(EffectiveDate = lambda x: x['EffectiveDate'].dt.to_timestamp())
.query('ForecastDate >= EffectiveDate'))
print (out.tail(15))
Group EffectiveDate ForecastDate SKU Source
54 A 2022-10-01 2022-10-01 ABC12 fdhh
55 A 2022-10-01 2022-11-01 ABC12 fdhh
56 A 2022-10-01 2022-12-01 ABC12 fdhh
57 A 2022-10-01 2023-01-01 ABC12 fdhh
58 A 2022-10-01 2023-02-01 ABC12 fdhh
59 A 2022-10-01 2023-03-01 ABC12 fdhh
61 A 2022-11-01 2022-11-01 ABC12 fdhh
62 A 2022-11-01 2022-12-01 ABC12 fdhh
63 A 2022-11-01 2023-01-01 ABC12 fdhh
64 A 2022-11-01 2023-02-01 ABC12 fdhh
65 A 2022-11-01 2023-03-01 ABC12 fdhh
68 A 2022-12-01 2022-12-01 ABC12 fdhh
69 A 2022-12-01 2023-01-01 ABC12 fdhh
70 A 2022-12-01 2023-02-01 ABC12 fdhh
71 A 2022-12-01 2023-03-01 ABC12 fdhh
Обновлено: Для динамической фильтрации по столбцу Group используйте вспомогательный словарь mapping с Series.map на последнем этапе фильтрации:
df['EffectiveDate'] = pd.to_datetime(df['EffectiveDate']).dt.to_period('m')
df['ForecastDate'] = pd.to_datetime(df['ForecastDate'])
mapping = {'A': '2022-10-01',
'B':'2022-06-01'}
out = (df.assign(g = df.groupby(['Group','EffectiveDate']).cumcount())
.pivot(index=['Group','EffectiveDate'], columns='g')
.reset_index(level=0)
.groupby('Group')
.apply(lambda x: x.reindex(pd.period_range(x.index.min(),
pd.Period(f'{x.index.max().year}-12')),
method='ffill'))
.drop('Group', axis=1)
.stack()
.droplevel(2)
.rename_axis(['Group','EffectiveDate'])
.reset_index()
.assign(EffectiveDate = lambda x: x['EffectiveDate'].dt.to_timestamp())
.loc[lambda x: (x['ForecastDate'] >= x['EffectiveDate']) &
(x['EffectiveDate'] < x['Group'].map(mapping))]
)
print(out.tail(10))
Group EffectiveDate ForecastDate SKU Source
41 A 2022-07-01 2022-12-01 ABC12 fdhh
43 A 2022-08-01 2022-08-01 ABC12 fdhh
44 A 2022-08-01 2022-09-01 ABC12 fdhh
45 A 2022-08-01 2022-10-01 ABC12 fdhh
46 A 2022-08-01 2022-11-01 ABC12 fdhh
47 A 2022-08-01 2022-12-01 ABC12 fdhh
50 A 2022-09-01 2022-09-01 ABC12 fdhh
51 A 2022-09-01 2022-10-01 ABC12 fdhh
52 A 2022-09-01 2022-11-01 ABC12 fdhh
53 A 2022-09-01 2022-12-01 ABC12 fdhh
Все работает хорошо! Но необходимо прекратить добавлять непрерывную дату вступления в силу после максимальной даты вступления в силу, т. е. 2022-10 гг. Пожалуйста, измените код. Спасибо
@spartacus8w2039, так что нужно поменять .query('ForecastDate >= EffectiveDate') на .query('(ForecastDate >= EffectiveDate) & (EffectiveDate < "2022-10-01")')
< «2022-10-01» не является статическим значением, оно должно быть динамическим для группы по группе A, максимальное значение — «2022-10-01», может быть другая группа «B», которая имеет «2022-06-01» ".
@ spartacus8w2039 - ответ отредактирован.
пожалуйста, добавьте еще одну группу к вашим данным, чтобы охватить несколько групп. также, пожалуйста, уменьшите количество строк во входном фрейме данных - с этим просто работать