2013-10-11 160 views
48

我的數據可能在給定日期有多個事件,或者在某個日期沒有事件。我採取這些事件,按日期計算並繪製它們。但是,當我繪製它們時,我的兩個系列並不總是匹配。將缺失的日期添加到熊貓數據框中

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的日期添加到系列中。我寧願使用0值的30天完整圖表。如果這種方法是正確的,有關如何開始的任何建議?我需要某種動態reindex功能嗎?

這裏的小號df.groupby(['simpleDate']).size())的片段,發現沒有條目04和05

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

回答

115

你可以使用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 
... 
+2

哇謝謝!我並不完全瞭解重建索引的效果。 – KHibma

+12

'reindex'是一個了不起的功能。它可以(1)重新排序現有數據以匹配一組新標籤,(2)插入之前沒有標籤的新行,(3)填充丟失標籤的數據(包括前向/後向填充)(4)選擇行按標籤! – unutbu

+0

@unutbu這回答我也有一個問題的一部分,謝謝!但是想知道你是否知道如何動態地創建包含事件日期的列表? –

2

這裏有一個很好的方法來填補缺失的日期一個數據幀,與您選擇的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 
11

的一個問題是,如果有重複的值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 

(這個就意味着指數有重複,不在於它本身是一個DUP)

相反,我們可以使用.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可用於色譜柱系列填充空白(如果需要)。

6

更快的解決方法是使用asfreq()。這並不需要創建新的索引到用戶中reindex()調用。*

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 

*至少不是。這很好,可以在引擎蓋下調用。

2

在很多情況下,resample(see documentation here)提供了一個通用的解決方案,可以處理缺失日期和重複日期。例如:

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

resample是延遲操作像groupby所以你需要使用另一個操作遵循它。在這情況下mean效果很好,但你也可以使用許多標準的大熊貓方法有像maxsum

這裏是原始數據,但與「2013年9月3日」額外的條目:

  val 
date   
2013-09-02 2 
2013-09-03 10 
2013-09-03 20 
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 

注意,在此之後,你可以使用像fillnainterpolate方法根據需要來填補缺失值。