Заполнение нуля панд за отсутствующие даты * определяется * группой - PullRequest
2 голосов
/ 26 сентября 2019

Вопрос: Использование панд - как эффективно заполнить пропущенные даты нулевыми значениями с ежемесячной (например, индексированной в последний день) частотой относительно минимальных / максимальных значений даты на группу ?

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

df.date = df.date + pd.offsets.MonthEnd(0) 

Без этого исправления заполненные значения с freq = 'M' могут привести к NA ...!

Примечание: версия панды 0.24.2

Пример ввода:

data = [{'name': 'A', 'date': '2019-01-01', 'val': 10},
{'name': 'A', 'date': '2019-04-30', 'val': 2},
{'name': 'B', 'date': '2019-02-15', 'val': 6},
{'name': 'B', 'date': '2019-05-01', 'val': 5}]

df = pd.DataFrame(data)

         date name  val
0  2019-01-01    A   10
1  2019-04-30    A    2
2  2019-02-15    B    6
3  2019-05-01    B    5

Обратите внимание, что даты на входе не обязательно являются первым или последним днем ​​ихсоответствующий месяц.

Пример желаемого вывода

         date name  val
0  2019-01-31    A   10
1  2019-02-28    A    0
2  2019-03-31    A    0
3  2019-04-30    A    2
4  2019-02-28    B    6
5  2019-03-31    B    0
6  2019-04-30    B    0
7  2019-05-31    B    5

Попытки:

Следующее работает на уровне индекса, но заполняет все с помощью NA:

df['date'] = pd.to_datetime(df['date'])

dg = df.groupby('name').apply(lambda x: x.reindex(pd.date_range(min(x.date), max(x.date), freq='M')))

Также:

Панды, заполняющие недостающие даты и значения в группе

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

Ответы [ 2 ]

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

Я бы использовал groupby, resample и asfreq ( редактировать: по мере того, как вы обновляли вопрос о датах, не относящихся к концу месяца. Я добавил pd.offsets.MonthEnd, как вы предлагали )

df.date = df.date + pd.offsets.MonthEnd(0) 
(df.set_index('date').groupby('name').resample('M')
                     .asfreq(fill_value=0).drop('name',1)
                     .reset_index())

Out[550]:
  name       date  val
0    A 2019-01-31   10
1    A 2019-02-28    0
2    A 2019-03-31    0
3    A 2019-04-30    2
4    B 2019-02-28    6
5    B 2019-03-31    0
6    B 2019-04-30    0
7    B 2019-05-31    5
1 голос
/ 26 сентября 2019

Одно быстрое исправление:

df.date = pd.to_datetime(df.date)

new_df = (df.set_index('date')
            .groupby('name', as_index=False)
            .apply(lambda x: x.resample('M').interpolate())
            .reset_index(0, drop=True)
         )

s = new_df['name'].isna() 
new_df.loc[s, 'val'] = 0
new_df['name'] = new_df['name'].ffill()

Вывод:

           name   val
date                 
2019-01-31    A  10.0
2019-02-28    A   0.0
2019-03-31    A   0.0
2019-04-30    A   2.0
2019-02-28    B   6.0
2019-03-31    B   0.0
2019-04-30    B   0.0
2019-05-31    B   5.0
...