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 20reindex
是一个惊人的功能。它可以(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()作为替代。请参阅此处的文档: