#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