机器学习
一. 机器学习基本概念
机器学习-致力于研究如何通过计算的手段,利用经验(历史数据)来改善系统自身的性能[机器学习]。
从数据中产生模型的算法,即“学习算法”。
基本术语:
学习(训练):从数据中学得模型的过程
训练集:参与模型训练的样本集合
测试:学得模型后,使用其样本进行预测的过程
测试集:被预测的样本集合
假设:学得模型对应的关于数据的某种潜在规律
分类:输出结果是离散值
回归:输出结果是连续值
监督学习:训练样本有标记
无监督学习:训练样本无标记
泛化能力:学得模型适用于新样本的能力
独立同分布:样本空间的全体样本都服从一个未知的分布,且相互独立
误差:模型输出与样本真实值之间的差异
错误率:分类错误样本数占总样本数比例
精度:1-错误率
训练误差:模型在训练集上的误差
泛化误差:模型在新样本上的误差
过拟合:用力过猛
欠拟合:用力不足
模型性能度量
查准率/准确率(precision): P = TP/(TP+FP)
查全率/召回率/灵敏度(recall):R = TP/(TP+FN)
“1”代表正例,“0”代表反例
from sklearn.metrics import precision_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
y_true=[1,0,1,1,0]
y_pred=[1,0,1,0,0]
print(precision_score(y_true,y_pred,average=None))
print(confusion_matrix(y_true, y_pred))#混淆矩阵
print(classification_report(y_true, y_pred))
二. 相关技术:
1.回归分析(Regression Analysis)
线性回归
sklearn.linear_model中的LinearRegression可实现线性回归
LinearRegression 的构造方法:
LinearRegression( fit_intercept=True, #默认值为 True,表示 计算随机变量,False 表示不计算随机变量 normalize=False, #默认值为 False,表示在回归前是否对回归因子X进行归一化True 表示是 , copy_X=True)
LinearRegression 的常用方法有:
decision_function(X) #返回 X 的预测值 y
fit(X,y[,n_jobs]) #拟合模型
get_params([deep]) #获取 LinearRegression 构造方法的参数信息
predict(X) #求预测值 #同 decision_function
1.使用Python实现下面输入与输出的线性回归
输入:[[0, 0], [1, 1], [2, 2]]——两个输入
输出:[0, 1, 2]
预测:[3, 3]
from sklearn.linear_model import LinearRegression
clf = LinearRegression()#线性回归
clf.fit([[0, 0], [1, 1], [2, 2]], [0, 1, 2]) # 模型训练x和y,二维
pre = clf.predict([[3, 3]]) # 模型预测,二维即一行两列
clf.coef_ #x和y的系数
clf.intercept_ #截距项
print(pre) #[3.]
'''
y = 0.5*x1 + 0.5*x2 #学习得到的模型
'''
2.波士顿房价数据集(Boston House Price Dataset)包含对房价的预测,以千美元计,给定的条件是房屋及其相邻房屋的详细信息。
该数据集是一个回归问题。每个类的观察值数量是均等的,共有 506 个观察,13 个输入变量和1个输出变量。
sklearn库的datasets包含该数据集( load_boston)
直觉告诉我们:第6列(住宅平均房间数)与最终房价一般是成正比的,具有某种线性关系。我们利用线性回归来验证想法。
同时,作为一个二维的例子,可以在平面上绘出图形,进一步观察图形。
# 波士顿房价数据回归分析
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
bosten = load_boston() # 实例化
x = bosten.data[:, 5:6]#进行切片取第6列,保持二维结构
clf = LinearRegression()
clf.fit(x, bosten.target) # 模型训练
#clf.coef_ # 回归系数
y_pre = clf.predict(x) # 模型输出值
plt.scatter(x, bosten.target) # 样本实际分布
plt.plot(x, y_pre, color='red') # 绘制拟合曲线
plt.show()
逻辑回归(解决分类问题)
研究生入学录取预测:
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
data = pd.read_csv('LogisticRegression.csv')
data_tr, data_te, label_tr, label_te = train_test_split(data.iloc[:, 1:], data['admit'], test_size=0.2)
clf = LogisticRegression()
clf.fit(data_tr, label_tr)
pre = clf.predict(data_te)
res = classification_report(label_te, pre)
print(res)
结果:
2.决策树(Decision Tree)
属性选择的先后顺序
熵值
信息增益
信息增益率
问题:对于给定样本集,如何判断应该在哪个属性上进行拆分、
每次拆分都存在多种可能,哪个才是较好的选择呢?
理想情况:在拆分过程中,当叶节点只拥有单一类别时,将不必继续拆分。
目标是寻找较小的树,希望递归过程尽早停止
较小的树意味着什么?
当前最好的拆分属性产生的拆分中目标类的分布应该尽可能地单一(单纯),多数类占优。
如果能测量每一个节点的纯度,就可以选择能产生最纯子节点的那个属性进行拆分;
决策树算法通常按照纯度的增加来选择拆分属性。
纯度的概念
纯度度量
当样本中没有两项属于同一类:0
当样本中所有项都属于同一类:1
最佳拆分可以转化为选择拆分属性使纯度度量最大化的优化问题
拆分增加了纯度,但如何将这种增加量化呢,或者如何与其他拆分进行比较呢?
用于评价拆分分类目标变量的纯度度量包括
基尼(Gini,总体发散性) CART
熵(entropy,信息量)
信息增益(Gain) ID3
信息增益率 C4.5,C5.0
改变拆分准则(splitting criteria)导致树的外观互不相同
熵(entropy)
信息论中的熵:是信息的度量单位,是一种 对属性“不确定性的度量”。
属性的不确定性越大,把它搞清楚所需要的信息量也就越大,熵也就越大。
如果一个数据集D有N个类别,则该数据集的熵为:
打球数据集的熵为:
信息增益(gain):对纯度提升的程度
若离散属性a有V个取值,则其信息增益为:
天气属性的信息增益
晴:打球记录2条,不打球记录为3条
阴:打球记录4条,不打球记录0条
雨:打球记录3条,不打球记录2条
天气属性的信息增益:
ID3算法实现
ID3算法的详细实现步骤如下:
ID3算法是决策树系列中的经典算法之一,它包含了决策树作为机器学习算法的主要思想缺点是:
由于ID3决策树算法采用信息增益作为选择拆分属性的标准,
会偏向于选择取值较多的,即所谓高度分支属性,
而这类属性并不一定是最优的属性。
ID3算法只能处理离散属性,对于连续型的属性,
在分类前需要对其进行离散化。
实例—使用scikit-learn建立基于信息熵的决策树模型
这个例子是经典的Kaggle101问题——泰坦尼克生还预测,部分数据如下:
为了说明的方便,数据集有许多属性被删除了。通过观察可知:列Survived是指是否存活,是类别标签,属于预测目标;列Sex的取值是非数值型的。我们在进行数据预处理时应该合理应用Pandas的功能,让数据能够被模型接受。
泰坦尼克生还预测代码:
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.metrics import classification_report
import graphviz
# 1.导入数据
data = pd.read_csv('titanic_data.csv')
# 2.数据预处理
data.drop('PassengerId', axis=1, inplace=True) # 删除PassengerId 列,且对源数据进行处理
#通过标签索引
data.loc[data['Sex'] == 'male', 'Sex'] = 1 # 用数值1来代替male,用0来代替female
data.loc[data['Sex'] == 'female', 'Sex'] = 0
#fillna()填充缺失值
data.fillna(data['Age'].mean(), inplace=True) # 用均值来填充缺失值
# 3.模型的构建
Dtc = DecisionTreeClassifier(max_depth=5, random_state=8) # 构建决策树模型,树的最大深度是5,随机种子8
#fit(样本自变量(二维)—即所有行的后三列,目标变量即Survived列)
Dtc.fit(data.iloc[:, 1:], data['Survived']) # 模型训练
pre = Dtc.predict(data.iloc[:, 1:]) # 模型预测
pre == data['Survived'] # 比较模型预测值与样本实际值是否一致
classification_report(data['Survived'], pre) # 分类报告
# 4.决策树的可视化
dot_data = export_graphviz(Dtc, feature_names=['Pclass', 'Sex', 'Age'], class_names='Survived')#feature_names是指属性名称即列名称
graph = graphviz.Source(dot_data) # 决策树可视化
graph
如要将决策树可视化,还需要安装Graphviz(跨平台的、基于命令行的绘图工具),并将安装路径\bin\dot.exe添加至系统变量
*https://graphviz.gitlab.io/_pages/Download/Download_windows.html *
生成的效果图如下:(jupyter notebook)
3.人工神经网络(Artificial Neural Network)
单个神经元结构
xj为输入信号, f 为传递函数,wi,j表示与神经元xj 连接的权值,yi 表示输出值,表示阈值
经典网络结构
BP网络结构
一个小例子:
梯度下降法
网络训练目标:
找出合适的权值和阈值,
使得误差 E 最小
激活函数
网络训练过程
输入:训练集数据、学习速率yita
过程:
在(0,1)范围内随机初始化网络中所有连接权和阈值
repeat
根据网络输入和当前参数计算网络输出值y
根据输出值和实际值得误差计算输出层神经元梯度项gj
计算隐层神经元梯度项eh
更新连接权值和阈值
until达到停止条件(即误差足够小或达到最大训练轮数)
输出:连接权值和阈值
BP神经网络实现
训练集数据:BPdata_tr.txt
测试集数据:BPdata_te.txt
网络结构
其中-1表达的是减去(-1)*阈值,即加上阈值
隐层神经元的个数是4(自己设置的)
数据结构
修正量公式:
映射函数
import math
import numpy as np
import pandas as pd
from pandas import DataFrame,Seres
def sigmoid(x): #映射函数
return 1/(1+math.exp(-x))
中间层神经元输入和输出层神经元输入
#中间层神经元输入和输出层神经元输入
Net_in = np.array([0,0,-1])
Out_in = np.array([0,0,0,0,-1])
中间层和输出层神经元权值及其变化量
#中间层和输出层神经元权值及其变化量
w_mid = np.zeros([3,4])
w_out = np.array([0.3,0.3,0.3,0.3,0.3])
delta_w_mid = np.zeros([3,4])
delta_w_out = np.array([0,0,0,0,0])
中间层的输出
#中间层的输出
for i in range(4):
Out_in[i] = sigmoid(sum(w_mid[:,i]*Net_in))
#输出层的输出/网络输出
res = sigmoid(sum(Out_in*w_out))
error = abs(res-real)
输出层权值变化量
#输出层权值变化量
delta_w_out = yita*res*(1-res)*(real-res)*Out_indelta_w_out[4] = -(yita*res*(1-res)*(real-res))
w_out = w_out+delta_w_out
中间层权值变化量
#中间层权值变化量
for i in range(4):
delta_w_mid[:,i] = yita*Out_in[i]*(1-Out_in[i])*w_out[i]*res*(1-res)*(real-res)*Net_in
delta_w_mid[2,i] = -(yita*Out_in[i]*(1-Out_in[i])*w_out[i]*res*(1-res)*(real-res))w_mid = w_mid+delta_w_mid
全样本网络代码实现
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x): # 定义网络激活函数
return 1/(1+np.exp(-x))
data_tr = pd.read_csv('BPdata_tr.txt') # 训练集样本
data_te = pd.read_csv('BPdata_te.txt') # 测试集样本
n = len(data_tr)
yita = 0.85 # 自己设置学习速率
out_in = np.array([0.0, 0, 0, 0, -1]) # 输出层的输入,即隐层的输出
w_mid = np.zeros([3, 4]) # 隐层神经元的权值&阈值
w_out = np.zeros([5]) # 输出层神经元的权值&阈值
delta_w_out = np.zeros([5]) # 输出层权值&阈值的修正量
delta_w_mid = np.zeros([3, 4]) # 中间层权值&阈值的修正量
Err = []
'''
模型训练
'''
for j in range(1000):
error = []
for it in range(n):
net_in = np.array([data_tr.iloc[it, 0], data_tr.iloc[it, 1], -1]) # 网络输入
real = data_tr.iloc[it, 2]
for i in range(4):
out_in[i] = sigmoid(sum(net_in * w_mid[:, i])) # 从输入到隐层的传输过程
res = sigmoid(sum(out_in * w_out)) # 模型预测值
error.append(abs(real-res))#误差
# print(it, '个样本的模型输出:', res, 'real:', real)
delta_w_out = yita*res*(1-res)*(real-res)*out_in # 输出层权值的修正量
delta_w_out[4] = -yita*res*(1-res)*(real-res) # 输出层阈值的修正量
w_out = w_out + delta_w_out # 更新,加上修正量
for i in range(4):
delta_w_mid[:, i] = yita*out_in[i]*(1-out_in[i])*w_out[i]*res*(1-res)*(real-res)*net_in # 中间层神经元的权值修正量
delta_w_mid[2, i] = -yita*out_in[i]*(1-out_in[i])*w_out[i]*res*(1-res)*(real-res) # 中间层神经元的阈值修正量,第2行是阈值
w_mid = w_mid + delta_w_mid # 更新,加上修正量
Err.append(np.mean(error))
plt.plot(Err)#训练集上每一轮的平均误差
plt.show()
plt.close()
'''
将测试集样本放入训练好的网络中去
'''
error_te = []
for it in range(len(data_te)):
net_in = np.array([data_te.iloc[it, 0], data_te.iloc[it, 1], -1]) # 网络输入
real = data_te.iloc[it, 2]
for i in range(4):
out_in[i] = sigmoid(sum(net_in * w_mid[:, i])) # 从输入到隐层的传输过程
res = sigmoid(sum(out_in * w_out)) # 模型预测值
error_te.append(abs(real-res))
plt.plot(error_te)#测试集上每一轮的误差
plt.show()
np.mean(error_te)
结果—训练集上每一轮的平均误差
结果—测试集上每一轮的误差
调用sklearn实现神经网络算法
API文档对方法以及参数详细介绍:
https://scikitlearn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html?highlight=mlp#sklearn.neural_network.MLPClassifier
'''
调用sklearn实现神经网络算法
'''
data_tr = pd.read_csv('BPdata_tr.txt') # 训练集样本
data_te = pd.read_csv('BPdata_te.txt') # 测试集样本
#hidden_layer_sizes是隐藏神经元的个数,max_iter是迭代次数,learning_rate_init是学习速率,random_state是随机种子
model = MLPRegressor(hidden_layer_sizes=(10,), random_state=10, max_iter=800, learning_rate_init=0.3) # 构建模型
model.fit(data_tr.iloc[:, :2], data_tr.iloc[:, 2]) # 模型训练
pre = model.predict(data_te.iloc[:, :2]) # 模型预测
err = np.abs(pre - data_te.iloc[:, 2]).mean() # 模型预测误差
print(err)
结果:0.038157725482174526