回归树的python实例

一:概述

        将决策树运用到回归问题上,则为回归树。对于回归问题,响应变量y是连续变量。故对于回归树,可使用“最小化残差平方和”作为节点的分裂准则。这意味着,在进行节点分裂时,希望分裂后,残差平方和下降最多,即两个子节点的残差平方和之总和最小。

        为避免过拟合,对于回归树,也要使用惩罚项进行修枝,即最小化如下目标函数:

其中,Rm为第m个终节点,而负号后面的这一项为该终节点的预测值(此终节点的样本均值)。为第m个终节点的残差平方和。然后对所有终节点m=1,...,|T|进行加总,即为成本R(T)。(还是需要大家有一定的决策树的基础的,要不可能会有一点点看不懂。)

二:程序实现

        本节使用波士顿房价数据boston,演示回归树。该数据集包含1970年波士顿506个社区有关房价的14个变量。响应变量为社区房价中位数MEDV。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeRegressor,export_text
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_boston
from sklearn.metrics import cohen_kappa_score

        载入boston数据集,抽取 30%作为测试集,其余70%作为训练集。train_test_split()函数可以很好的划分训练集和测试集。

Boston = load_boston() #响应变量为MEDV
X_train, X_test, y_train, y_test = train_test_split(Boston.data, Boston.target, test_size=0.3, random_state=0)
model = DecisionTreeRegressor(max_depth=2, random_state=123) #进行回归树估计,max_depth=2限制最大深度为2,使用一种改进的CART算法

        此命令创建了DecisionTreeRegressor类的一个实例model。第一个参数表示最大深度为2,第二个参数设定随机种子,以表示结果可重复。DecisionTreeRegressor使用了一种改进的CART算法(CART算法可参考西瓜书,或李航的机器学习都可以)。接下来使用fit()方法进行估计。

model.fit(X_train, y_train)
model.score(X_test, y_test)

        可以把上述结果输出,考察测试集的拟合优度。接下来打印文本格式的决策树。

print(export_text(model,feature_names=list(Boston.feature_names)))

        可以用python自带的函数画出决策树。(前提别忘了加上plt.show())

plot_tree(model, feature_names=Boston.feature_names, node_ids=True, rounded=True, precision=2)

        

        如图可知,在根节点的分裂条件为房间数RM<=6.8。如果满足此条件,则为“普宅”向左。如果不满足此条件,则为“大宅”向右。

        虽然数据集有13个特征变量,但此决策树仅仅用了两个变量,十分简明且易于解释,而且测试集的拟合优度也能达到0.6。但是规模多大的决策树具有最佳的泛化预测能力?可以通过对成本复杂性参数ccp_alpha进行交叉验证来确定。当其为0,不惩罚决策树的规模,可能导致过拟合;反之参数太大,惩罚过于严厉,可能会欠拟合,就是只剩下一个树桩了。

        针对DecisionTreeRegressor类的一个实例model,可用cost_complexity_pruning_path()方法,得到一系列ccp_alpha相对应的“叶节点总不纯度”。对于回归树,其不纯度就是均方误差MSE。可输入如下命令:

model = DecisionTreeRegressor(random_state=123)
path = model.cost_complexity_pruning_path(X_train, y_train)

其中,cost_alphas与path.impurities分别为ccp_alpha序列与相应叶节点总均方误差。更直观的,画图展示:

plt.plot(path.ccp_alphas, path.impurities, marker='o', drawstyle='steps-post')
plt.xlabel('alpha (cost-complexity parameter)')
plt.ylabel('Total Leaf MSE')
plt.title('Total Leaf MSE vs alpha for Training Set')
plt.show()

        如图,成本复杂性参数alpha为0时,并不惩罚决策树规模,导致每个观测值本身就是一个叶节点,故叶节点的总均方误差为0.当alpha上升时,对于决策树的惩罚力度增加,叶节点总均方误差随之上升。然而,在alpha的一定区间内,所得决策树规模可能不变,导致图中的曲线呈现阶梯状。最后alpha接近40时,决策树仅剩下树桩,而叶节点总均方误差达到最大:

print(max(path.ccp_alphas),  max(path.impurities))

        下面用十折交叉验证,选择最优的超参数ccp_alpha。先将path.ccp_alphas定义为一个名为param_grid的字典:

param_grid = {'ccp_alpha': path.ccp_alphas}

        然后使用sklearn的KFold类,定义一个10折随机分组kfold:

kfold = KFold(n_splits=10, shuffle=True, random_state=1) #使用sklearn的KFold类,定义一个10折随机分组kfold

        将参数网格param_grid与随机分组kfold作为参数,传给sklearn的GridSearchCV类,进行十折交叉验证:

model = GridSearchCV(DecisionTreeRegressor(random_state=123), param_grid, cv=kfold)#将参数网格param_grid与随机分组kfold作为参数,传给sklearn的GridsearchCV类
model.fit(X_train, y_train)#使用fit方法进行估计

        使用model的best_params_属性,考察最优超参数:

print(model.best_params_)

        结果就是最优的ccp_alpha值,为0.039.使用best_estimator_属性,将model重新定义为最优的决策树模型(使用最优的ccp_alpha),并考察拟合优度:

model = model.best_estimator_
model.score(X_test,y_test) #0.6848 结果显示测试集的R方上升为0.685

        结果为0.68484。也可以使用model.get_depth()和model.get_n_leaves()查看树的深度和叶节点数目。接下来可考察每个变量的重要性,在此就不介绍了。有需要的可以私信,评论等。

写的有点草率,感谢大家,求赞谢谢!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的 Python 实现 CART 回归的例子: ```python import numpy as np class CARTRegressionTree: def __init__(self, max_depth=5, min_samples_split=2, min_samples_leaf=1): self.max_depth = max_depth self.min_samples_split = min_samples_split self.min_samples_leaf = min_samples_leaf def fit(self, X, y): self.n_features_ = X.shape[1] self.tree_ = self._build_tree(X, y, depth=0) def predict(self, X): return np.array([self._predict(inputs) for inputs in X]) def _build_tree(self, X, y, depth): n_samples, n_features = X.shape if depth >= self.max_depth or n_samples < self.min_samples_split: return self._make_leaf_node(y) best_feature, best_threshold = self._find_split(X, y, n_samples, n_features) if best_feature is None: return self._make_leaf_node(y) left_indices = X[:, best_feature] < best_threshold right_indices = ~left_indices left_tree = self._build_tree(X[left_indices], y[left_indices], depth+1) right_tree = self._build_tree(X[right_indices], y[right_indices], depth+1) return self._make_decision_node(best_feature, best_threshold, left_tree, right_tree) def _find_split(self, X, y, n_samples, n_features): best_feature, best_threshold, best_mse = None, None, np.inf for feature in range(n_features): thresholds = np.unique(X[:, feature]) for threshold in thresholds: left_indices = X[:, feature] < threshold right_indices = ~left_indices if sum(left_indices) >= self.min_samples_leaf and sum(right_indices) >= self.min_samples_leaf: left_mse = self._mean_squared_error(y[left_indices]) right_mse = self._mean_squared_error(y[right_indices]) mse = left_mse + right_mse if mse < best_mse: best_feature, best_threshold, best_mse = feature, threshold, mse return best_feature, best_threshold def _mean_squared_error(self, y): return np.mean((y - np.mean(y))**2) def _make_decision_node(self, feature, threshold, left_tree, right_tree): return {'feature': feature, 'threshold': threshold, 'left_tree': left_tree, 'right_tree': right_tree} def _make_leaf_node(self, y): return {'leaf': np.mean(y)} def _predict(self, inputs): node = self.tree_ while isinstance(node, dict): if inputs[node['feature']] < node['threshold']: node = node['left_tree'] else: node = node['right_tree'] return node['leaf'] ``` 在上面的代码中,`CARTRegressionTree` 类实现了 CART 回归的训练和预测方法。其中,`max_depth`、`min_samples_split` 和 `min_samples_leaf` 是可调参数,分别控制的最大深度、节点分裂所需的最小样本数和叶节点所需的最小样本数。`fit` 方法用于训练模型,`predict` 方法用于预测新样本。 在 `_build_tree` 方法中,我们递归地构建决策树。如果当前节点样本数少于 `min_samples_split` 或者的深度达到了 `max_depth`,则返回当前节点的平均值作为叶节点。否则,我们尝试在所有特征和阈值的组合中找到一个最优的分裂点,使得分裂后的左右子的均方误差之和最小。如果无法找到合适的分裂点,则返回当前节点的平均值作为叶节点。 在 `_find_split` 方法中,我们遍历所有特征和阈值的组合,计算分裂后的左右子的均方误差之和。如果左右子的样本数都大于等于 `min_samples_leaf`,则更新最优的分裂点。 在 `_make_decision_node` 和 `_make_leaf_node` 方法中,我们分别创建决策节点和叶节点。 在 `_predict` 方法中,我们遍历决策树,根据当前节点的特征和阈值判断向左还是向右走,直到到达叶节点,返回叶节点的平均值作为预测值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值