pandas 将缺失日期添加到panda Dataframe

hec6srdp  于 2022-12-21  发布在  其他
关注(0)|答案(7)|浏览(170)

我的数据可以在给定日期有多个事件,也可以在某个日期没有事件。我获取这些事件,按日期获得计数,然后绘制它们。但是,在绘制它们时,我的两个系列并不总是匹配。

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函数吗?
下面是Sdf.groupby(['simpleDate']).size())的一个代码片段,注意没有04和05的条目。

09-02-2013     2
09-03-2013    10
09-06-2013     5
09-07-2013     1
c86crjj0

c86crjj01#

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

2w2cym1i2#

更快的解决方法是使用.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
6za6bjd0

6za6bjd03#

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

(by这意味着索引有重复项,而不是它本身是一个重复项)
相反,我们可以使用.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可用于列系列以填充空白(如果需要)。

9njqaruj

9njqaruj4#

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

df.resample('D').mean()

resamplegroupby一样是一个延迟操作,所以你需要在它后面执行另一个操作,在这种情况下mean可以很好地工作,但是你也可以使用许多其他的panda方法,比如maxsum,等等。
以下是原始数据,但添加了"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
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

我将缺失的日期保留为NaNs,以说明这是如何工作的,但是您可以添加fillna(0),以便按照OP的要求用零替换NaNs,或者使用类似interpolate()的内容,根据相邻行填充非零值。

f8rj6qna

f8rj6qna5#

这里有一个很好的方法来填充缺失的日期到一个 Dataframe 中,你可以选择fill_valuedays_back来填充,以及排序顺序(date_order)来排序 Dataframe :

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
i5desfxk

i5desfxk6#

您可以始终只使用DataFrame.merge(),利用从“所有日期”数据框到“缺少日期”数据框的左联接。示例如下。

# example DataFrame with missing dates between min(date) and max(date)
missing_df = pd.DataFrame({
    'date':pd.to_datetime([
        '2022-02-10'
        ,'2022-02-11'
        ,'2022-02-14'
        ,'2022-02-14'
        ,'2022-02-24'
        ,'2022-02-16'
    ])
    ,'value':[10,20,5,10,15,30]
})

# first create a DataFrame with all dates between specified start<-->end using pd.date_range()
all_dates = pd.DataFrame(pd.date_range(missing_df['date'].min(), missing_df['date'].max()), columns=['date'])

# from the all_dates DataFrame, left join onto the DataFrame with missing dates
new_df = all_dates.merge(right=missing_df, how='left', on='date')
6xfqseft

6xfqseft7#

s.asfreq('D').interpolate().asfreq('Q')

相关问题