2015-11-25 14 views
8

Sto cercando di risolvere un problema di apprendimento automatico. Ho un set di dati specifico con l'elemento serie temporale. Per questo problema sto usando la nota libreria Python - sklearn. Ci sono molti iteratori di convalida incrociati in questa libreria. Inoltre ci sono diversi iteratori per definire autonomamente la convalida incrociata. Il problema è che non so davvero come definire una semplice convalida incrociata per le serie temporali. Ecco un buon esempio di quello che sto cercando di ottenere:sklearn: Convalida incrociata definita dall'utente per i dati delle serie temporali

Supponiamo di avere diversi periodi (anni) e vogliamo dividere il nostro set di dati in blocchi diversi come segue:

data = [1, 2, 3, 4, 5, 6, 7] 

train: [1]    test: [2] (or test: [2, 3, 4, 5, 6, 7]) 
train: [1, 2]    test: [3] (or test: [3, 4, 5, 6, 7]) 
train: [1, 2, 3]   test: [4] (or test: [4, 5, 6, 7]) 
... 
train: [1, 2, 3, 4, 5, 6] test: [7] 

posso' Capisco davvero come creare questo tipo di convalida incrociata con gli strumenti di sklearn. Probabilmente dovrei usare PredefinedSplit da sklearn.cross_validation così:

train_fraction = 0.8 
train_size  = int(train_fraction * X_train.shape[0]) 
validation_size = X_train.shape[0] - train_size 

cv_split = cross_validation.PredefinedSplit(test_fold=[-1] * train_size + [1] * validation_size) 

Risultato:

train: [1, 2, 3, 4, 5] test: [6, 7] 

Ma ancora non è così buono come i dati precedenti suddivisi

+0

quali sono le variabili nel set di dati? perché è importante usare le serie temporali per dividere, perché non dividerci solo casualmente? – maxymoo

+1

È possibile generare le divisioni senza l'uso di scikit-learn, come segue: 'cv_split = [(data [: i], data [i:]) per i in range (1, len (data))]'. Cosa ne pensi? –

+0

@maxymoo, La ragione per non dividersi casualmente con i dati delle serie temporali è che il tempo potrebbe importare (non solo le altre funzionalità che hai identificato) ma "in the wild" non potrai mai addestrare il tuo modello sui dati del futuro. Pertanto, durante il test del modello, è necessario comportarsi in modo simile e non addestrare i dati dopo la/le data/e di test. – dslack

risposta

5

È possibile ottenere le spaccature convalida incrociata desiderati senza usare sklearn. Ecco un esempio

import numpy as np 

from sklearn.svm import SVR 
from sklearn.feature_selection import RFECV 

# Generate some data. 
N = 10 
X_train = np.random.randn(N, 3) 
y_train = np.random.randn(N) 

# Define the splits. 
idxs = np.arange(N) 
cv_splits = [(idxs[:i], idxs[i:]) for i in range(1, N)] 

# Create the RFE object and compute a cross-validated score. 
svr = SVR(kernel="linear") 
rfecv = RFECV(estimator=svr, step=1, cv=cv_splits) 
rfecv.fit(X_train, y_train) 
+0

Non creerà una divisione separata per ogni osservazione mentre si fa il finestrino? Se voglio diminuire questo dovrei usare il parametro 'step' nell'intervallo per farlo andare in" pezzi "più grandi? – dreyco676

+1

@ dreyco676 Proprio così. Basta usare un parametro 'step' maggiore di uno, ad esempio,' cv_splits = [(idxs [: i], idxs [i:]) per i in range (1, N, 2)] ' –

+0

Solo per essere sicuri: che StratifiedKFold è stato lasciato indietro, giusto? – paulochf

3

Nel frattempo questo è stato aggiunto alla libreria: http://scikit-learn.org/stable/modules/cross_validation.html#time-series-split

Esempio dal doc:

>>> from sklearn.model_selection import TimeSeriesSplit 

>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]]) 
>>> y = np.array([1, 2, 3, 4, 5, 6]) 
>>> tscv = TimeSeriesSplit(n_splits=3) 
>>> print(tscv) 
TimeSeriesSplit(n_splits=3) 
>>> for train, test in tscv.split(X): 
...  print("%s %s" % (train, test)) 
[0 1 2] [3] 
[0 1 2 3] [4] 
[0 1 2 3 4] [5]