2017-06-06 71 views
24

我已經在已棄用的stats/ols模塊中使用了熊貓的MovingOLS類(源here)。不幸的是,它完全被熊貓0.20吞噬。大熊貓滾動迴歸:替代循環

在我看來,如何以高效的方式運行滾動OLS迴歸的問題已被多次提出(例如here),但是表達方式有點寬泛,沒有一個很好的答案。

這裏是我的問題:

  1. 我怎樣才能最好地模擬大熊貓MovingOLS的基本框架?這個類最吸引人的特點是能夠將多個方法/屬性視爲不同的時間序列 - 即,係數,r平方,t統計等,而不需要重新運行迴歸。例如,您可以創建類似model = pd.MovingOLS(y, x)的東西,然後調用.t_stat.rmse.std_err等。在下面的例子中,相反,我沒有看到被迫分別計算每個統計量的方法。是否有一種方法不涉及創建滑動/滾動「塊」(步幅)和運行迴歸/使用線性代數來獲取每個模型參數?

  2. 更廣泛地說,這是怎麼回事引擎蓋下的大熊貓,讓rolling.apply不能當你創建一個.rolling對象採取更復雜的功能*,通俗地說,內部發生了什麼的 - ?是從根本上不同循環遍歷每個窗口並創建一個更高維的數組,如下所示?

*即,func傳遞給.apply

必須從ndarray輸入*指定參數和** kwargs 被傳遞給函數

在此處,產生一個單一的值我目前正在處理一些樣本數據,迴歸利率差價和銅價的交易加權美元百分比變化。 (這並沒有多少意義,只是隨機選取了這些)。我已經將它從基於類的實現中解放出來,並嘗試將其剝離爲更簡單的腳本。

from datetime import date 
from pandas_datareader.data import DataReader 
import statsmodels.formula.api as smf 

syms = {'TWEXBMTH' : 'usd', 
     'T10Y2YM' : 'term_spread', 
     'PCOPPUSDM' : 'copper' 
     } 

start = date(2000, 1, 1) 
data = (DataReader(syms.keys(), 'fred', start) 
     .pct_change() 
     .dropna()) 
data = data.rename(columns = syms) 
data = data.assign(intercept = 1.) # required by statsmodels OLS 

def sliding_windows(x, window): 
    """Create rolling/sliding windows of length ~window~. 

    Given an array of shape (y, z), it will return "blocks" of shape 
    (x - window + 1, window, z).""" 

    return np.array([x[i:i + window] for i 
        in range(0, x.shape[0] - window + 1)]) 

data.head(3) 
Out[33]: 
       usd term_spread copper intercept 
DATE             
2000-02-01 0.012573 -1.409091 -0.019972  1.0 
2000-03-01 -0.000079  2.000000 -0.037202  1.0 
2000-04-01 0.005642  0.518519 -0.033275  1.0 

window = 36 
wins = sliding_windows(data.values, window=window) 
y, x = wins[:, :, 0], wins[:, :, 1:] 

coefs = [] 

for endog, exog in zip(y, x): 
    model = smf.OLS(endog, exog).fit() 
     # The full set of model attributes gets lost with each loop 
    coefs.append(model.params) 

df = pd.DataFrame(coefs, columns=data.iloc[:, 1:].columns, 
        index=data.index[window - 1:]) 

df.head(3) # rolling 36m coefficients 
Out[70]: 
      term_spread copper intercept 
DATE           
2003-01-01 -0.000122 -0.018426 0.001937 
2003-02-01  0.000391 -0.015740 0.001597 
2003-03-01  0.000655 -0.016811 0.001546 
+2

作爲一個基本的解決辦法,我會用你的循環和存儲您在一個通所需要的所有屬性和結果。這是我的非答案,因爲我不知道熊貓足夠了https://github.com/statsmodels/statsmodels/issues/2302#issuecomment-306389959 – user333700

+0

這是我的想法。我是一個硬核Pandas和R用戶:對於任何與迴歸有關的東西,使用R而不是Python。當然,你可以做約。同樣的事情,但Python無法匹配R的軟件包的廣度。此外,你有像「掃帚」這樣的軟件包,可以讓你輕鬆捕捉到你關心的這些迴歸統計數據,並將它們放入數據框或乳膠表中。 –

+0

MovingOLS無法正常工作,還是僅僅被刪除?你可以採取MovingOLS代碼,並有效地製作你自己的小型圖書館嗎? – BrenBarn

回答

4

我創建了一個ols模塊設計爲模擬大熊貓棄用MovingOLS;它是here

它有三個核心類:

  • OLS:靜態的(單窗口)普通最小二乘迴歸。輸出是NumPy的陣列
  • RollingOLS:軋製(多窗口)普通最小二乘迴歸。輸出是更高維的NumPy數組。
  • PandasRollingOLS:將RollingOLS的結果包裝在熊貓系列中& DataFrames。旨在模仿已棄用的熊貓模塊的外觀。

請注意,該模塊是package(現在在PyPI上)的一部分,它需要一個軟件包間導入。

第一兩類以上在NumPy的完全實現,並且主要使用矩陣代數。 RollingOLS也充分利用廣播。屬性很大程度上模仿了statsmodels的OLS RegressionResultsWrapper

一個例子:

# Pull some data from fred.stlouisfed.org 
from pandas_datareader.data import DataReader 

syms = {'TWEXBMTH' : 'usd', 
     'T10Y2YM' : 'term_spread', 
     'PCOPPUSDM' : 'copper' 
     } 
data = (DataReader(syms.keys(), 'fred', start='2000-01-01') 
     .pct_change() 
     .dropna()) 
data = data.rename(columns=syms) 
print(data.head()) 
       # usd term_spread copper 
# DATE          
# 2000-02-01 0.01260  -1.40909 -0.01997 
# 2000-03-01 -0.00012  2.00000 -0.03720 
# 2000-04-01 0.00564  0.51852 -0.03328 
# 2000-05-01 0.02204  -0.09756 0.06135 
# 2000-06-01 -0.01012  0.02703 -0.01850 

# Rolling regressions 

from pyfinance.ols import OLS, RollingOLS, PandasRollingOLS 

y = data.usd 
x = data.drop('usd', axis=1) 

window = 12 # months 
model = PandasRollingOLS(y=y, x=x, window=window) 

print(model.beta.head()) # Coefficients excluding the intercept 
      # term_spread copper 
# DATE        
# 2001-01-01  0.00010 0.05568 
# 2001-02-01  0.00047 0.06271 
# 2001-03-01  0.00147 0.03576 
# 2001-04-01  0.00161 0.02956 
# 2001-05-01  0.00158 -0.04497 

print(model.fstat.head()) 
# DATE 
# 2001-01-01 0.28121 
# 2001-02-01 0.42602 
# 2001-03-01 0.38802 
# 2001-04-01 0.39230 
# 2001-05-01 0.41706 
# Freq: MS, Name: fstat, dtype: float64 

print(model.rsq.head()) # R-squared 
# DATE 
# 2001-01-01 0.05882 
# 2001-02-01 0.08648 
# 2001-03-01 0.07938 
# 2001-04-01 0.08019 
# 2001-05-01 0.08482 
# Freq: MS, Name: rsq, dtype: float64 
+1

這種方法的主要問題是保持所有OLS實例需要大量內存。 – user333700

+0

@ user333700如果您有興趣看一下,我已經做了一些重大更改,應該對內存更友善。 –