Python 将缺少的日期添加到数据框

Python 将缺少的日期添加到数据框,python,date,plot,pandas,dataframe,Python,Date,Plot,Pandas,Dataframe,我的数据可以在给定日期有多个事件,也可以在某个日期没有事件。我把这些事件记录下来,按日期进行计数并绘制它们。然而,当我绘制它们时,我的两个系列并不总是匹配 idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max()) s = df.groupby(['simpleDate']).size() 在上面的代码中,idx成为一个范围,比如说30个日期。2013年1月9日至2013年9月30日 但是,S可能只有25或26天,因为

我的数据可以在给定日期有多个事件,也可以在某个日期没有事件。我把这些事件记录下来,按日期进行计数并绘制它们。然而,当我绘制它们时,我的两个系列并不总是匹配

idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max())
s = df.groupby(['simpleDate']).size()
在上面的代码中,idx成为一个范围,比如说30个日期。2013年1月9日至2013年9月30日 但是,S可能只有25或26天,因为给定日期内没有发生任何事件。然后我得到一个断言错误,因为当我尝试绘制时,大小不匹配:

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

您可以使用
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
...
            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
            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

这里有一个很好的方法可以将缺少的日期填充到数据框中,您可以选择
fill\u value
days\u back
来填充,以及排序顺序(
date\u 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

一个问题是,如果存在重复值,
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
屈服

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
...
            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
            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
由于重复的
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]
屈服

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
...
            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
            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
可以在列系列上使用,以在需要时填充空格。

一个更快的解决方法是使用。这不需要在
.reindex()
中创建新索引来调用


另一种方法是,它可以处理丢失日期之外的重复日期。例如:

df.resample('D').mean()
resample
是一个延迟操作,类似于
groupby
,因此您需要在它之后执行另一个操作。在这种情况下,
mean
工作正常,但您也可以使用许多其他方法,如
max
sum

这是原始数据,但有一个额外的“2013-09-03”条目:

             val
date           
2013-09-02     2
2013-09-03    10
2013-09-03    20    <- duplicate date added to OP's data
2013-09-06     5
2013-09-07     1
val
日期
2013-09-02     2
2013-09-03    10

2013-09-03 20
reindex
是一个惊人的功能。它可以(1)重新排序现有数据以匹配一组新的标签,(2)在以前不存在标签的地方插入新行,(3)填充缺少标签的数据,(包括向前/向后填充)(4)按标签选择行@这也回答了我的一个问题,谢谢!但我想知道您是否知道如何动态创建包含事件的日期的列表?不过reindex有一个问题(或bug):它不适用于1970年1月1日之前的日期,因此在本例中df.resample()工作得非常好。您可以使用它代替idx手动跳过输入开始和结束日期:
idx=pd.date\u range(df.index.min(),df.index.max())
在此处删除指向文档的链接,以节省搜索:我真的更喜欢这种方法;您不必调用
date\u range
,因为它隐式地使用第一个和最后一个索引作为开始和结束(这是您几乎总是想要的)。非常干净和专业的方法。之后使用插值也很好。我支持这种方法。这也是合并两个不同索引长度的数据帧之前使用的一种很好的方法,在合并、合并等处。几乎总是会导致错误,例如列满了NaN。谢谢你的回答,但我仍然有一个问题。鉴于我想t从日期x-x-x开始,到日期y-y-y结束,在我的数据集上,我有日期e-e-e到f-f-f,介于日期x-x-x和y-y-y之间。使用“asfreq”我如何在数据集的“s”上填写从x-x-x到y-y-y的日期?我在文档中没有找到。谢谢。如果日期列包含
空格
空值
,该怎么办?
df.loc[所有天数]
在这种情况下不起作用。传递列表喜欢.loc或[]如果丢失的标签将来会引发KeyError,您可以使用.reindex()作为替代。请参阅此处的文档: