特征重要性
作为决策树模型训练过程的副产品,根据每个特征划分子表前后的信息熵减少量就标志了该特征的重要程度,此即为该特征的特征重要性指标。通过模型训练得到的model对象提供了属性:feature_importances_来存储每个特征的特征重要性指标值。
获取特征重要性相关API:
model.fit(train_x, train_y)
fi = model.feature_importances_
案例:
from __future__ import unicode_literals #特征重要性
import sklearn.datasets as sd
import sklearn.utils as su
import sklearn.tree as st
import sklearn.metrics as sm
import sklearn.ensemble as se
import sklearn.linear_model as lm
import matplotlib.pyplot as mp
import numpy as np
boston = sd.load_boston()
print(boston.data.shape) # 数据量
print(boston.target.shape)
print(boston.feature_names) # 13个特征名
# 打乱原始输入、输出数据集
x,y = su.shuffle(
boston.data,boston.target,random_state=7)
# 划分测试集与训练集
train_size = int(len(x) * 0.8 )
train_x,train_y,test_x,test_y = x[:train_size],y[:train_size],x[train_size:],y[train_size:]
# 创建模型,使用训练集数据进行训练
model = st.DecisionTreeRegressor(max_depth=4)
model.fit(train_x,train_y)
# 测试集数据预测
pred_test_y = model.predict(test_x)
# 输出R2得分
print(sm.r2_score(test_y,pred_test_y))
#单颗决策树模型,输出特征重要性
fi = model.feature_importances_
# 把特征重要性绘制成柱状图
mp.figure('Feature Importance')
mp.subplot(211)
mp.title('Decision Tree',fontsize = 14)
mp.ylabel('Importance',fontsize = 12)
mp.grid(linestyle=':')
indices = fi.argsort()[::-1]
pos = np.arange(indices.size)
mp.bar(pos,fi[indices],label='DT',facecolor='deepskyblue',edgecolor='steelblue')
mp.xticks(pos,boston.feature_names[indices])
mp.legend()
# 正向激励
model = se.AdaBoostRegressor(model, #基础模型
n_estimators = 400, # 决策树数量
random_state = 7 # 随机种子
)
model.fit(train_x,train_y)
pred_test_y = model.predict(test_x)
# 输出R2得分
print(sm.r2_score(test_y,pred_test_y))
# 基于决策树的正向激励,输出特征重要性
fi2 = model.feature_importances_
# 把特征重要性绘制成柱状图
mp.subplot(212)
mp.title('AdaBoostRegressor',fontsize=14)
mp.ylabel('Importance',fontsize=12)
mp.grid(linestyle=":")
indices = fi2.argsort()[::-1]
pos = np.arange(indices.size)
mp.bar(pos,fi2[indices],label='AB',facecolor='deepskyblue',edgecolor='steelblue')
mp.xticks(pos,boston.feature_names[indices])
mp.legend()
mp.show()
自助聚合
每次从样本矩阵中有放回抽样的方式随机抽取部分样本构建决策树,这样形成多颗包含不同训练样本的决策树。以削弱某些强势样本对模型预测结果的影响,提高模型的普适性。
随机森林
在自助聚合的基础上,每次构建决策树模型时,不仅随机选择部分样本,而且还随机选择部分特征,这样的集合算法,不仅规避了强势样本对预测结果的影响,而且也削弱了强制特征的影响,使模型的预测能力更加泛化。
随机森林API:
import sklearn.ensemble as se
# 随机森林回归器
model = se.RandomForestRegressor(
max_depth=10, # 数的最大深度
n_estimators=1000, # 决策树的数量
min_samples_split=2 # 子表中最小样本数,小于该值,不再拆分
)
案例:分析共享单车的需求,从而判断如何进行共享单车的投放
import numpy as np
import sklearn.utils as su
import sklearn.ensemble as se
import sklearn.metrics as sm
import matplotlib.pyplot as mp
data = np.loadtxt('../bike_day.csv',unpack=False,dtype='U20',delimiter=',')
#获取表头字符序列
day_headers = data[0,2:13]
# 整理输入输出集
x = np.array(data[1:,2:13],dtype=float)
y = np.array(data[1:,-1],dtype=float)
x,y = su.shuffle(x,y,random_state = 7)
train_size = int(len(x) * 0.9)
train_x, train_y, test_x, test_y = x[:train_size], y[:train_size], x[train_size:], y[train_size:]
# 随机森林回归器
model = se.RandomForestRegressor(
max_depth=10, n_estimators=1000,
min_samples_split=2)
model.fit(train_x, train_y)
pred_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pred_test_y))
fi = model.feature_importances_
indices = fi.argsort()[::-1]
print(day_headers[indices])
# 以小时为单位
data = np.loadtxt('../ml_data/bike_hour.csv',
unpack=False, dtype='U20',
delimiter=',')
# 获取表头字符序列
hour_headers = data[0, 2:14]
# 整理输入输出集
x = np.array(data[1:, 2:14], dtype=float)
y = np.array(data[1:, -1], dtype=float)
x, y = su.shuffle(x, y, random_state=7)
train_size = int(len(x) * 0.9)
train_x, train_y, test_x, test_y = \
x[:train_size], y[:train_size], \
x[train_size:], y[train_size:]
# 随机森林回归器
model = se.RandomForestRegressor(
max_depth=10, n_estimators=1000,
min_samples_split=2)
model.fit(train_x, train_y)
pred_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pred_test_y))
fi = model.feature_importances_
indices = fi.argsort()[::-1]
print(hour_headers[indices])
人工分类(简单分类)
案例:
import numpy as np
import matplotlib.pyplot as mp
x = np.array([
[3, 1],
[2, 5],
[1, 8],
[6, 4],
[5, 2],
[3, 5],
[4, 7],
[4, -1]])
y = np.array([0, 1, 1, 0, 0, 1, 1, 0])
# 绘制类别边界线
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(
np.linspace(l, r, n),
np.linspace(b, t, n))
grid_z = np.piecewise(
grid_x,
[grid_x < grid_y, grid_x >= grid_y],
[1, 0])
# 使用matplotlib绘制这些点,以及点的类别
mp.figure('Simple Classification', facecolor='lightgray')
mp.title('Simple Classification', fontsize=16)
mp.xlabel('Feture1', fontsize=12)
mp.ylabel('Feture2', fontsize=12)
mp.tick_params(labelsize=10)
# 为网格点坐标矩阵填充颜色
mp.pcolormesh(grid_x, grid_y, grid_z,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=y, cmap='brg',
s=80)
mp.show()
逻辑分类
通过输入的样本数据,基于多元线性回归模型求出线性预测方程。
y = w0 + w1x1 + w2x2
x1 x2 y
7 13 0.823423423
12 4 0.224234234
......
但通过线性回归方程返回的是连续值,不可以直接用于分类业务模型,所以急需一种方式使得把连续的预测值->离散的预测值。[-∞, +∞] -> (0, 1)
逻辑函数:y=11+e−x
逻辑函数:y=\frac{1}{1+e^{-x}}
逻辑函数:y=1+e−x1
该逻辑函数当x>0,y>0.5; 当x<0, y<0.5; 可以把样本数据经过线性预测模型求得的值代入逻辑函数的x,即将预测函数的输出看做被划分成为1类别的概率,则概率大的类别作为预测结果,就可以根据函数值确定两个分类。这也是线性函数非线性化的一种方式。
逻辑分类相关API:
import sklearn.linear_model as lm
# 创建逻辑分类模型
# solver:liblinear指的是逻辑分类底层使用线性回归模型
m = lm.LogisticRegression(solver='liblinear', C=正则强度)
m.fit(训练输入,训练输出)
m.predict(测试输入)
案例:
import numpy as np
import matplotlib.pyplot as mp
import sklearn.linear_model as lm
x = np.array([
[3, 1],
[2, 5],
[1, 8],
[6, 4],
[5, 2],
[3, 5],
[4, 7],
[4, -1]])
y = np.array([0, 1, 1, 0, 0, 1, 1, 0])
# 绘制类别边界线
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(
np.linspace(l, r, n),
np.linspace(b, t, n))
# 构建逻辑分类器
model = lm.LogisticRegression(
solver='liblinear', C=1)
model.fit(x, y)
samples = np.column_stack((
grid_x.ravel(), grid_y.ravel()))
grid_z = model.predict(samples)
grid_z = grid_z.reshape(grid_x.shape)
# 使用matplotlib绘制这些点,以及点的类别
mp.figure('Simple Classification', facecolor='lightgray')
mp.title('Simple Classification', fontsize=16)
mp.xlabel('Feture1', fontsize=12)
mp.ylabel('Feture2', fontsize=12)
mp.tick_params(labelsize=10)
# 为网格点坐标矩阵填充颜色
mp.pcolormesh(grid_x, grid_y, grid_z,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=y, cmap='brg',
s=80)
mp.show()
多元分类
通过多个二元分类器解决多元分类的问题。
若拿到一组新的样本,可以基于二元逻辑分类器,训练出一个模型,判断属于A类别的概率。在使用同样的方法训练出两个模型,分别判断属于B、C类别的概率,最终选择概率最高的类别作为这组样本的分类结果。
案例:基于逻辑分类模型的多元分类。
import numpy as np
import matplotlib.pyplot as mp
import sklearn.linear_model as lm
x = np.array([
[4, 7],
[3.5, 8],
[3.1, 6.2],
[0.5, 1],
[1, 2],
[1.2, 1.9],
[6, 2],
[5.7, 1.5],
[5.4, 2.2]])
y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])
# 绘制类别边界线
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(
np.linspace(l, r, n),
np.linspace(b, t, n))
# 构建逻辑分类器
model = lm.LogisticRegression(
solver='liblinear', C=1000)
model.fit(x, y)
samples = np.column_stack((
grid_x.ravel(), grid_y.ravel()))
grid_z = model.predict(samples)
grid_z = grid_z.reshape(grid_x.shape)
# 使用matplotlib绘制这些点,以及点的类别
mp.figure('Logistic Classification', facecolor='lightgray')
mp.title('Logistic Classification', fontsize=16)
mp.xlabel('Feture1', fontsize=12)
mp.ylabel('Feture2', fontsize=12)
mp.tick_params(labelsize=10)
# 为网格点坐标矩阵填充颜色
mp.pcolormesh(grid_x, grid_y, grid_z,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=y, cmap='brg',
s=80)
mp.show()
朴素贝叶斯分类
朴素贝叶斯分类是一种依据统计概率理论而实现的一种分类方式。
天气情况 | 穿衣风格 | 约女朋友 | ==> | 心情 |
---|---|---|---|---|
0(晴天) | 0(休闲) | 0(约了) | ==> | 0(高兴) |
0 | 1(风骚) | 1(没约) | ==> | 0 |
1(多云) | 1 | 0 | ==> | 0 |
0 | 2(破旧) | 1 | ==> | 1(郁闷) |
2(下雨) | 2 | 0 | ==> | 0 |
… | … | … | ==> | … |
0 | 1 | 0 | ==> | ? |
贝叶斯定理:
P(A|B) = P(A) P(B|A) / P(B) <= P(A, B) = P(A)P(B|A) = P(B) P(A|B)
例如:假设一个学校里有60%男生和40%女生,女生穿裤子的人数和穿裙子的人数相等,所有男生都穿裤子,一个人在远处随机看到了一个穿裤子的学生,那么这个学生是女生的概率是多少?
P(女) = 0.4
P(裤子|女) = 0.5
P(裤子) = 0.6+0.2 = 0.8
P(女生|裤子)= 0.4*0.5/0.8 = 0.25
由此可得,统计总样本空间中晴天、休闲、没约并且高兴的概率,然后在求总样本空间中晴天、休闲、没约并且郁闷的概率,取其大者作为分类结果。
P(晴天,休闲,没约,高兴)
=P(晴天|休闲,没约,高兴) P(休闲,没约,高兴)
=P(晴天|休闲,没约,高兴) P(休闲|没约,高兴) P(没约,高兴)
=P(晴天|休闲,没约,高兴) P(休闲|没约,高兴) P(没约|高兴)P(高兴)
(朴素:条件独立,特征值中间没有因果关系)
=P(晴天|高兴) P(休闲|高兴) P(没约|高兴)P(高兴)
朴素贝叶斯分类器相关API:
import sklearn.naive_bayes as nb
# 创建符合高斯分布的朴素贝叶斯分类器
model = nb.GaussianNB()
model.fit(x, y)
result = model.predict(samples)
案例:multiple1.txt
import numpy as np
import sklearn.naive_bayes as nb
import matplotlib.pyplot as mp
data = np.loadtxt('../ml_data/multiple1.txt',
unpack=False, dtype='U20',
delimiter=',')
x = np.array(data[:, :-1], dtype=float)
y = np.array(data[:, -1], dtype=float)
# 构建高斯朴素贝叶斯分类器
model = nb.GaussianNB()
model.fit(x, y)
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(
np.linspace(l, r, n),
np.linspace(b, t, n))
samples = np.column_stack(
(grid_x.ravel(), grid_y.ravel()))
grid_z = model.predict(samples)
grid_z = grid_z.reshape(grid_x.shape)
mp.figure('Naive Bayes Classification')
mp.title('Naive Bayes Classification', fontsize=16)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x, grid_y, grid_z,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], s=80,
c=y, cmap='brg')
mp.show()
数据集的划分
对于分类问题,训练集和测试集的划分不应该用整个样本空间的特定百分比作为训练数据,而应该在其每一个类别的样本中抽取特定百分比作为训练数据。
sklearn提供了数据集划分相关方法,可以方便的划分训练集与测试数据,相关API如下:
import sklearn.model_selection as ms
# train_test_split自动划分测试集与训练街
训练输入,测试输入,训练输出,测试输出 = ms.train_test_split(
输入集,输出集,
test_size=0.2, # 测试集占比
random_state=7
)
案例:
# 划分训练集与测试集
train_x, test_x, train_y, test_y = \
ms.train_test_split(
x, y, test_size=0.25, random_state=7)
# 让模型预测测试集结果
pred_test_y = model.predict(test_x)
# 输出精准度:预测正确的个数/总预测个数
print((test_y == pred_test_y).sum() / pred_test_y.size)
# 绘制测试集图形
mp.pcolormesh(grid_x, grid_y, grid_z, cmap='gray')
mp.scatter(test_x[:, 0], test_x[:, 1], s=80,
c=test_y, cmap='brg')
交叉验证
由于数据集的划分有不确定性,若随机划分的样本正好处于某类特殊样本,那么得到的训练模型所预测的结果可信度将会受到质疑。所以需要进行多次交叉验证。把样本空间中所有的样本均分成n分,使用不同的训练集训练模型,对不同的测试集进行测试,输出指标得分。
sklearn提供了交叉验证相关API:
import sklearn.model_selection as ms
# 交叉验证
指标值数组 = ms.cross_val_score(
模型, # 原始模型
输入集,输出集,
cv=5, # 折叠数 (做5次交叉验证)
scoring=指标名
)
交叉验证指标
-
精确度(accuracy): 分类正确的样本数/总样本数
-
查准率(precision_weighted):针对每一个类别,预测正确的样本数/预测出来的样本数。
-
召回率(recall_weighted):针对每一个类别,预测正确的样本数/实际存在的样本数。
-
f1得分(f1_weighted): 2 x 查准率 x 召回率/(查准率+召回率)
案例:
# 构建高斯朴素贝叶斯分类器
model = nb.GaussianNB()
# 先做交叉验证,看一下f1得分
ac = ms.cross_val_score(
model, train_x, train_y, cv=5,
scoring='accuracy')
pw = ms.cross_val_score(
model, train_x, train_y, cv=5,
scoring='precision_weighted')
rw = ms.cross_val_score(
model, train_x, train_y, cv=5,
scoring='recall_weighted')
f1 = ms.cross_val_score(
model, train_x, train_y, cv=5,
scoring='f1_weighted')
print(ac.mean(), pw.mean(), rw.mean(), f1.mean())
混淆矩阵
sklearn提供了混淆矩阵清晰的显示出每一类别的查准率、召回率等验证结果。每一行和每一列分别对应样本输出中的每一个类别,行表示实际类别,列表示预测类别。
A类别 | B类别 | C类别 | |
---|---|---|---|
A类别 | 5 | 0 | 0 |
B类别 | 0 | 6 | 0 |
C类别 | 0 | 0 | 7 |
上述矩阵为理想的混淆矩阵。不理想的如下:
A类别 | B类别 | C类别 | |
---|---|---|---|
A类别 | 3 | 1 | 1 |
B类别 | 0 | 4 | 2 |
C类别 | 0 | 0 | 7 |
获取模型分类结果的混淆矩阵相关API:
import sklearn.metrics as sm
m = sm.confusion_matrix(实际输出, 预测输出)
案例:
# 输出预测结果的混淆矩阵
m = sm.confusion_matrix(test_y, pred_test_y)
print(m)
mp.figure('M')
mp.imshow(m, cmap='gray')