"""
 GradientBoostedTree.py  (author: Anson Wong / git: ankonzoid)
"""
import numpy as np
from sklearn.tree import DecisionTreeRegressor
class GradientBoostedTreeRegressor:
	def __init__(self, n_estimators=20, max_depth=5, min_samples_split=2, min_samples_leaf=1):
		self.n_estimators = n_estimators
		self.max_depth = max_depth
		self.min_samples_split = min_samples_split
		self.min_samples_leaf = min_samples_leaf
	def fit(self, X, y):
		"""
        Method:
         1) Train tree with greedy splitting on dataset (X, y)
         2) Recursively (n_estimator times) compute the residual between the
            truth and prediction values (res = y-y_pred), and use the residual as
            the next estimator's training y (keep X the same)
         3) The prediction at each estimator is the trained prediction plus
            the previous trained prediction, making the full prediction of the final
            model the sum of the predictions of each model.
        """
		self.models = []
		y_i = y
		y_pred_i = np.zeros(y.shape)
		for i in range(self.n_estimators):
			model = DecisionTreeRegressor(max_depth=self.max_depth, min_samples_split=self.min_samples_split, min_samples_leaf=self.min_samples_leaf)
			model.fit(X, y_i)
			y_pred = model.predict(X) + y_pred_i
			res = y - y_pred
			y_i = res
			y_pred_i = y_pred
			self.models.append(model)
	def predict(self, X):
		y_pred = np.zeros(len(X))
		for model in self.models:
			y_pred += model.predict(X)
		return y_pred