[PYTHON] Vergleich von Regressionsmodellen - ARMA vs. Random Forest Regression

(Zusatz) In der zweiten Hälfte dieses Artikels habe ich einen Korrekturartikel über Random Rorest Regression veröffentlicht. Siehe auch hier. Was Sie bei der Analyse von Zeitreihendaten (einschließlich Reflexion) nicht tun sollten

Bei der Durchführung von Zeitreihendatenanalysen mit Python ist möglicherweise das von StatsModels für die statistische Modellierung bereitgestellte Modul zur Analyse von Zeitreihen (tsa) die erste Option. Darüber hinaus verfügt die maschinelle Lernbibliothek Scikit-learn über Decision Tree Regression und Random Forest Regression, die Regressionen basierend auf verschiedenen Konzepten durchführen. Daher wollte ich diese ebenfalls ausprobieren und vergleichen.

(Programmierumgebung: Python 2.7.11, Pandas 0.18.0, StatsModels 0.6.1, Scikit-learn 0.17.1.)

Eine Gruppe traditioneller Selbstrückgabemodelle

Wenn Sie die Literatur zur Zeitreihendatenanalyse öffnen, werden die Erklärungen häufig in der folgenden Reihenfolge angezeigt.

Abkürzung Erläuterung
AR Selbstrückkehr(Auto Regression)Modell-
MA gleitender Durchschnitt(Moving Average)Modell-
ARMA Selbstkehrendes Modell mit gleitendem Durchschnitt
ARIMA Modell des gleitenden Durchschnitts der Selbstrückgabesumme

Einzelheiten zu jedem Modell finden Sie in Wikipedia usw. Grundsätzlich ist ** ARMA ** ein Modell, das ** AR ** und ** MA ** enthält, und ** ARIMA ** ist * Da es sich um ein Modell handelt, das * ARMA ** enthält, können alle oben genannten vier Modelle unterstützt werden, wenn ** ARIMA ** als Bibliothek unterstützt wird. StatsModels bietet jedoch ** AR **, ** ARMA **, ** ARIMA ** als APIs.

http://statsmodels.sourceforge.net/stable/tsa.html

Dieses Mal wurde "Nil" als zu analysierende Daten verwendet.

Nile River flows at Ashwan 1871-1970 This dataset contains measurements on the annual flow of the Nile as measured at Ashwan for 100 years from 1871-1970. There is an apparent changepoint near 1898.

Dies sind die jährlichen Daten des Nilflusses in Afrika und die Beispieldaten, die in der StatsModel-Bibliothek erstellt wurden.

Nile_1.png

In vielen Fällen ist "Stationarität" eine Voraussetzung für die Anwendung des Modells im Self-Return-Modell. Da das obige Diagramm jedoch keine monotone Zunahme oder Abnahme zeigt, haben wir uns für die Anwendung des ** ARMA ** -Modells entschieden. Machen.

Auswahl der ARMA-Modellreihenfolge

Da es sich um Zeitreihendaten für etwa 100 Jahre handelt, werden wir 70 Jahre für die erste Hälfte als Daten für die Anpassung (für die Ausbildung) und 30 Jahre für die zweite Hälfte als Daten für die Modellprüfung zuweisen. Es ist notwendig, die Reihenfolge (p, q) des ARMA-Modells auszuwählen. Zeichnen wir zunächst das ACF-Diagramm (Autokorrelationsfunktionsdiagramm) und das PACF-Diagramm (partielles Autokorrelationsdiagramm), die auch als Cholerogramme bezeichnet werden.

def load_data():
    df_read = sm.datasets.nile.load_pandas().data
    s_date = pd.Series(
        [pd.to_datetime(str(int(y_str))) for y_str in df_read['year']]
    )
    df = df_read.set_index(s_date)
    df = df.drop('year', axis=1)
    
    return df

df_nile = load_data()

# Plot Time Series Data
ax = df_nile['volume'].plot(figsize=(8,4), grid=True)
ax.set_xlabel('year')
ax.set_ylabel('volume x 10^8 m^3')
plt.show()

# Data Split (70: 30)
# ACF, PACF
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(211)
fig = sm.graphics.tsa.plot_acf(df_train.values, lags=40, ax=ax1)
ax2 = fig.add_subplot(212)
fig = sm.graphics.tsa.plot_pacf(df_train.values, lags=40, ax=ax2)

Fig. ACF and PACF plot of "Nile" data Nile_2.png

In ARMA (p, q) kann q = [0, 1, 2, 3] aus dem ACF-Diagramm (oben) und p = [0, 1] aus dem PACF-Diagramm (unten) ausgewählt werden ( Irgendwie verstehe ich. Unter Berücksichtigung der Tatsache, dass ARMA (p = 1, q = 3) berücksichtigt wird und die Informationen vom Dienstprogramm zur Auftragsauswahl ausgegeben werden, ist das Ergebnis vorerst wie folgt.

info_criteria = sm.tsa.stattools.arma_order_select_ic(
                    df_train.values, ic=['aic', 'bic']
                )
print(info_criteria.aic_min_order)
print(info_criteria.bic_min_order)

ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  "Check mle_retvals", ConvergenceWarning)
>>> (1, 1)
>>> (1, 0)

Beachten Sie, dass eine Warnung zur Konvergenz angezeigt wird. Basierend auf der Warnung haben wir Informationen erhalten, dass ARMA (1, 1) von AIC (Modellauswahlreferenzwert) und AMMA (1, 0) von BIC (Modellauswahlreferenzwert) gut ist. Passen wir daher diese beiden Modelle an die Daten an.

arma_10 = sm.tsa.ARMA(df_train, (1, 0)).fit()
arma_11 = sm.tsa.ARMA(df_train, (1, 1)).fit()

Dies wurde ohne besonderen Fehler oder Warnung verarbeitet. Die Rückgabewerte arma_10 und arma_11 sind nach dem Anpassen Modellobjekte (ARMAResults-Klasse). Vorerst habe ich auch Modelle höherer Ordnung ARMA (1, 2) und ARMA (1, 3) ausprobiert.

arma_12 = sm.tsa.ARMA(df_train, (1, 2)).fit()
arma_13 = sm.tsa.ARMA(df_train, (1, 3)).fit()

(Ausgelassen, Traceback-Informationen usw.)

ValueError: The computed initial AR coefficients are not stationary
You should induce stationarity, choose a different model order, or you can
pass your own start_params.

Der obige Wertefehler ist aufgetreten. (Obwohl in der Fehlermeldung stationär erwähnt wird ...) Es gibt ein Problem mit der Konvergenz bei der Berechnung von Parametern, und es ist schwierig, auf ARMA (1, 2) und ARMA (1, 3) anzuwenden. Gibt es. In Zukunft wird diese Ursache möglicherweise eingehend untersucht, aber dieses Mal lautet das Thema ARMA vs. Random Forest Regressor. Daher werden wir die Verwendung von ARMA (1, 0) und ARMA (1, 1) in Betracht ziehen, die angepasst werden können. Vorgehen.

Validierung des ARMA-Modells

Überprüfen Sie zunächst den Wert von AIC.

print('ARMA(1,0): AIC = %.2f' % arma_10.aic)
print('ARMA(1,1): AIC = %.2f' % arma_11.aic)
>>> ARMA(1,0): AIC = 910.94
>>> ARMA(1,1): AIC = 908.92

Der AIC-Wert ist im ARMA-Modell (1, 1) kleiner.

Als nächstes werden die Modellschätzungen für den Trainingsdatenabschnitt (70 Jahre) und die Modellschätzungen für den nachfolgenden Testabschnitt (30 Jahre) berechnet.

# in-sample predict
arma_10_inpred = arma_10.predict(start='1871-01-01', end='1940-01-01')
arma_11_inpred = arma_11.predict(start='1871-01-01', end='1940-01-01')

# out-of-sample predict
arma_10_outpred = arma_10.predict(start='1941-01-01', end='1970-01-01')
arma_11_outpred = arma_11.predict(start='1941-01-01', end='1970-01-01')

Sowohl die AIC-Berechnung als auch die Schätzwertberechnung können nach der Methode der ARMA-Modellergebnisklasse (ARMAResults-Klasse) erhalten werden. Zeichnen Sie die Werte der Originaldaten und die geschätzten Werte zusammen.

# plot data and predicted values
def plot_ARMA_results(origdata, pred10in, pred10out, pred11in, pred11out):
    px = origdata.index
    py1 = origdata.values
    plt.plot(px, py1, 'b:', label='orig data')
    
    px_in = pred10in.index
    plt.plot(px_in, pred10in.values, 'g')
    plt.plot(px_in, pred11in.values, 'c')
    
    px_out = pred10out.index
    plt.plot(px_out, pred10out.values, 'g', label='ARMA(1,0)')
    plt.plot(px_out, pred11out.values, 'c', label='ARMA(1,1)')
    
    plt.legend()
    plt.grid(True)
    plt.show()

plot_ARMA_results(df_nile, arma_10_inpred, arma_10_outpred, 
    arma_11_inpred, arma_11_outpred)

Fig. Nile data - original data and ARMA estimated data Nile_3.png

Der Trainingsabschnitt (In-Sample) ist von 1870 bis 1940, und der Testabschnitt (Out-of-Sample) ist danach. Es ist ein wenig schwer zu verstehen, aber irgendwie scheint ARMA (1,1) näher an den tatsächlichen Daten zu sein. MSE (Mean Squared Error) wird aus den Residuen für den späteren Modellvergleich erhalten.

# Residue (mse for train) 
arma_10_mse_tr = np.array([r ** 2 for r in arma_10.resid]).mean()
arma_11_mse_tr = np.array([r ** 2 for r in arma_11.resid]).mean()

# Residue (mse for test)
arma_10_mse_te = np.array([(df_test.values[i] - arma_10_outpred[i]) **2 
                            for i in range(30)]).mean()
arma_11_mse_te = np.array([(df_test.values[i] - arma_11_outpred[i]) **2 
                            for i in range(30)]).mean()

Zufällige Waldrückgabe

Die Grundlage der Random Forest-Regression ist die Decision Tree Regression. Es scheint, dass der Entscheidungsbaumalgorithmus selbst grob verstanden werden muss, aber in diesem Artikel wird die Erklärung weggelassen und die Funktion von Scikit-learn wird als Black Box behandelt. Es gibt ein Beispiel im Scikit-Lerndokument, aber das Ergebnis des Versuchs wird unten gezeigt.

Fig. Decision Tree Regression Example tree_regression_s.png

Das Merkmal ist, dass es in eine gestufte gerade Linie passt. Diesmal handelt es sich um univariate Zeitreihendaten, aber ich habe versucht, den aktuellen Wert anhand einiger früherer Daten als Modell zu schätzen. Speziell, Volume_current ~ Volume_Lag1 + Volume_Lag2 + Volume_Lag3 Dies ist das Modell. Ich wollte die Trainingsdaten und Testdaten wie beim letzten Mal (70, 30) machen, aber da NaN bei der Berechnung des Lag-Werts erscheint, dropna () den ersten Teil und setze die Datenlänge auf (67, 30). tat.

Zunächst werden Daten vorverarbeitet.

df_nile['lag1'] = df_nile['volume'].shift(1) 
df_nile['lag2'] = df_nile['volume'].shift(2)
df_nile['lag3'] = df_nile['volume'].shift(3)

df_nile = df_nile.dropna()

X_train = df_nile[['lag1', 'lag2', 'lag3']][:67].values
X_test = df_nile[['lag1', 'lag2', 'lag3']][67:].values

y_train = df_nile['volume'][:67].values
y_test = df_nile['volume'][67:].values

Verwenden Sie Random Forest Regressor von Scikit-learn.

from sklearn.ensemble import RandomForestRegressor
r_forest = RandomForestRegressor(
            n_estimators=100,
            criterion='mse',
            random_state=1,
            n_jobs=-1
)
r_forest.fit(X_train, y_train)
y_train_pred = r_forest.predict(X_train)
y_test_pred = r_forest.predict(X_test)

Die geschätzten Werte sind in der folgenden Abbildung dargestellt.

Fig. Nile data - original data and Random Forest Regression results Nile_4.png

Berechnen Sie abschließend MSE.

# check residue (mse)
train_resid = y_train - y_train_pred
RFR_mse_train = np.array([r ** 2 for r in train_resid]).mean()
test_resid = y_test - y_test_pred
RFR_mse_test = np.array([r ** 2 for r in test_resid]).mean()

Modellgenauigkeitsvergleich

Vergleichen Sie die MSE (Mean Squared Error) jedes Modells.

Model MSE of in-samle (train) MSE of out-of-sample (test)
ARMA(1,0) 24111.0 18684.4
ARMA(1,1) 22757.3 16625.8
Random F. Regressor 3470.1 15400.3

(MSE : smaller ... better)

Beim Vergleich von ARMA-Modellen mit unterschiedlichen Ordnungen ist ersichtlich, dass ARMA (1,1) sowohl im Trainingsabschnitt als auch im Testabschnitt eine kleinere MSE und eine bessere Genauigkeit aufweist, was mit dem Vergleich der zuvor erhaltenen AIC-Werte übereinstimmt. Es gibt.

Im Vergleich zwischen dem ARMA-Modell und dem Random Forest-Regressionsmodell ist die MSE der Random Forest-Regression klein, mit einem großen Unterschied im Trainingsabschnitt. Die Random Forest-Regression ist im Testabschnitt ebenfalls gering, der Unterschied beträgt jedoch etwa 7%. Die zufällige Waldregression ist hinsichtlich der Genauigkeit vorteilhaft, es sollte jedoch berücksichtigt werden, dass das ARMA-Modell, auf das das statistische Modell angewendet wird, zusätzlich zum vorhergesagten Medianwert Informationen zum Konfidenzintervall (z. B. 95% -Konfidenzintervall) erhalten kann. Ist fertig. Ich möchte es entsprechend dem Zweck richtig verwenden.

(Beim Vergleich der Diagramme der ARMA- und Random Forest-Regression war ich erneut überrascht, dass die Linien sehr unterschiedlich aussehen. Beachten Sie auch, dass keines der Modelle ausreichende Parameteranpassungen hatte. Bitte gib mir.)

Referenzen (Website)

Recommended Posts

Vergleich von Regressionsmodellen - ARMA vs. Random Forest Regression
Zufälliger Wald (2)
Zufälliger Wald
Regression mit einem linearen Modell
Balanced Random Forest in Python
Ich habe versucht, RandomForest zu verwenden
[Maschinelles Lernen] Zufällige Gesamtstruktur verstehen
Entscheidungsbaum und zufälliger Wald
Verwenden Sie Random Forest mit Python
Maschinelles Lernen: Überwacht - Zufälliger Wald