feat(DataLoader): caching MVP, added ability to use standard scaling for exogenous data, scaling is now also done before feature selection (#105)

* fix(FeatureExtractor): apply log to transform some series to normality

* feat(DataLoader): add ability of not returning returns when they're not needed (exogenous data), applied log to certain features

* feat(FeatureExtractors): added standard scaling for exogenous data

* feat(FeatureSelection): scale data with the passed in scaler before doing feature-selection

* fix(Config): sweep config

* feat(Models): output probability, store it

* feat(Core): added caching to select_features() and load_data()

* fix(Dependencies): added diskcache

* fix(Training): error when creating results DF

* feat(Models): added xgboost, fixed tests

* refactor(Cache): moved hashing to a separate function, created wrapper functions to separate business logic and caching

* fix(Tests): new syntax

* fix(Model): XGboost can't handle -1 class, so we'll use the deprecated label_encoder fornow

* fix(Model): XGBoost config

* feat(Cache): add run_clear_cache script

* fix(Pipeline) accidentally re-instatiating all_predictions for each asset
This commit is contained in:
Mark Aron Szulyovszky
2022-01-04 11:44:35 +01:00
committed by GitHub
parent 867269df2b
commit 1cd0119589
27 changed files with 324 additions and 206 deletions
+10 -5
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
from models.base import Model
import numpy as np
@@ -10,16 +11,20 @@ class StaticAverageModel(Model):
only_column = 'model_'
feature_selection = 'off'
model_type = 'static'
predict_window_size = 'single_timestamp'
def fit(self, X, y, prev_model):
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
# This is a static model, it can' learn anything
pass
def predict(self, X):
def predict(self, X) -> tuple[float, np.ndarray]:
# Make sure there's data to average
assert X.shape[1] > 0
prediction = np.average(X[-1])
return np.array([prediction])
return (prediction, np.array([]))
def clone(self):
return self
def clone(self) -> StaticAverageModel:
return self
def get_name(self) -> str:
return 'static_average'
+24 -13
View File
@@ -1,7 +1,8 @@
from __future__ import annotations
from typing import Literal, Optional
from sklearn.base import clone
from abc import ABC, abstractmethod, abstractproperty
from abc import ABC, abstractmethod
import numpy as np
class Model(ABC):
@@ -10,18 +11,22 @@ class Model(ABC):
# data_format: Literal["wide", "narrow"]
only_column: Optional[str]
model_type: Literal['ml', 'static']
predict_window_size: Literal['single_timestamp', 'window_size']
@abstractmethod
def fit(self, X, y, prev_model):
pass
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
raise NotImplementedError
@abstractmethod
def predict(self, X):
pass
def predict(self, X) -> tuple[float, np.ndarray]:
raise NotImplementedError
@abstractmethod
def clone(self):
pass
def clone(self) -> Model:
raise NotImplementedError
def get_name(self) -> str:
raise NotImplementedError
class SKLearnModel(Model):
@@ -30,15 +35,21 @@ class SKLearnModel(Model):
only_column = None
feature_selection = 'on'
model_type = 'ml'
predict_window_size = 'single_timestamp'
def __init__(self, model):
self.model = model
def fit(self, X, y, prev_model):
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
self.model.fit(X, y)
def predict(self, X):
return self.model.predict(X)
def predict(self, X) -> tuple[float, np.ndarray]:
pred = self.model.predict(X).item()
probability = self.model.predict_proba(X).squeeze()
return (pred, probability)
def clone(self):
return SKLearnModel(clone(self.model))
def clone(self) -> SKLearnModel:
return SKLearnModel(clone(self.model))
def get_name(self) -> str:
return self.model.__class__.__name__
+2
View File
@@ -11,6 +11,7 @@ from models.base import SKLearnModel
from models.momentum import StaticMomentumModel
from models.average import StaticAverageModel
from models.naive import StaticNaiveModel
from xgboost import XGBClassifier
model_map = {
@@ -34,6 +35,7 @@ model_map = {
NB= SKLearnModel(GaussianNB()),
AB= SKLearnModel(AdaBoostClassifier(n_estimators=15)),
RF= SKLearnModel(RandomForestClassifier(n_jobs=-1, max_depth=20, random_state=1)),
XGB= SKLearnModel(XGBClassifier(n_jobs=-1, max_depth = 20, random_state=1, use_label_encoder=True, objective='multi:softprob', eval_metric='mlogloss')),
StaticMom= StaticMomentumModel(allow_short=True),
Ensemble_Average = StaticAverageModel(),
),
+10 -5
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
from models.base import Model
import numpy as np
@@ -10,19 +11,23 @@ class StaticMomentumModel(Model):
only_column = 'mom'
feature_selection = 'off'
model_type = 'static'
predict_window_size = 'single_timestamp'
def __init__(self, allow_short: bool) -> None:
super().__init__()
self.allow_short = allow_short
def fit(self, X, y, prev_model):
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
# This is a static model, it can' learn anything
pass
def predict(self, X):
def predict(self, X) -> tuple[float, np.ndarray]:
negative_class = -1.0 if self.allow_short == True else 0.0
prediction = 1.0 if X[-1][0] > 0 else negative_class
return np.array([prediction])
return (prediction, np.array([]))
def clone(self):
return self
def clone(self) -> StaticMomentumModel:
return self
def get_name(self) -> str:
return 'static_mom'
+10 -5
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
from models.base import Model
import numpy as np
@@ -10,13 +11,17 @@ class StaticNaiveModel(Model):
only_column = None
feature_selection = 'off'
model_type = 'static'
predict_window_size = 'single_timestamp'
def fit(self, X, y, prev_model):
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
# This is a static model, it can' learn anything
pass
def predict(self, X):
return np.array([X[-1][0]])
def predict(self, X) -> tuple[float, np.ndarray]:
return (X[-1][0], np.array([]))
def clone(self):
return self
def clone(self) -> StaticNaiveModel:
return self
def get_name(self) -> str:
return 'static_naive'