pandas填充时间序列中的缺失日期

39
我有一个数据框,其中包含了几天的聚合数据。我想添加缺失的日期。
我参考了另一篇文章 Add missing dates to pandas dataframe,但不幸的是,它覆盖了我的结果(可能功能稍微有所改变)... 代码如下:
import random
import datetime as dt
import numpy as np
import pandas as pd

def generate_row(year, month, day):
    while True:
        date = dt.datetime(year=year, month=month, day=day)
        data = np.random.random(size=4)
        yield [date] + list(data)

# days I have data for
dates = [(2000, 1, 1), (2000, 1, 2), (2000, 2, 4)]
generators = [generate_row(*date) for date in dates]

# get 5 data points for each
data = [next(generator) for generator in generators for _ in range(5)]

df = pd.DataFrame(data, columns=['date'] + ['f'+str(i) for i in range(1,5)])

# df
groupby_day = df.groupby(pd.PeriodIndex(data=df.date, freq='D'))
results = groupby_day.sum()

idx = pd.date_range(min(df.date), max(df.date))
results.reindex(idx, fill_value=0)

填补缺失日期索引前的结果
这里输入图片描述

填补缺失日期索引后的结果
这里输入图片描述


1
也许你要找的是重新采样(resample)? - cs95
看起来很有前途,但我在尝试从文档中应用它时遇到了困难。 - Alter
2
我想我懂了... df.set_index(df.date, inplace=True) + df = df.resample('D').sum() 这非常方便。 - Alter
没错。如果它能正常工作,把它写成答案,我会给你点赞的。 - cs95
3个回答

50
你需要使用 period_range 而不是 date_range:
In [11]: idx = pd.period_range(min(df.date), max(df.date))
    ...: results.reindex(idx, fill_value=0)
    ...:
Out[11]:
                  f1        f2        f3        f4
2000-01-01  2.049157  1.962635  2.756154  2.224751
2000-01-02  2.675899  2.587217  1.540823  1.606150
2000-01-03  0.000000  0.000000  0.000000  0.000000
2000-01-04  0.000000  0.000000  0.000000  0.000000
2000-01-05  0.000000  0.000000  0.000000  0.000000
2000-01-06  0.000000  0.000000  0.000000  0.000000
2000-01-07  0.000000  0.000000  0.000000  0.000000
2000-01-08  0.000000  0.000000  0.000000  0.000000
2000-01-09  0.000000  0.000000  0.000000  0.000000
2000-01-10  0.000000  0.000000  0.000000  0.000000
2000-01-11  0.000000  0.000000  0.000000  0.000000
2000-01-12  0.000000  0.000000  0.000000  0.000000
2000-01-13  0.000000  0.000000  0.000000  0.000000
2000-01-14  0.000000  0.000000  0.000000  0.000000
2000-01-15  0.000000  0.000000  0.000000  0.000000
2000-01-16  0.000000  0.000000  0.000000  0.000000
2000-01-17  0.000000  0.000000  0.000000  0.000000
2000-01-18  0.000000  0.000000  0.000000  0.000000
2000-01-19  0.000000  0.000000  0.000000  0.000000
2000-01-20  0.000000  0.000000  0.000000  0.000000
2000-01-21  0.000000  0.000000  0.000000  0.000000
2000-01-22  0.000000  0.000000  0.000000  0.000000
2000-01-23  0.000000  0.000000  0.000000  0.000000
2000-01-24  0.000000  0.000000  0.000000  0.000000
2000-01-25  0.000000  0.000000  0.000000  0.000000
2000-01-26  0.000000  0.000000  0.000000  0.000000
2000-01-27  0.000000  0.000000  0.000000  0.000000
2000-01-28  0.000000  0.000000  0.000000  0.000000
2000-01-29  0.000000  0.000000  0.000000  0.000000
2000-01-30  0.000000  0.000000  0.000000  0.000000
2000-01-31  0.000000  0.000000  0.000000  0.000000
2000-02-01  0.000000  0.000000  0.000000  0.000000
2000-02-02  0.000000  0.000000  0.000000  0.000000
2000-02-03  0.000000  0.000000  0.000000  0.000000
2000-02-04  1.856158  2.892620  2.986166  2.793448
这是因为您的groupby使用的是PeriodIndex,而不是datetime:
df.groupby(pd.PeriodIndex(data=df.date, freq='D'))
你本可以使用 pd.Grouper
df.groupby(pd.Grouper(key="date", freq='D'))

这将会给出一个日期时间索引。


23

根据cᴏʟᴅsᴘᴇᴇᴅ在评论中的提示:


resample 在此处很适用。

Resample:频率转换和时间序列重新取样的便捷方法。对象必须具有类似于日期时间的索引(DatetimeIndex、PeriodIndex 或 TimedeltaIndex),或将类似日期时间的值传递给 on 或 level 关键字。

import random
import datetime as dt
import numpy as np
import pandas as pd

def generate_row(year, month, day):
    while True:
        date = dt.datetime(year=year, month=month, day=day)
        data = np.random.random(size=4)
        yield [date] + list(data)

# days I have data for
dates = [(2000, 1, 1), (2000, 1, 2), (2000, 2, 4)]
generators = [generate_row(*date) for date in dates]

# get 5 points for each
data = [next(generator) for generator in generators for _ in range(5)]

# make dataframe
df = pd.DataFrame(data, columns=['date'] + ['f'+str(i) for i in range(1,5)])

# using the resample method
df.set_index(df.date, inplace=True)
df = df.resample('D').sum().fillna(0)

enter image description here


2
你有一些很棒的编辑技巧,我甚至不知道你可以链接到评论。 - Alter
2
谢谢...我觉得将评论链接到我的个人资料比较合适;-) - cs95
2
可以像上面那样做,但不对数据求和,在存在多个数据点的日期保留数据本身是否可能?例如,1月1日有5个数据点,2月2日有5个数据点,但是第3个数据点只是0? - spiff
1
没关系,这很简单,只需要使用外连接合并日期序列(转换为DataFrame)即可 - 非常感谢! - spiff

2

你可以参考下面的代码链接来填补时间序列数据中的缺失日期,并查找缺失日期,你可以参考下面的代码。

** 代码在 YYYY-MM-DD 格式上进行了测试。请查看下面的链接以获取完整的代码。

#fill missing dates in dataframe and return dataframe object
# tested on only YYYY-MM-DD format
# ds=fill_in_missing_dates(ds,date_col_name='Date')
# ds= dataframe object
# date_col_name= col name in your dataframe, has datevalue
def fill_in_missing_dates(df, date_col_name = 'date',fill_val = 
np.nan,date_format='%Y-%m-%d'):
  df.set_index(date_col_name,drop=True,inplace=True)
  df.index = pd.to_datetime(df.index, format = date_format)
  idx = pd.date_range(df.index.min(), df.index.max())
  print('missing_dates are',idx.difference(df.index))
  df=df.reindex(idx,fill_value=fill_val)...

https://github.com/n-idhisharma/mywork/blob/09942f15f6859e94e5dbb9fcb1af05ac7f627b06/Py_filling_missing_dates


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接