2015-11-25 19 views
8

Próbuję rozwiązać problem uczenie maszynowego. Mam określony zestaw danych z elementem time-series. Do tego problemu używam dobrze znanej biblioteki Pythona - sklearn. W tej bibliotece znajduje się wiele iteratorów walidacji krzyżowej. Istnieje również kilka iteratorów do samodzielnego zdefiniowania walidacji krzyżowej. Problem polega na tym, że tak naprawdę nie wiem, jak zdefiniować prostą walidację krzyżową dla szeregów czasowych. Tutaj jest dobrym przykładem tego, co staram się dostać:sklearn: Zdefiniowana przez użytkownika walidacja krzyżowa dla danych szeregów czasowych

Załóżmy, że mamy kilka okresów (lat) i chcemy podzielić nasze dane określone w kilku kawałkach, co następuje:

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] 

mogę” t naprawdę zrozumieć, jak stworzyć tego rodzaju krzyżową walidację za pomocą narzędzi sklearn. Prawdopodobnie powinienem użyć PredefinedSplit od sklearn.cross_validation tak:

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) 

Wynik:

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

Ale nadal to nie jest tak dobry jak poprzednie dane podzielone

+0

co zmienne w zbiorze danych? dlaczego ważne jest, aby podzielić serie czasowe, dlaczego nie podzielić losowo? – maxymoo

+1

Można wygenerować podziały bez użycia scikit-learn, w następujący sposób: 'cv_split = [(dane [: i], dane [i:]) dla i w zakresie (1, len (dane))]'. Co myślisz? –

+0

@maxymoo, Powodem, dla którego nie należy dzielić losowo danych z szeregów czasowych, jest to, że czas może mieć znaczenie (a nie tylko inne zidentyfikowane funkcje), ale "na wolności", że nigdy nie nauczysz się modelować danych z przyszłości. Testując swój model, powinieneś zachowywać się podobnie i nie ćwiczyć danych po dacie testu. – dslack

Odpowiedz

5

można uzyskać pożądane podziały krzyżowej walidacji bez użycia sklearn. Oto przykład

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

Czy nie stworzy to oddzielnego podziału dla każdej obserwacji, podczas gdy okno do przodu? Jeśli chcę to zmniejszyć, to czy powinienem użyć parametru 'step' w zakresie, aby przejść do większych" kawałków "? – dreyco676

+1

@ dreyco676 Zgadza się. Po prostu użyj parametru 'step' większego niż jeden, na przykład' cv_splits = [(idxs [: i], idxs [i:]) dla i w zakresie (1, N, 2)] ' –

+0

Tylko dla pewności: że StratifiedKFold został z tyłu, prawda? – paulochf

3

Tymczasem ta została dodana do biblioteki: http://scikit-learn.org/stable/modules/cross_validation.html#time-series-split

Przykład z 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]