为pandas数据帧添加缺少日期

KHi*_*bma 95 python plot date dataframe pandas

我的数据可以在给定日期有多个事件,也可以在某个日期没有事件.我参加这些活动,按日期计算并绘制它们.但是,当我绘制它们时,我的两个系列并不总是匹配.

idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max())
s = df.groupby(['simpleDate']).size()
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,idx成为30个日期的范围.S 01-01-2013至09-30-2013但是S可能只有25天或26天,因为在给定日期没有发生任何事件.然后,当我尝试绘制时,我得到一个AssertionError,因为大小不匹配:

fig, ax = plt.subplots()    
ax.bar(idx.to_pydatetime(), s, color='green')
Run Code Online (Sandbox Code Playgroud)

解决这个问题的正确方法是什么?我是否要删除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
Run Code Online (Sandbox Code Playgroud)

unu*_*tbu 206

你可以使用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)
Run Code Online (Sandbox Code Playgroud)

产量

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
...
Run Code Online (Sandbox Code Playgroud)

  • `reindex`是一个了不起的功能.它可以(1)重新排序现有数据以匹配一组新标签,(2)插入以前不存在标签的新行,(3)填充缺失标签的数据,(包括通过向前/向后填充)(4)选择行按标签! (17认同)
  • 您可以使用它来代替 idx 跳过手动输入开始和结束日期:`idx = pd.date_range(df.index.min(), df.index.max())` (3认同)
  • 但是,重新索引存在一个问题(或错误):它不适用于1970年1月1日之前的日期,因此在这种情况下df.resample()可以完美地工作。 (2认同)
  • 删除此处文档的链接,以节省搜索:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.reindex.html (2认同)
  • 重新索引至少不再起作用了 (2认同)

Bra*_*mon 29

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

# "broken" (staggered) dates
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
Run Code Online (Sandbox Code Playgroud)

  • 我真的更喜欢这种方法;您可以避免调用“date_range”,因为它隐式使用第一个和最后一个索引作为开始和结束(这几乎是您想要的)。 (3认同)
  • 感谢您的回答,但我还有一个问题。鉴于我想在日期 xxx 开始并在日期 yyy 结束,并且在我的数据集上,我有日期 eee 到 fff,它们位于日期 xxx 和 yyy 之间。使用“asfreq”如何填写数据集上从 xxx 到 yyy 的日期?我在文档上没有找到。谢谢 (2认同)

小智 23

一个问题是,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
Run Code Online (Sandbox Code Playgroud)

产量

            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
Run Code Online (Sandbox Code Playgroud)

由于重复2016-11-16日期,尝试重新索引:

all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')
df.reindex(all_days)
Run Code Online (Sandbox Code Playgroud)

失败了:

...
ValueError: cannot reindex from a duplicate axis
Run Code Online (Sandbox Code Playgroud)

(这意味着索引有重复,而不是它本身就是重复)

相反,我们可以使用.loc查找范围内所有日期的条目:

df.loc[all_days]
Run Code Online (Sandbox Code Playgroud)

产量

            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
Run Code Online (Sandbox Code Playgroud)

fillna 如果需要,可以在列系列上使用以填充空白.

  • 将 list-likes 传递给 .loc 或 [] 并缺少任何标签将在将来引发 KeyError,您可以使用 .reindex() 作为替代方案。请参阅此处的文档:https://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlike (2认同)

Joh*_*hnE 15

另一种方法是resample,除了缺少日期外,还可以处理重复日期.例如:

df.resample('D').mean()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

以下是结果:

             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
Run Code Online (Sandbox Code Playgroud)

我将缺少的日期留作NaN来清楚它是如何工作的,但你可以添加fillna(0)用OP请求用零替换NaN,或者使用类似的东西interpolate()来填充基于相邻行的非零值.


eiT*_*aVi 8

这是一种将缺失日期填充到数据帧中的好方法,您可以选择fill_valuedays_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
Run Code Online (Sandbox Code Playgroud)