Добавьте отсутствующие даты в pandas dataframe
Мои данные могут содержать несколько событий в заданную дату или NO-события на дату. Я принимаю эти события, получаю подсчет по дате и замышляю их. Однако, когда я их рисую, мои две серии не всегда совпадают.
idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max())
s = df.groupby(['simpleDate']).size()
В приведенном выше коде idx становится диапазон из 30 дат. 09-01-2013 - 09-30-2013
Однако S может иметь только 25 или 26 дней, потому что не было событий за определенную дату. Затем я получаю AssertionError, поскольку размеры не совпадают, когда я пытаюсь построить:
fig, ax = plt.subplots()
ax.bar(idx.to_pydatetime(), s, color='green')
Какой правильный способ справиться с этим? Я хочу удалить даты без каких-либо значений из IDX или (что я предпочел сделать) - добавить в серию недостающую дату со счетом 0. Я бы предпочел иметь полный график 30 дней с 0 значениями. Если этот подход является правильным, любые предложения о том, как начать работу? Мне нужна какая-то динамическая функция reindex
?
Здесь фрагмент S (df.groupby(['simpleDate']).size()
), не замечает записей для 04 и 05.
09-02-2013 2
09-03-2013 10
09-06-2013 5
09-07-2013 1
Ответы
Ответ 1
Вы можете использовать Series.reindex
:
import pandas as pd
idx = pd.date_range('09-01-2013', '09-30-2013')
s = pd.Series({'09-02-2013': 2,
'09-03-2013': 10,
'09-06-2013': 5,
'09-07-2013': 1})
s.index = pd.DatetimeIndex(s.index)
s = s.reindex(idx, fill_value=0)
print(s)
дает
2013-09-01 0
2013-09-02 2
2013-09-03 10
2013-09-04 0
2013-09-05 0
2013-09-06 5
2013-09-07 1
2013-09-08 0
...
Ответ 2
Одна из проблем заключается в том, что reindex
завершится с ошибкой, если есть повторяющиеся значения. Предположим, что мы работаем со временными данными, которые мы хотим индексировать по дате:
df = pd.DataFrame({
'timestamps': pd.to_datetime(
['2016-11-15 1:00','2016-11-16 2:00','2016-11-16 3:00','2016-11-18 4:00']),
'values':['a','b','c','d']})
df.index = pd.DatetimeIndex(df['timestamps']).floor('D')
df
дает
timestamps values
2016-11-15 "2016-11-15 01:00:00" a
2016-11-16 "2016-11-16 02:00:00" b
2016-11-16 "2016-11-16 03:00:00" c
2016-11-18 "2016-11-18 04:00:00" d
Из-за повторяющейся даты 2016-11-16
попытка переиндексации:
all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')
df.reindex(all_days)
сбой:
...
ValueError: cannot reindex from a duplicate axis
(этим он означает, что индекс имеет дубликаты, а не то, что он сам является dup)
Вместо этого мы можем использовать .loc
для поиска записей для всех дат в диапазоне:
df.loc[all_days]
дает
timestamps values
2016-11-15 "2016-11-15 01:00:00" a
2016-11-16 "2016-11-16 02:00:00" b
2016-11-16 "2016-11-16 03:00:00" c
2016-11-17 NaN NaN
2016-11-18 "2016-11-18 04:00:00" d
fillna
может использоваться в серии столбцов для заполнения пробелов, если это необходимо.
Ответ 3
Более быстрое обходное решение - использовать .asfreq
. Это не требует создания нового индекса для вызова внутри reindex
.
dates = pd.Index([pd.Timestamp('2012-05-01'),
pd.Timestamp('2012-05-04'),
pd.Timestamp('2012-05-06')])
s = pd.Series([1, 2, 3], dates)
print(s.asfreq('D'))
2012-05-01 1.0
2012-05-02 NaN
2012-05-03 NaN
2012-05-04 2.0
2012-05-05 NaN
2012-05-06 3.0
Freq: D, dtype: float64
Ответ 4
Здесь хороший метод заполнения отсутствующих дат в фреймворке данных, с вашим выбором fill_value
, days_back
для заполнения и сортировки (date_order
), с помощью которого можно сортировать данные:
def fill_in_missing_dates(df, date_col_name = 'date',date_order = 'asc', fill_value = 0, days_back = 30):
df.set_index(date_col_name,drop=True,inplace=True)
df.index = pd.DatetimeIndex(df.index)
d = datetime.now().date()
d2 = d - timedelta(days = days_back)
idx = pd.date_range(d2, d, freq = "D")
df = df.reindex(idx,fill_value=fill_value)
df[date_col_name] = pd.DatetimeIndex(df.index)
return df
Ответ 5
Во многих случаях resample
(см. документацию здесь) предлагает общее решение, которое может обрабатывать как отсутствующие, так и повторяющиеся даты. Например:
df.resample('D').mean()
resample
является отложенной операцией типа groupby
, поэтому вам нужно следовать ей с другой операцией. В этом случае mean
работает хорошо, но вы также можете использовать многие стандартные методы pandas, такие как max
, sum
и т.д.
Вот исходные данные, но с дополнительной записью для "2013-09-03":
val
date
2013-09-02 2
2013-09-03 10
2013-09-03 20
2013-09-06 5
2013-09-07 1
И вот результаты:
val
date
2013-09-02 2.0
2013-09-03 15.0 <- mean of original values for 2013-09-03
2013-09-04 NaN <- NaN b/c date not present in orig
2013-09-05 NaN <- NaN b/c date not present in orig
2013-09-06 5.0
2013-09-07 1.0
Обратите внимание, что после этого вы можете использовать такие методы, как fillna
или interpolate
, чтобы заполнить недостающие значения по желанию.