2013-02-26 39 views
4

我使用Pandas 0.8.1,目前我無法更改版本。如果較新的版本能夠幫助解決以下問題,請在評論中註明而不是回答。此外,這是針對研究複製項目的,因此即使在追加一個新數據點後重新運行迴歸可能很愚蠢(如果數據集較大),我仍然必須這樣做。謝謝!累計OLS與Python Pandas

在熊貓,沒有爲window_type參數pandas.ols一個rolling選項,但似乎暗示,這需要一個窗口大小或使用整個數據樣本爲默認的一些選擇。我正在尋求以累積方式使用所有數據。

我想在日期排序的pandas.DataFrame上運行迴歸。對於每個指數i,我想使用可用數據從最低日期到指數i處的日期進行迴歸。因此,窗口在每次迭代中都有效地增長一次,所有數據都是從最早觀察中累積使用的,並且沒有數據從窗口中丟失。

我已經寫了一個函數(下)與apply一起使用來執行此操作,但它是慢得令人無法接受的。相反,有沒有辦法使用pandas.ols直接執行這種累積迴歸?

下面是關於我的數據的一些更具體的細節。我有一個pandas.DataFrame,其中包含一列標識符,一列日期,一列左側值和一列右側值。我想根據標識符使用groupby進行分組,然後對由左側和右側變量組成的每個時間段執行累積迴歸。

這是我能夠在標識分組的對象與apply使用的功能:

def cumulative_ols(
        data_frame, 
        lhs_column, 
        rhs_column, 
        date_column, 
        min_obs=60 
       ): 

    beta_dict = {} 
    for dt in data_frame[date_column].unique(): 
     cur_df = data_frame[data_frame[date_column] <= dt] 
     obs_count = cur_df[lhs_column].notnull().sum() 

     if min_obs <= obs_count: 
      beta = pandas.ols(
           y=cur_df[lhs_column], 
           x=cur_df[rhs_column], 
          ).beta.ix['x'] 
      ### 
     else: 
      beta = np.NaN 
     ### 
     beta_dict[dt] = beta 
    ### 

    beta_df = pandas.DataFrame(pandas.Series(beta_dict, name="FactorBeta")) 
    beta_df.index.name = date_column 
    return beta_df 
+0

你有看過'pd.expanding_apply()'嗎? – Zelazny7 2013-02-26 19:03:10

+0

這似乎是在一個新的版本,但我一定會看看。謝謝! – ely 2013-02-26 19:59:56

+0

@EMS如果無法升級,expanding_apply實際上只是語法糖。如果您指定rolling_apply,並且窗口大小爲整個集合的長度並且min_periods等於1,那麼您將獲得相同的展開窗口行爲 – 2013-02-27 00:23:27

回答

0

上的意見建議之後,我創建了自己的功能,可以與apply和使用依靠cumsum來累積所有個別需要的術語,用於表示來自OLS單變量回歸的係數。

def cumulative_ols(
        data_frame, 
        lhs_column, 
        rhs_column, 
        date_column, 
        min_obs=60, 
       ): 
    """ 
    Function to perform a cumulative OLS on a Pandas data frame. It is 
    meant to be used with `apply` after grouping the data frame by categories 
    and sorting by date, so that the regression below applies to the time 
    series of a single category's data and the use of `cumsum` will work  
    appropriately given sorted dates. It is also assumed that the date 
    conventions of the left-hand-side and right-hand-side variables have been 
    arranged by the user to match up with any lagging conventions needed. 

    This OLS is implicitly univariate and relies on the simplification to the 
    formula: 

    Cov(x,y) ~ (1/n)*sum(x*y) - (1/n)*sum(x)*(1/n)*sum(y) 
    Var(x) ~ (1/n)*sum(x^2) - ((1/n)*sum(x))^2 
    beta  ~ Cov(x,y)/Var(x) 

    and the code makes a further simplification be cancelling one factor 
    of (1/n). 

    Notes: one easy improvement is to change the date column to a generic sort 
    column since there's no special reason the regressions need to be time- 
    series specific. 
    """ 
    data_frame["xy"]   = (data_frame[lhs_column] * data_frame[rhs_column]).fillna(0.0) 
    data_frame["x2"]   = (data_frame[rhs_column]**2).fillna(0.0) 
    data_frame["yobs"]  = data_frame[lhs_column].notnull().map(int) 
    data_frame["xobs"]  = data_frame[rhs_column].notnull().map(int) 
    data_frame["cum_yobs"] = data_frame["yobs"].cumsum() 
    data_frame["cum_xobs"] = data_frame["xobs"].cumsum() 
    data_frame["cumsum_xy"] = data_frame["xy"].cumsum() 
    data_frame["cumsum_x2"] = data_frame["x2"].cumsum() 
    data_frame["cumsum_x"] = data_frame[rhs_column].fillna(0.0).cumsum() 
    data_frame["cumsum_y"] = data_frame[lhs_column].fillna(0.0).cumsum() 
    data_frame["cum_cov"] = data_frame["cumsum_xy"] - (1.0/data_frame["cum_yobs"])*data_frame["cumsum_x"]*data_frame["cumsum_y"] 
    data_frame["cum_x_var"] = data_frame["cumsum_x2"] - (1.0/data_frame["cum_xobs"])*(data_frame["cumsum_x"])**2 
    data_frame["FactorBeta"] = data_frame["cum_cov"]/data_frame["cum_x_var"] 
    data_frame["FactorBeta"][data_frame["cum_yobs"] < min_obs] = np.NaN 
    return data_frame[[date_column, "FactorBeta"]].set_index(date_column) 
### End cumulative_ols 

我已經在無數的測試案例證實,這是我以前的函數的輸出,並與NumPy的linalg.lstsq函數的輸出相匹配。我沒有在時間上做一個完整的基準,但有趣的是,在我一直在研究的情況下,它的速度快了大約50倍。