J'ai un modèle XGBoost essayant de prédire si une devise montera ou descendra la prochaine période (5 min). J'ai un ensemble de données de 2004 à 2018. J'ai divisé les données randomisées en 95% de train et 5% de validation et la précision sur l'ensemble de validation est jusqu'à 55%. Lorsque j'utilise ensuite le modèle sur un nouvel ensemble de test (données de 2019), la précision descend en dessous de 51%.
Quelqu'un peut-il expliquer pourquoi cela pourrait être?
Je veux dire, je suppose que le modèle n'a pas "vu" (formé) les données de validation plus qu'il n'a les données de test, donc peut-il vraiment être trop adapté?
J'ai joint un modèle simple ci-dessous pour illustrer. Celui-ci donne 54% sur l'ensemble de validation mais seulement 50,9% sur l'ensemble de test .
Merci pour toute aide!
NB Une théorie que j'avais était que, comme certaines fonctionnalités reposaient sur des données historiques (par exemple, la moyenne mobile), il pouvait s'agir d'une fuite de données. J'ai ensuite essayé de corriger cela en n'échantillonnant que des données qui ne faisaient pas partie de la création de la moyenne mobile. Par exemple, s'il y a une moyenne mobile de 3 périodes, je n'échantillonne / n'utilise pas les lignes de données de 2 périodes en arrière. Cela n'a rien changé donc ce n'est pas dans le modèle ci-dessous.
NB2 Le modèle ci-dessous est une version simple de ce que j'utilise. La raison d'un ensemble de validation pour moi est que j'utilise un algorithme génétique pour le réglage de l'hyperparamètre mais tout ce qui est supprimé ici pour plus de clarté.
import pandas as pd
import talib as ta
from sklearn.utils import shuffle
pd.options.mode.chained_assignment = None
from sklearn.metrics import accuracy_score
# ## TRAINING AND VALIDATING
# ### Read in data
input_data_file = 'EURUSDM5_2004-2018_cleaned.csv' # For train and validation
df = pd.read_csv(input_data_file)
# ### Generate features
#######################
# SET TARGET
#######################
df['target'] = df['Close'].shift(-1)>df['Close'] # target is binary, i.e. either up or down next period
#######################
# DEFINE FEATURES
#######################
df['rsi'] = ta.RSI(df['Close'], 14)
# ### Treat the data
#######################
# FIND AND MAKE CATEGORICAL VARAIBLES AND DO ONE-HOT ENCODING
#######################
for col in df.drop('target',axis=1).columns: # Crude way of defining variables with few unique variants as categorical
if df[col].nunique() < 25:
df[col] = pd.Categorical(df[col])
cats = df.select_dtypes(include='category') # Do one-hot encoding for the categorical variables
for cat_col in cats:
df = pd.concat([df,pd.get_dummies(df[cat_col], prefix=cat_col,dummy_na=False)],axis=1).drop([cat_col],axis=1)
uints = df.select_dtypes(include='uint8')
for col in uints.columns: # Variables from the one-hot encoding is not created as categoricals so do it here
df[col] = df[col].astype('category')
#######################
# REMOVE ROWS WITH NO TRADES
#######################
df = df[df['Volume']>0]
#######################
# BALANCE NUMBER OF UP/DOWN IN TARGET SO THE MODEL CANNOT SIMPLY CHOOSE ONE AND BE SUCCESSFUL THAT WAY
#######################
df_true = df[df['target']==True]
df_false = df[df['target']==False]
len_true = len(df_true)
len_false = len(df_false)
rows = min(len_true,len_false)
df_true = df_true.head(rows)
df_false = df_false.head(rows)
df = pd.concat([df_true,df_false],ignore_index=True)
df = shuffle(df)
df.dropna(axis=0, how='any', inplace=True)
# ### Split data
df = shuffle(df)
split = int(0.95*len(df))
train_set = df.iloc[0:split]
val_set = df.iloc[split:-1]
# ### Generate X,y
X_train = train_set[train_set.columns.difference(['target', 'Datetime'])]
y_train = train_set['target']
X_val = val_set[val_set.columns.difference(['target', 'Datetime'])]
y_val = val_set['target']
# ### Scale
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
cont = X_train.select_dtypes(exclude='category') # Find columns with continous (not categorical) variables
X_train[cont.columns] = sc.fit_transform(X_train[cont.columns]) # Fit and transform
cont = X_val.select_dtypes(exclude='category') # Find columns with continous (not categorical) variables
X_val[cont.columns] = sc.transform(X_val[cont.columns]) # Transform
cats = X_train.select_dtypes(include='category')
for col in cats.columns:
X_train[col] = X_train[col].astype('uint8')
cats = X_val.select_dtypes(include='category')
for col in cats.columns:
X_val[col] = X_val[col].astype('uint8')
# ## MODEL
from xgboost import XGBClassifier
model = XGBClassifier()
model.fit(X_train, y_train)
predictions = model.predict(X_val)
acc = 100*accuracy_score(y_val, predictions)
print('{0:0.1f}%'.format(acc))
# # TESTING
input_data_file = 'EURUSDM5_2019_cleaned.csv' # For testing
df = pd.read_csv(input_data_file)
#######################
# SET TARGET
#######################
df['target'] = df['Close'].shift(-1)>df['Close'] # target is binary, i.e. either up or down next period
#######################
# DEFINE FEATURES
#######################
df['rsi'] = ta.RSI(df['Close'], 14)
#######################
# FIND AND MAKE CATEGORICAL VARAIBLES AND DO ONE-HOT ENCODING
#######################
for col in df.drop('target',axis=1).columns: # Crude way of defining variables with few unique variants as categorical
if df[col].nunique() < 25:
df[col] = pd.Categorical(df[col])
cats = df.select_dtypes(include='category') # Do one-hot encoding for the categorical variables
for cat_col in cats:
df = pd.concat([df,pd.get_dummies(df[cat_col], prefix=cat_col,dummy_na=False)],axis=1).drop([cat_col],axis=1)
uints = df.select_dtypes(include='uint8')
for col in uints.columns: # Variables from the one-hot encoding is not created as categoricals so do it here
df[col] = df[col].astype('category')
#######################
# REMOVE ROWS WITH NO TRADES
#######################
df = df[df['Volume']>0]
df.dropna(axis=0, how='any', inplace=True)
X_test = df[df.columns.difference(['target', 'Datetime'])]
y_test = df['target']
cont = X_test.select_dtypes(exclude='category') # Find columns with continous (not categorical) variables
X_test[cont.columns] = sc.transform(X_test[cont.columns]) # Transform
cats = X_test.select_dtypes(include='category')
for col in cats.columns:
X_test[col] = X_test[col].astype('uint8')
predictions = model.predict(X_test)
acc = 100*accuracy_score(y_test, predictions)
print('{0:0.1f}%'.format(acc))
Comme le veut l'ancien mantra de l'investissement, "les performances passées ne sont pas indicatives des performances futures".
Mon premier candidat est sur-adapté. Bien que la probabilité qu'un modèle particulier soit symptomatique d'une certaine direction, même s'il n'est pas du tout causal (ou prédictif au-delà de l'échantillon en question), est astronomiquement faible, il existe également une quantité astronomique de modèles à détecter pouvant présenter un tel comportement. .
Supposons que ce sont de vrais schémas que vous avez appris:
pendant que vous entraîniez un algo à apprendre ses trois fonds et ses têtes et épaules, des centaines de banques l'étaient aussi, et à le faire plus rapidement que vous et à utiliser ces informations.
Cette information s'est reflétée dans différents mouvements de prix, car ils en savaient plus qu'en 2018 et ont agi différemment, votre modèle ne sait pas encore prendre en compte ces actions car elles sont nouvelles.
la source