Отбрасывание всех дат до значения

#python #pandas #time-series #panel-data

Вопрос:

У меня есть панельный фрейм данных о штатах и датах США. Моя цель состоит в том, чтобы найти последнюю дату для каждого состояния, у которого в столбце «Значение» есть 0, а затем удалить все наблюдения до этой точки и включая ее. Так как MWE:

 df = pd.DataFrame({'state':['CA']*6 ['MA']*6, 
               'date':list(pd.date_range('2000-1-1', freq='MS', periods=6))*2,
               'vals':[0, 2, 0, 4, 5, 6, 1, 2, 3, 4, 5, 6]}).set_index(['state', 'date'])
 

Создает этот df:

                   vals
state date
CA    2000-01-01     0
      2000-02-01     2
      2000-03-01     0
      2000-04-01     4
      2000-05-01     5
      2000-06-01     6
MA    2000-01-01     1
      2000-02-01     2
      2000-03-01     3
      2000-04-01     4
      2000-05-01     5
      2000-06-01     6
 

Это находит правильные даты отсечения (интервал открытия), учитывая тот факт, что у MA нет нулей, и, следовательно, нет даты отсечения:

 cutoff_dates = df.groupby('state').apply(lambda g: g[g['vals'] == 0].index.get_level_values(1).max())

state
CA   2000-03-01
MA          NaT
dtype: datetime64[ns]
 

Но я не смог перейти от этого к фильтрации моего фрейма данных, так что у меня есть наблюдения только для CA, начиная с 2000-4-1, и для MA с 2000-1-1. Я вижу, как это можно сделать, повторяя » df » и «cutoff_dates». Но как это может быть достигнуто в среде Панд и групп? Кажется, что это должно быть возможно, но я просто этого не вижу.

Ответ №1:

Создайте логическую маску и промежуточную группу для фильтрации фрейма данных:

 m = df['vals'].eq(0)
g = m.cumsum()
out = df[~m amp; g.groupby(level=0).transform(max).eq(g)]
 

Выход:

 >>> out
                  vals
state date            
CA    2000-04-01     4
      2000-05-01     5
      2000-06-01     6
MA    2000-01-01     1
      2000-02-01     2
      2000-03-01     3
      2000-04-01     4
      2000-05-01     5
      2000-06-01     6
 

Подробности о m amp; g:

 >>> pd.concat([df, m.rename('m'), g.rename('g')], axis=1)
                  vals      m  g
state date                      
CA    2000-01-01     0   True  1
      2000-02-01     2  False  1
      2000-03-01     0   True  2
      2000-04-01     4  False  2
      2000-05-01     5  False  2
      2000-06-01     6  False  2
MA    2000-01-01     1  False  2
      2000-02-01     2  False  2
      2000-03-01     3  False  2
      2000-04-01     4  False  2
      2000-05-01     5  False  2
      2000-06-01     6  False  2