{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Decision tree for regression in plain Python\n", "\n", "A decision tree is a **supervised** machine learning model that can be used both for **classification** and **regression**. At its core, a decision tree uses a tree structure to predict an output value for a given input example. In the tree, each path from the root node to a leaf node represents a *decision path* that ends in a predicted value. \n", "\n", "A simple example might predict housing prices:\n", "\n", "![caption](figures/regression_tree.png)\n", "\n", "Decision trees have many advantages. For example, they are easy to understand and their decisions are easy to interpret. Also, they don't require a lot of data preparation. A more extensive list of their advantages and disadvantages can be found [here](http://scikit-learn.org/stable/modules/tree.html).\n", "\n", "### CART training algorithm \n", "In order to train a decision tree, various algorithms can be used. In this notebook we will focus on the *CART* algorithm (Classification and Regression Trees) for *regression*. The CART algorithm builds a *binary tree* in which every non-leaf node has exactly two children (corresponding to a yes/no answer). \n", "\n", "Given a set of training examples and their labels, the algorithm repeatedly splits the training examples $D$ into two subsets $D_{left}, D_{right}$ using some feature $f$ and feature threshold $t_f$ such that samples with the same label are grouped together. At each node, the algorithm selects the split $\\theta = (f, t_f)$ that produces the smallest *mean squared error* (MSE) (alternatively, we could use the mean absolute error).\n", "\n", "So at each step, the algorithm selects the parameters $\\theta$ that minimize the following cost function:\n", "\n", "\\begin{equation}\n", "J(D, \\theta) = \\frac{n_{left}}{n_{total}} MSE_{left} + \\frac{n_{right}}{n_{total}} MSE_{right}\n", "\\end{equation}\n", "\n", "- $D$: remaining training examples \n", "- $n_{total}$ : number of remaining training examples\n", "- $\\theta = (f, t_f)$: feature and feature threshold\n", "- $n_{left}/n_{right}$: number of samples in the left/right subset\n", "- $MSE_{left}/MSE_{right}$: MSE of the left/right subset\n", "\n", "This step is repeated recursively until the *maximum allowable depth* is reached or the current number of samples $n_{total}$ drops below some minimum number. The original equations can be found [here](http://scikit-learn.org/stable/modules/tree.html).\n", "\n", "After building the tree, new examples can be classified by navigating through the tree, testing at each node the corresponding feature until a leaf node/prediction is reached.\n", "\n", "\n", "### Mean Squared Error (MSE)\n", "\n", "When performing regression (i.e. the target values are continuous) we can evaluate a split using its MSE. The MSE of node $m$ is computed as follows:\n", "\n", "\\begin{equation}\n", "\\hat{y}_m = \\frac{1}{n_{m}} \\sum_{i \\in D_m} y_i\n", "\\end{equation}\n", "\\begin{equation}\n", "MSE_m = \\frac{1}{n_{m}} \\sum_{i \\in D_m} (y_i - \\hat{y}_m)^2\n", "\\end{equation}\n", "\n", "- $D_m$: training examples in node $m$\n", "- $n_{m}$ : total number of training examples in node $m$\n", "- $y_i$: target value of $i-$th example\n", "\n", "### Caveats\n", "\n", "Without regularization, decision trees are likely to overfit the training examples. This can be prevented using techniques like *pruning* or by providing a maximum allowed tree depth and/or a minimum number of samples required to split a node further." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:42:50.190368Z", "start_time": "2018-04-17T14:42:49.587490Z" } }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from sklearn.model_selection import train_test_split\n", "np.random.seed(123)\n", "\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dataset" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:42:54.501545Z", "start_time": "2018-04-17T14:42:54.111218Z" } }, "outputs": [ { "data": { "text/plain": [ "Text(0,0.5,'Target values')" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "X = np.linspace(-3, 3, 400)\n", "y = X ** 2 + np.random.randn(400)\n", "\n", "plt.figure(figsize=(10,8))\n", "plt.scatter(X, y)\n", "plt.title(\"Simple quadratic dataset with noise\")\n", "plt.xlabel(\"Feature values\")\n", "plt.ylabel(\"Target values\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:43:06.489812Z", "start_time": "2018-04-17T14:43:06.477392Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Shape X_train: (300, 1)\n", "Shape y_train: (300,)\n", "Shape X_test: (100, 1)\n", "Shape y_test: (100,)\n" ] } ], "source": [ "X = X[:, np.newaxis]\n", "\n", "# Split the data into a training and test set\n", "X_train, X_test, y_train, y_test = train_test_split(X, y)\n", "\n", "print(f'Shape X_train: {X_train.shape}')\n", "print(f'Shape y_train: {y_train.shape}')\n", "print(f'Shape X_test: {X_test.shape}')\n", "print(f'Shape y_test: {y_test.shape}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Decision tree class\n", "\n", "Parts of this code were inspired by [this tutorial](https://machinelearningmastery.com/implement-decision-tree-algorithm-scratch-python/)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:44:56.019512Z", "start_time": "2018-04-17T14:44:55.373615Z" } }, "outputs": [], "source": [ "class DecisionTree:\n", " \"\"\"\n", " Decision tree for regression\n", " \"\"\"\n", "\n", " def __init__(self):\n", " self.root_dict = None\n", " self.tree_dict = None\n", "\n", " def split_dataset(self, X, y, feature_idx, threshold):\n", " \"\"\"\n", " Splits dataset X into two subsets, according to a given feature\n", " and feature threshold.\n", "\n", " Args:\n", " X: 2D numpy array with data samples\n", " y: 1D numpy array with labels\n", " feature_idx: int, index of feature used for splitting the data\n", " threshold: float, threshold used for splitting the data\n", "\n", " Returns:\n", " splits: dict containing the left and right subsets\n", " and their labels\n", " \"\"\"\n", "\n", " left_idx = np.where(X[:, feature_idx] < threshold)\n", " right_idx = np.where(X[:, feature_idx] >= threshold)\n", "\n", " left_subset = X[left_idx]\n", " y_left = y[left_idx]\n", "\n", " right_subset = X[right_idx]\n", " y_right = y[right_idx]\n", "\n", " splits = {\n", " 'left': left_subset,\n", " 'y_left': y_left,\n", " 'right': right_subset,\n", " 'y_right': y_right,\n", " }\n", "\n", " return splits\n", "\n", " def mean_squared_error(self, y_left, y_right, n_left, n_right):\n", " \"\"\"\n", " Computes MSE of a split.\n", "\n", " Args:\n", " y_left, y_right: target values of samples in left/right subset\n", " n_left, n_right: number of samples in left/right subset\n", "\n", " Returns:\n", " mse_left: float, MSE of left subset\n", " mse_right: gloat, MSE of right subset\n", " \"\"\"\n", "\n", " mse_left, mse_right = 0, 0\n", "\n", " if len(y_left) != 0:\n", " y_hat_left = (1 / n_left) * np.sum(y_left)\n", " mse_left = (1 / n_left) * np.sum((y_left - y_hat_left) ** 2)\n", "\n", " if len(y_right) != 0:\n", " y_hat_right = (1 / n_right) * np.sum(y_right)\n", " mse_right = (1 / n_right) * np.sum((y_right - y_hat_right) ** 2)\n", "\n", " return mse_left, mse_right\n", "\n", " def get_cost(self, splits):\n", " \"\"\"\n", " Computes cost of a split given the MSE of the left\n", " and right subset and the sizes of the subsets.\n", "\n", " Args:\n", " splits: dict, containing params of current split\n", " \"\"\"\n", " y_left = splits['y_left']\n", " y_right = splits['y_right']\n", "\n", " n_left = len(y_left)\n", " n_right = len(y_right)\n", " n_total = n_left + n_right\n", "\n", " mse_left, mse_right = self.mean_squared_error(y_left, y_right, n_left, n_right)\n", " cost = (n_left / n_total) * mse_left + (n_right / n_total) * mse_right\n", "\n", " return cost\n", "\n", " def find_best_split(self, X, y):\n", " \"\"\"\n", " Finds the best feature and feature index to split dataset X into\n", " two groups. Checks every value of every attribute as a candidate\n", " split.\n", "\n", " Args:\n", " X: 2D numpy array with data samples\n", " y: 1D numpy array with labels\n", "\n", " Returns:\n", " best_split_params: dict, containing parameters of the best split\n", " \"\"\"\n", "\n", " n_samples, n_features = X.shape\n", " best_feature_idx, best_threshold, best_cost, best_splits = np.inf, np.inf, np.inf, None\n", "\n", " for feature_idx in range(n_features):\n", " for i in range(n_samples):\n", " current_sample = X[i]\n", " threshold = current_sample[feature_idx]\n", " splits = self.split_dataset(X, y, feature_idx, threshold)\n", " cost = self.get_cost(splits)\n", "\n", " if cost < best_cost:\n", " best_feature_idx = feature_idx\n", " best_threshold = threshold\n", " best_cost = cost\n", " best_splits = splits\n", "\n", " best_split_params = {\n", " 'feature_idx': best_feature_idx,\n", " 'threshold': best_threshold,\n", " 'cost': best_cost,\n", " 'left': best_splits['left'],\n", " 'y_left': best_splits['y_left'],\n", " 'right': best_splits['right'],\n", " 'y_right': best_splits['y_right'],\n", " }\n", "\n", " return best_split_params\n", "\n", "\n", " def build_tree(self, node_dict, depth, max_depth, min_samples):\n", " \"\"\"\n", " Builds the decision tree in a recursive fashion.\n", "\n", " Args:\n", " node_dict: dict, representing the current node\n", " depth: int, depth of current node in the tree\n", " max_depth: int, maximum allowed tree depth\n", " min_samples: int, minimum number of samples needed to split a node further\n", "\n", " Returns:\n", " node_dict: dict, representing the full subtree originating from current node\n", " \"\"\"\n", " left_samples = node_dict['left']\n", " right_samples = node_dict['right']\n", " y_left_samples = node_dict['y_left']\n", " y_right_samples = node_dict['y_right']\n", "\n", " if len(y_left_samples) == 0 or len(y_right_samples) == 0:\n", " node_dict[\"left_child\"] = node_dict[\"right_child\"] = self.create_terminal_node(np.append(y_left_samples, y_right_samples))\n", " return None\n", "\n", " if depth >= max_depth:\n", " node_dict[\"left_child\"] = self.create_terminal_node(y_left_samples)\n", " node_dict[\"right_child\"] = self.create_terminal_node(y_right_samples)\n", " return None\n", "\n", " if len(right_samples) < min_samples:\n", " node_dict[\"right_child\"] = self.create_terminal_node(y_right_samples)\n", " else:\n", " node_dict[\"right_child\"] = self.find_best_split(right_samples, y_right_samples)\n", " self.build_tree(node_dict[\"right_child\"], depth+1, max_depth, min_samples)\n", "\n", " if len(left_samples) < min_samples:\n", " node_dict[\"left_child\"] = self.create_terminal_node(y_left_samples)\n", " else:\n", " node_dict[\"left_child\"] = self.find_best_split(left_samples, y_left_samples)\n", " self.build_tree(node_dict[\"left_child\"], depth+1, max_depth, min_samples)\n", "\n", " return node_dict\n", "\n", " def create_terminal_node(self, y):\n", " \"\"\"\n", " Creates a terminal node.\n", "\n", " Args:\n", " y: 1D numpy array with target values\n", " Returns:\n", " predicted_value: float, predicted value\n", " \"\"\"\n", " return np.mean(y)\n", "\n", " def train(self, X, y, max_depth, min_samples):\n", " \"\"\"\n", " Fits decision tree on a given dataset.\n", "\n", " Args:\n", " X: 2D numpy array with data samples\n", " y: 1D numpy array with labels\n", " max_depth: int, maximum allowed tree depth\n", " min_samples: int, minimum number of samples needed to split a node further\n", " \"\"\"\n", " self.n_classes = len(set(y))\n", " self.root_dict = self.find_best_split(X, y)\n", " self.tree_dict = self.build_tree(self.root_dict, 1, max_depth, min_samples)\n", "\n", " def predict(self, X, node):\n", " \"\"\"\n", " Predicts the class for a given input example X.\n", "\n", " Args:\n", " X: 1D numpy array, input example\n", " node: dict, representing trained decision tree\n", "\n", " Returns:\n", " prediction: float, predicted value\n", " \"\"\"\n", " feature_idx = node['feature_idx']\n", " threshold = node['threshold']\n", "\n", " if X[feature_idx] < threshold:\n", " if isinstance(node['left_child'], (float)):\n", " return node['left_child']\n", " else:\n", " prediction = self.predict(X, node['left_child'])\n", " elif X[feature_idx] >= threshold:\n", " if isinstance(node['right_child'], (float)):\n", " return node['right_child']\n", " else:\n", " prediction = self.predict(X, node['right_child'])\n", "\n", " return prediction" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2018-04-09T12:19:30.968801Z", "start_time": "2018-04-09T12:19:30.963691Z" } }, "source": [ "## Initializing and training the decision tree" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:44:59.750231Z", "start_time": "2018-04-17T14:44:59.698500Z" } }, "outputs": [], "source": [ "tree = DecisionTree()\n", "tree.train(X_train, y_train, max_depth=2, min_samples=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Printing the decision tree structure" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:45:02.836283Z", "start_time": "2018-04-17T14:45:02.824214Z" } }, "outputs": [], "source": [ "def print_tree(node, depth=0):\n", " if isinstance(node, (float)):\n", " print(f\"{depth * ' '}predicted class: {round(node, 3)}\")\n", " else:\n", " print(f\"{depth * ' '} feature {node['feature_idx']} < {round(node['threshold'], 3)}, \"\n", " f\"cost of split: {round(node['cost'], 3)}\")\n", " print_tree(node[\"left_child\"], depth+1)\n", " print_tree(node[\"right_child\"], depth+1)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:45:04.621032Z", "start_time": "2018-04-17T14:45:04.616888Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " feature 0 < -2.053, cost of split: 5.829\n", " feature 0 < -2.639, cost of split: 1.105\n", " predicted class: 8.152\n", " predicted class: 5.674\n", " feature 0 < 1.947, cost of split: 2.45\n", " predicted class: 1.309\n", " predicted class: 6.105\n" ] } ], "source": [ "print_tree(tree.tree_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testing the decision tree" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:45:17.199579Z", "start_time": "2018-04-17T14:45:17.185717Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MSE on test set: 2.464\n" ] } ], "source": [ "mse = 0\n", "predictions = []\n", "for i in range(X_test.shape[0]):\n", " result = tree.predict(X_test[i], tree.tree_dict)\n", " mse += (y_test[i] - result) ** 2\n", " predictions.append(result)\n", "\n", "\n", "mse = (1 / len(y_test)) * mse\n", "print(f\"MSE on test set: {round(mse, 3)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting the predictions" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "ExecuteTime": { "end_time": "2018-04-17T14:46:37.715892Z", "start_time": "2018-04-17T14:46:37.397711Z" } }, "outputs": [ { "data": { "image/png": "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52MRtcOUnwVe47SEBRERJdDTdwG5spqWua787ROudL3ZE044AQ0NDQCAq666Cvfddx9uuukmAMC8efMA5Jc++sMf/oArrrii73nvvPMOAGDNmjV9C4VfffXVuPnmmwfs46mnnsLnPvc5DBqUDzmOPvroAY9Zu3YtXnrppb62HDx4EGeddRY2bdqEMWPG4KSTTupr46JFiyxf0969e3HNNdfgr3/9K0QEuVyu777zzjsPxxxzDADg0ksvxXPPPYdBgwahra0NU6ZMAQB0dXXhuOP6Z0+NHz8eN910E26++WZceOGFOPvssy3b4FTgwZiI/BLAuQCOFZEdAO5APghbKiKfBrANwBXmW4iGXwVeuYQSERF5tneHs9s1iYjpvw8//HAAQG9vL4YPH46Ojg6tbZRTSmk95rzzzsMvf/nLfrd3dHTYPrfcbbfdhunTp+PRRx/F1q1bce6555q2VUSglMI111yDu+++23SbJ598Mtra2vCb3/wGt9xyC2bNmoXbb7/dUbushDGb8mNKqfcopTJKqeOVUg8qpd5USs1USp1U+LN8tmXk/CrwatXDRkREpGXY8c5u17Rt2zb88Y9/BAD88pe/xLRp0wY85sgjj8SYMWOwbNkyAPnAaf369QCAhoYG/OpXvwKAAUN7RbNmzcIDDzyA7u5uAMDu3flT/hFHHIG33noLADB16lSsWbMGf/vb3wAA+/fvx1/+8heMGzcOW7ZswSuvvNLXRjt79+5FbW2+s+Ohhx7qd9/vfvc77N69G11dXWhpaUFDQwNmzpyJRx55BK+//npf+1599dV+z9u5cyeGDBmCq666CjfddBOef/5523Y4EfsE/qj4VeDVrCct29nF/DMiItIz83YgU9YZkKnJ3+7BKaecgocffhgTJkzA7t278fnPf97wcYsXL8aDDz6IiRMn4rTTTsNjj+Wzi77//e/jRz/6EaZMmYK9e/caPvczn/kMRo0ahQkTJmDixIn4xS9+AQC47rrrcMEFF2D69OkYMWIEHnroIXzsYx/DhAkTMHXqVGzatAmDBw/GokWLMGfOHEybNg0nnnii7Wv66le/iltuuQUNDQ0DEvGnTZuGq6++GpMmTcJll12G+vp6nHrqqfjmN7+JWbNmYcKECTjvvPPw2muv9XveCy+80Jfg/61vfQtf//rXbdvhhCilfN1gkOrr61Vra2to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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "predictions = []\n", "for i in range(X.shape[0]):\n", " result = tree.predict(X[i], tree.tree_dict)\n", " predictions.append(result)\n", "\n", "plt.figure(figsize=(10, 8))\n", "plt.title(\"Decision tree predictions\")\n", "plt.xlabel(\"Feature values\")\n", "plt.ylabel(\"Target values\")\n", "plt.scatter(X, y, label=\"target labels\")\n", "plt.scatter(X, predictions, label=\"predicted labels\")\n", "plt.legend(loc='upper right')\n", "plt.show()" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" }, "toc": { "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }