机器学习03-(决策树:基本原理及集合算法、波士顿房屋价格数据分析与房价预测)

机器学习-03

决策树

基本算法原理

核心思想:相似的输入必会产生相似的输出。例如预测某人薪资:

年龄:1-青年,2-中年,3-老年
学历:1-本科,2-硕士,3-博士
经历:1-出道,2-一般,3-老手,4-骨灰
性别:1-男性,2-女性

年龄学历经历性别==>薪资
1111==>6000(低)
2131==>10000(中)
3341==>50000(高)
==>
1322==>?

为了提高搜索效率,使用树形数据结构处理样本数据:
年 龄 = 1 { 学 历 1 学 历 2 学 历 3 年 龄 = 2 { 学 历 1 学 历 2 学 历 3 年 龄 = 3 { 学 历 1 学 历 2 学 历 3 年龄=1\left\{ \begin{aligned} 学历1 \\ 学历2 \\ 学历3 \\ \end{aligned} \right. \quad\quad 年龄=2\left\{ \begin{aligned} 学历1 \\ 学历2 \\ 学历3 \\ \end{aligned} \right. \quad\quad 年龄=3\left\{ \begin{aligned} 学历1 \\ 学历2 \\ 学历3 \\ \end{aligned} \right. =1123=2123=3123
首先从训练样本矩阵中选择一个特征进行子表划分,使每个子表中该特征的值全部相同,然后再在每个子表中选择下一个特征按照同样的规则继续划分更小的子表,不断重复直到所有的特征全部使用完为止,此时便得到叶级子表,其中所有样本的特征值全部相同。对于待预测样本,根据其每一个特征的值,选择对应的子表,逐一匹配,直到找到与之完全匹配的叶级子表,用该子表中样本的输出,通过平均(回归)或者投票(分类)为待预测样本提供输出。

首先选择哪一个特征进行子表划分决定了决策树的性能。这么多特征,使用哪个特征先进行子表划分?

sklearn提供的决策树底层为cart树(Classification and Regression Tree),cart回归树在解决回归问题时的步骤如下:

  1. 原始数据集S,此时树的深度depth=0;
  2. 针对集合S,遍历每一个特征的每一个value,用该value将原数据集S分裂成2个集合:左集合left(<=value的样本)、右集合right(>value的样本),分别计算这2个集合的mse,找到使(left_mse+right_mse)最小的那个value,记录下此时的特征名称和value,这个就是最佳分割特征以及最佳分割值;
  3. 找到最佳分割特征以及最佳分割value之后,用该value将集合S分裂成2个集合,depth+=1;
  4. 针对集合left、right分别重复步骤2,3,直到达到终止条件。
终止条件有如下几种:
1、特征已经用完了:没有可供使用的特征再进行分裂了,则树停止分裂;
3、子节点中没有样本了:此时该结点已经没有样本可供划分,该结点停止分裂;
1、树达到了人为预先设定的最大深度:depth >= max_depth,树停止分裂。
2、节点的样本数量达到了人为设定的阈值:样本数量 < min_samples_split ,则树停止分裂;

决策树回归器模型相关API:

import sklearn.tree as st

# 创建决策树回归器模型  决策树的最大深度为4
model = st.DecisionTreeRegressor(max_depth=4)
# 训练模型  
# train_x: 二维数组样本数据
# train_y: 训练集中对应每行样本的结果
model.fit(train_x, train_y)
# 测试模型
pred_test_y = model.predict(test_x)

案例:预测波士顿地区房屋价格。

  1. 读取数据,打断原始数据集。 划分训练集和测试集。
import sklearn.datasets as sd
import sklearn.utils as su
# 加载波士顿地区房价数据集
boston = sd.load_boston()
print(boston.feature_names)
# |CRIM|ZN|INDUS|CHAS|NOX|RM|AGE|DIS|RAD|TAX|PTRATIO|B|LSTAT|
# 犯罪率|住宅用地比例|商业用地比例|是否靠河|空气质量|房间数|年限|距中心区距离|路网密度|房产税|师生比|黑人比例|低地位人口比例|
# 打乱原始数据集的输入和输出
x, y = su.shuffle(boston.data, boston.target, random_state=7)
# 划分训练集和测试集
train_size = int(len(x) * 0.8)
train_x, test_x, train_y, test_y = \
    x[:train_size], x[train_size:], \
    y[:train_size], y[train_size:]
  1. 创建决策树回归器模型,使用训练集训练模型。使用测试集测试模型。
import sklearn.tree as st
import sklearn.metrics as sm

# 创建决策树回归模型
model = st.DecisionTreeRegressor(max_depth=4)
# 训练模型
model.fit(train_x, train_y)
# 测试模型
pred_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pred_test_y))

集合算法

根据多个不同模型给出的预测结果,利用平均(回归)或者投票(分类)的方法,得出最终预测结果。

基于决策树的集合算法,就是按照某种规则,构建多棵彼此不同的决策树模型,分别给出针对未知样本的预测结果,最后通过平均或投票得到相对综合的结论。常用的集合模型包括Boosting类模型(AdaBoost、GBDT)与Bagging(自助聚合、随机森林)类模型。

AdaBoost模型(正向激励)

首先为样本矩阵中的样本随机分配初始权重,由此构建一棵带有权重的决策树,在由该决策树提供预测输出时,通过加权平均或者加权投票的方式产生预测值。将训练样本代入模型,预测其输出,对那些预测值与实际值不同的样本,提高其权重,由此形成第二棵决策树。重复以上过程,构建出不同权重的若干棵决策树。

正向激励相关API:

import sklearn.tree as st
import sklearn.ensemble as se
# model: 决策树模型(一颗)
model = st.DecisionTreeRegressor(max_depth=4)
# 自适应增强决策树回归模型	
# n_estimators:构建400棵不同权重的决策树,训练模型
model = se.AdaBoostRegressor(model, n_estimators=400, random_state=7)
# 训练模型
model.fit(train_x, train_y)
# 测试模型
pred_test_y = model.predict(test_x)

案例:基于正向激励训练预测波士顿地区房屋价格的模型。

# 创建基于决策树的正向激励回归器模型
model = se.AdaBoostRegressor(
	st.DecisionTreeRegressor(max_depth=4), n_estimators=400, random_state=7)
# 训练模型
model.fit(train_x, train_y)
# 测试模型
pred_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pred_test_y))

代码总结

波士顿房屋价格数据分析与房价预测

import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as sd
import sklearn.utils as su
import pandas as pd
# 加载数据集
boston = sd.load_boston()
# print(boston.DESCR)
x, y, header = boston.data, boston.target, boston.feature_names
# 针对当前数据集,做简单的数据分析
data = pd.DataFrame(x, columns=header)
data['y'] = y
data.describe()
CRIMZNINDUSCHASNOXRMAGEDISRADTAXPTRATIOBLSTATy
count506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000506.000000
mean3.59376111.36363611.1367790.0691700.5546956.28463468.5749013.7950439.549407408.23715418.455534356.67403212.65306322.532806
std8.59678323.3224536.8603530.2539940.1158780.70261728.1488612.1057108.707259168.5371162.16494691.2948647.1410629.197104
min0.0063200.0000000.4600000.0000000.3850003.5610002.9000001.1296001.000000187.00000012.6000000.3200001.7300005.000000
25%0.0820450.0000005.1900000.0000000.4490005.88550045.0250002.1001754.000000279.00000017.400000375.3775006.95000017.025000
50%0.2565100.0000009.6900000.0000000.5380006.20850077.5000003.2074505.000000330.00000019.050000391.44000011.36000021.200000
75%3.64742312.50000018.1000000.0000000.6240006.62350094.0750005.18842524.000000666.00000020.200000396.22500016.95500025.000000
max88.976200100.00000027.7400001.0000000.8710008.780000100.00000012.12650024.000000711.00000022.000000396.90000037.97000050.000000
data.pivot_table(index='CHAS', values='y')
y
CHAS
0.022.093843
1.028.440000
data['DIS'].plot.box()
<matplotlib.axes._subplots.AxesSubplot at 0x1dbae587518>

在这里插入图片描述

# 判断每个字段与房价之间的关系
data.plot.scatter(x='RM', y='y')
<matplotlib.axes._subplots.AxesSubplot at 0x1dbaea91b00>

在这里插入图片描述

训练回归模型,预测房屋价格

  1. 整理数据集(输入集、输出集)
  2. 打乱数据集,拆分测试集、训练集。
  3. 选择模型,使用训练集训练模型,用测试集测试。
# 整理数据集(输入集、输出集)
x, y = data.iloc[:, :-1], data['y']
# 打乱数据集。  su:  sklearn.utils
# random_state:随机种子。 若两次随机操作使用的随机种子相同,则随机结果也相同。
x, y = su.shuffle(x, y, random_state=7)
# 拆分测试集、训练集。
train_size = int(len(x) * 0.9)
train_x, test_x, train_y, test_y = \
    x[:train_size], x[train_size:], y[:train_size], y[train_size:]
train_x.shape, test_x.shape, train_y.shape, test_y.shape
((455, 13), (51, 13), (455,), (51,))
# 选择模型,使用训练集训练模型,用测试集测试。
import sklearn.linear_model as lm
import sklearn.metrics as sm

model = lm.LinearRegression()
model.fit(train_x, train_y)  # 针对训练集数据进行训练
pred_test_y = model.predict(test_x)  # 针对测试集数据进行测试
print(sm.r2_score(test_y, pred_test_y))
print(sm.mean_absolute_error(test_y, pred_test_y))
0.8188356183218533
2.405641089772746
# 选择岭回归模型,使用训练集训练模型,用测试集测试。
model = lm.Ridge(0)
model.fit(train_x, train_y)  # 针对训练集数据进行训练
pred_test_y = model.predict(test_x)  # 针对测试集数据进行测试
print(sm.r2_score(test_y, pred_test_y))
print(sm.mean_absolute_error(test_y, pred_test_y))
0.8188356183218408
2.405641089772664
# 选择多项式回归模型,使用训练集训练模型,用测试集测试。
import sklearn.pipeline as pl
import sklearn.preprocessing as sp

model = pl.make_pipeline(sp.PolynomialFeatures(2), lm.Ridge(50))
model.fit(train_x, train_y)  # 针对训练集数据进行训练
pred_test_y = model.predict(test_x)  # 针对测试集数据进行测试
print(sm.r2_score(test_y, pred_test_y))
print(sm.mean_absolute_error(test_y, pred_test_y))
0.8935803967838563
2.0136422973642047

决策树回归

import sklearn.tree as st
# 决策树回归模型,使用训练集训练模型,用测试集测试。
model = st.DecisionTreeRegressor(max_depth=4)
model.fit(train_x, train_y)  # 针对训练集数据进行训练
pred_test_y = model.predict(test_x)  # 针对测试集数据进行测试
print(sm.r2_score(test_y, pred_test_y))
print(sm.mean_absolute_error(test_y, pred_test_y))
0.678829897847864
2.9230600667206295
import graphviz
dot_data = st.export_graphviz(model,out_file=None,feature_names= header)
graph = graphviz.Source(dot_data)
graph

在这里插入图片描述

正向激励

import sklearn.ensemble as se

# AdaBoost回归模型,使用训练集训练模型,用测试集测试。
# 调整参数
params1 = [6, 7]
params2 = [50, 100, 150, 200]

for p1 in params1:
    for p2 in params2:
        model = st.DecisionTreeRegressor(max_depth=p1)
        model = se.AdaBoostRegressor(model, n_estimators=p2, random_state=7)
        model.fit(train_x, train_y)  # 针对训练集数据进行训练
        pred_test_y = model.predict(test_x)  # 针对测试集数据进行测试
        print('max_depth:', p1, '  n_estimators:', p2)
        print(sm.r2_score(test_y, pred_test_y))
        print(sm.mean_absolute_error(test_y, pred_test_y))
max_depth: 6   n_estimators: 50
0.8637049113548018
2.1825021616462665
max_depth: 6   n_estimators: 100
0.8814458900728809
2.060418077972981
max_depth: 6   n_estimators: 150
0.8786572551090628
2.067117240711519
max_depth: 6   n_estimators: 200
0.8793366363872159
2.048915502561963
max_depth: 7   n_estimators: 50
0.8621580468395789
2.0957038936825683
max_depth: 7   n_estimators: 100
0.8705920085320278
2.0740357212747056
max_depth: 7   n_estimators: 150
0.8710945918567736
2.049387496883028
max_depth: 7   n_estimators: 200
0.8677487622900691
2.0715533946795985
posted @ 2020-07-06 12:00  野哥李  阅读(34)  评论(0编辑  收藏  举报  来源