2013-11-01 17 views
3

我有一個大型熊貓數據框(約1300萬行),其中包含各種項目的數據,每個項目都有來自不同月份的觀察數據。這些項目隨着相應行數(即觀察數據的月份)而變化,並且月份可能連續也可能不連續。一個高度簡化abbreivated樣品:減少複雜熊貓重新索引任務的內存使用量

      x   y 
item_id date 
4  2006-01-01 5.69368 0.789752 
     2006-02-01 5.67199 0.786743 
     2006-03-01 5.66469 0.783626 
     2006-04-01 5.69427 0.782596 
     2006-05-01 5.70198 0.781670 
5  2006-05-01 3.16992 1.000000 
     2006-07-01 3.25000 0.978347 

我需要完成的數據如下所示:對於每個項目,向前填充從第一觀測行觀察該項目指定的最大時間。因此,給定上述示例,期望的輸出是下面的:

      x   y 
item_id 
4  2006-01-01 5.69368 0.789752 
     2006-02-01 5.67199 0.786743 
     2006-03-01 5.66469 0.783626 
     2006-04-01 5.69427 0.782596 
     2006-05-01 5.70198 0.781670 
     2006-06-01 5.70198 0.781670 
     2006-07-01 5.70198 0.781670 
     2006-08-01 5.70198 0.781670 
     2006-09-01 5.70198 0.781670 
     2006-10-01 5.70198 0.781670 
     2006-11-01 5.70198 0.781670 
     2006-12-01 5.70198 0.781670 
5  2006-05-01 3.16992 1.000000 
     2006-06-01 3.16992 1.000000 
     2006-07-01 3.25000 0.978347 
     2006-08-01 3.25000 0.978347 
     2006-09-01 3.25000 0.978347 
     2006-10-01 3.25000 0.978347 
     2006-11-01 3.25000 0.978347 
     2006-12-01 3.25000 0.978347 

爲了便於進一步的分析,然後我需要的時間索引轉換爲一個簡單數字索引(我們稱之爲「SEQ」),例如最終的結果是:

    x   y 
item_id seq 
4  0 5.69368 0.789752 
     1 5.67199 0.786743 
     2 5.66469 0.783626 
     3 5.69427 0.782596 
     4 5.70198 0.781670 
     5 5.70198 0.781670 
     6 5.70198 0.781670 
     7 5.70198 0.781670 
     8 5.70198 0.781670 
     9 5.70198 0.781670 
     10 5.70198 0.781670 
     11 5.70198 0.781670 
5  0 3.16992 1.000000 
     1 3.16992 1.000000 
     2 3.25000 0.978347 
     3 3.25000 0.978347 
     4 3.25000 0.978347 
     5 3.25000 0.978347 
     6 3.25000 0.978347 
     7 3.25000 0.978347 

(這點的目的是讓我平均第一,第二,...,第n個觀測項目)。在任何情況下,我有一個解決方案,這是工作正常,如果我操作僅在數據的子集:

df = pd.read_table(filename,sep='\s*',header=None,names=['item_id','date','x','y'],index_col=['item_id','date'],parse_dates='date') 
maxDate = '2006-12-01' 
def switchToSeqIndex(df): 
    minDate = df.index[0][1] # get the first observed date 
    return df.reset_index(level='item_id',drop=True).reset_index(). \ 
      set_index('date').reindex(pd.date_range(minDate,maxDate,freq='MS'), \ 
      method='ffill').reset_index('date',drop=True) 
df_fixed = df.groupby(level='item_id').apply(switchToSeqIndex) 
df_fixed.index.names[1]='seq' 

原則上,這是偉大的,併產生正確的輸出,但是當我嘗試執行在整個數據集上運行(1300萬行,通過重新索引擴展了大量數據),內存使用量失控(使用20gb RAM撞擊機器)。

我的問題,那麼,我是如何做到這一點,同時減少我的記憶開銷。我認爲問題是嘗試使用groupby/apply方法執行重新索引,但我不知道替代方法。似乎應該有辦法,我可以做類似的迭代,需要更少的內存,但我不知道如何去做。

+0

不要做這一切在內存中。用HFDStore寫你的表。將它重新讀回塊,處理並寫入一個新文件,查看幾個非常類似的問題[here](http://pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore) – Jeff

回答

0

我會通過創建一個DataFrame來解決這個問題,它只包含所需的全部日期。然後按ID分組原始的DataFrame,並使用outer加入日期-DataFrame,以吸引任何缺失的日期(因此,xy對於日期必須通過連接拉入的行,將爲NaN)。

之後,通過ID組,按日期排序以任何順序你需要它,然後只需使用普通的調用fillna轉發填補所有在xy列NaN值。

我已經完成了這樣的任務,其中DataFrame s之前有超過2億行(在有12 GB RAM的系統上),是的,這不是瞬時的,但它也不夠慢。

一些僞代碼:

df = your_current_df.reset_index().set_index("item_id") 
# Or, use something smarter with unstack(level=1) and possibly some 
# in-place option. 

# I assume this puts the dates into a regular column called 'date' 

# Do stuff to make all the dates you could possibly need 
dates_df = pandas.DataFrame(...) 

df = pandas.merge(df, dates_df, left_on="date", right_on="date", how="outer") 
df.sort("date", ascending=True, inplace=True) 
df.groupby("item_id").fillna(method="ffill") 
+0

我喜歡這個原則上,但似乎並不奏效。這裏是我迅速掀起的ipython筆記本,它說明了我嘗試使用你的方法,並比較了它的原始方法:https://www.dropbox.com/s/hdfl4qcqhst4wzs/Scratch2.html – moustachio