Il semble que XGBoost utilise par défaut des arbres de régression comme apprenants de base. XGBoost (ou Gradient boosting en général) fonctionne en combinant plusieurs de ces apprenants de base. Les arbres de régression ne peuvent pas extrapoler les modèles dans les données d'entraînement, donc toute entrée supérieure à 3 ou inférieure à 1 ne sera pas correctement prédite dans votre cas. Votre modèle est formé pour prédire les sorties des entrées dans l'intervalle [1,3]
, une entrée supérieure à 3 recevra la même sortie que 3 et une entrée inférieure à 1 recevra la même sortie que 1.
De plus, les arbres de régression ne voient pas vraiment vos données comme une ligne droite car ce sont des modèles non paramétriques, ce qui signifie qu'ils peuvent théoriquement s'adapter à n'importe quelle forme plus compliquée qu'une ligne droite. En gros, un arbre de régression fonctionne en affectant vos nouvelles données d'entrée à certains des points de données d'entraînement qu'il a vus pendant l'entraînement et produit la sortie en fonction de cela.
Cela contraste avec les régresseurs paramétriques (comme la régression linéaire ) qui recherchent en fait les meilleurs paramètres d'un hyperplan (ligne droite dans votre cas) pour s'adapter à vos données. La régression linéaire ne voir vos données en ligne droite avec une pente et une interception.
Vous pouvez changer l'apprenant de base de votre modèle XGBoost en GLM (modèle linéaire généralisé) en ajoutant "booster":"gblinear"
à votre modèle params
:
import pandas as pd
import xgboost as xgb
df = pd.DataFrame({'x':[1,2,3], 'y':[10,20,30]})
X_train = df.drop('y',axis=1)
Y_train = df['y']
T_train_xgb = xgb.DMatrix(X_train, Y_train)
params = {"objective": "reg:linear", "booster":"gblinear"}
gbm = xgb.train(dtrain=T_train_xgb,params=params)
Y_pred = gbm.predict(xgb.DMatrix(pd.DataFrame({'x':[4,5]})))
print Y_pred
En général, pour déboguer les raisons pour lesquelles votre modèle XGBoost se comporte d'une manière particulière, consultez les paramètres du modèle:
gbm.get_dump()
Si votre apprenant de base est un modèle linéaire, la sortie get_dump est:
['bias:\n4.49469\nweight:\n7.85942\n']
Dans votre code ci-dessus, puisque vous arborez les apprenants de base, le résultat sera:
['0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=2.85\n\t\t4:leaf=5.85\n\t2:leaf=8.85\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=1.995\n\t\t4:leaf=4.095\n\t2:leaf=6.195\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=1.3965\n\t\t4:leaf=2.8665\n\t2:leaf=4.3365\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.97755\n\t\t4:leaf=2.00655\n\t2:leaf=3.03555\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.684285\n\t\t4:leaf=1.40458\n\t2:leaf=2.12489\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.478999\n\t\t4:leaf=0.983209\n\t2:leaf=1.48742\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.3353\n\t\t4:leaf=0.688247\n\t2:leaf=1.04119\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.23471\n\t\t4:leaf=0.481773\n\t2:leaf=0.728836\n',
'0:[x<3] yes=1,no=2,missing=1\n\t1:[x<2] yes=3,no=4,missing=3\n\t\t3:leaf=0.164297\n\t\t4:leaf=0.337241\n\t2:leaf=0.510185\n',
'0:[x<2] yes=1,no=2,missing=1\n\t1:leaf=0.115008\n\t2:[x<3] yes=3,no=4,missing=3\n\t\t3:leaf=0.236069\n\t\t4:leaf=0.357129\n']
Astuce: je préfère en fait utiliser les classes xgb.XGBRegressor ou xgb.XGBClassifier, car elles suivent l' API d' apprentissage sci-kit . Et comme sci-kit learn possède de nombreuses implémentations d'algorithmes d'apprentissage automatique, l'utilisation de XGB comme bibliothèque supplémentaire ne perturbe pas mon flux de travail uniquement lorsque j'utilise l'interface sci-kit de XGBoost.