问题引入
炮弹轨迹问题
对于以上的炮弹问题,想分析他不用的数据模型
- 以上三种模型对应着3种不同模型情况
芯片检测问题
根据芯片尺寸1、尺寸2参数识别次品
- 以上三种情况对应着拟合的3种结果
- 模型对数据的预测情况
由于模型不合适,致使其无法对数据进行准确的预测
- 通常来说,欠拟合可通过观察训练数据的预测结果发现,解决办法可以是:选用其他模型、增加模型复杂度、增加数据样本、采集新的维度数据
解决过拟合问题的方法
- 原因:
Ø 使用了过于复杂的模型结构(比如高阶决策边界)
Ø 训练数据不足,有限的训练数据(训练样本只有总体样本中的小部分、不具备代表性)
Ø 样本里的噪音数据干扰过大,模型学习到了噪音信息(使用过多与结果不相关属性数据)
解决办法:
Ø 简化模型结构(降低模型复杂度,能达到好的效果情况下尽可能选择简单的模型)
Ø 数据增强(按照一定的规则扩充样本数据)
Ø 数据预处理,保留主成分信息(数据PCA处理)
Ø 增加正则化项(regularization)
- 数据增强
- 如图形中用的比较多的平移、翻转、旋转、镜像
- PCA降维处理
- 增加正则项
机器学习过程中,模型求解的核心目标就是最小化损失函数,增加正则项是指在损失函数中添加一个额外项,实现对求解参数的数值约束,防止模型过拟合。
如果λ是很大的数值(比如1000000),那各个θ取值就不能过大,其意义则是各个属性数据的系数受到约束(有效控制各个属性数据的影响)。(这里用ridge正则项做例子,但并不局限,如用绝对值亦可)
- 回归模型,引入不同正则项
如在分类项目中
小tips
如果想偷个懒,不知道该用几阶的回归任务,直接选用一个高阶的(如10阶5阶),这时候很有可能过拟合,则在这个的基础上增加一个pca数据分析降维,再去训练模型
分离训练数据与测试数据思考:仅仅通过训练数据的预测效果,是否足以评判模型的表现?
- 一个好的模型,能过对新数据样本做出准确预测
- 回顾模型训练与评估流程
- 在这个的基础上,我们在模型创建后,将数据分成两部分,对全数据进行数据分离!
分离流程
1、把全部数据分成两组:训练集、测试集
2、用训练集里的数据输入模型进行训练
3、用测试集里的数据输入模型进行预测,能有效评估此模型预测新的输入数据的表现
用于评估模型训练结果后的准确性,在前期学习的时候,我们对模型评估的方法就是查看其准确率,但是也有局限性:不能全面或真实表达模型对各类别结果的预测准确度
- 案例:奢饰品公司在投放广告前,根据部分高档消费客户的数据作为训练集和测试集,训练测试了高档消费客户的分类模型。该模型的准确率达到了95%。但是在实际广告投时,发现模型输出预测都为普非高档消费客户(非目标用户群体),其结果无法帮助决策。
更好的理解其中原因,我们将以上案例的数值提取出来概括:例如有100个样本,95个负样本,只有5个正样本,如果测试所有的样本结果都是负样本,也可以说准确率是95%
- 局限性变现在:
Ø 没有体现数据子类别的预测效果(如:0、1分别预测的准确率)
Ø 没有体现模型错误预测的类型(如:5%的错误率是什么预测错误)
以准确率作为分类问题的评价指标是有明显缺陷的,假如不同样本的比例非常不均衡,占大比例的类别会成为影响准确率的主要原因。
基于混淆矩阵计算评估指标
- 混淆矩阵也称误差矩阵,用于统计各类别样本预测正确与错误的数量,能帮助用户更全面地评估模型表现
- •True Positives (TP): 预测准确、预测为正样本的数量(实际为1,预测为1)
•True Negatives (TN): 预测准确、预测为负样本的数量(实际为0,预测为0)
•False Positives (FP): 预测错误、预测为正样本的数量(实际为0,预测为1)
•False Negatives (FN): 预测错误、预测为负样本的数量(实际为1,预测为0)
(预测结果正确或错误,预测结果为正样本或负样本)
- 案例
- A模型的各指标计算数值
- 最终结果
混淆矩阵小结
优点:
Ø 分类任务中,相比单一的准确率指标,混淆矩阵提供了更全面的模型评估信息(TP\TN\FP\FN)
Ø 基于混淆矩阵,我们可以计算出多样的模型表现衡量指标,从而实现模型的综合评估应用场景决定了衡量指标的重要性:
Ø 广告精准投放(正样本为 “目标用户”): 希望目标用户尽可能都被找出来、即实际正样本预测正确,需要关注召回率;同时,希望预测的正样本中实际都尽可能为正样本,需要关注精确率
Ø 异常消费检测 (正样本为 “异常消费”): 希望判断为正常的消费(负样本)中尽可能不存在异常消费,还需要关注特异度
不同时候看的指标不一样,需要具体问题具体分析
模型选择与优化在模型创建过程中有三大核心问题需要注意
算法选择
建模前检查
在这个过程,模型表现属于结果,如表现不好,需要从前往后找问题数据:是否有问题、算法选的是否合适、核心结构与参数是否合理
- 上游决定下游,建模前五检查:
1、样本代表性:采集数据的方法是否合理,采集到的数据是否有代表性
2、标签统一化:对于样本结果,要确保每个样本都遵循一样的标签规则
3、数据合理性:样本中的异常数据点是否合理、如何处理
4、数据重要性:数据属性的意义,是否为无关数据
5、属性差异性:不同属性数据的数量级差异性如何
- 对于异常5检查,可以用以下方法进行尝试:
1、根据实际场景扩充或减少样本(数据质量提升,有助于提高模型表现)
2、对不合理标签数据进行预处理(帮助模型学习到正确信息(合理的“监督”))
3、删除不重要的属性数据、数据降维(降低噪声影响、减少过拟合、节约运算时间)
4、对数据进行归一化或标准化(平衡数据影响,加快训练收敛)
5、过滤掉异常数据(降低噪声影响、提高鲁棒性)
关于后3检查的示例
根据芯片尺寸1、尺寸2参数识别次品
- 异常数据处理
- 不同属性数据量级比较
- 数据降维分析
- 多模型对比
对于不同算法,应用场景不同,因此可以多尝试不同的模型进行训练,找到最优解
不适合的基本情况(模型表现属于结果,如表现不好,需要从前往后找问题:数据是否有问题、算法选的是否合适、核心结构与参数是否合理)
- 单一模型的核心参数优化
KNN模型,可以尝试不同的K值
在该情况下K越小,训练数据的预测准确率越高,但测试数据准确率可能下降(过拟合)
提高模型表现的四要素
实战一:炮弹发射轨迹预测
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
- 数据加载
# 训练数据加载
data_train = pd.read_csv('task1_train_data.csv')
# 测试数据加载
data_test = pd.read_csv('task1_test_data.csv')
数据的基本情况
- 数据赋值
# 训练数据赋值
x_tr = data_train.loc[:,'x_d']
y_tr = data_train.loc[:,'y_d']
# 测试数据赋值
x_ts = data_test.loc[:,'x_d']
y_ts = data_test.loc[:,'y_d']
print(x_tr,y_tr,x_ts,y_ts)
- 可视化
# 可视化
fig1 = plt.figure(figsize=(6,6))
train = plt.scatter(x_tr,y_tr,color='b',label='train_data')
test = plt.scatter(x_ts,y_ts,color='r',label='test_data')
plt.title('training_test data')
plt.xlabel('x_d')
plt.ylabel('y_d')
plt.legend()
- 线性回归模型训练
# 线性回归模型训练
from sklearn.linear_model import LinearRegression
x_tr.shape#(12,)
# 列没有指定,如果将该数据直接放进线性回归模型,会报错
# 转换数组模式
x_tr1 = np.array(x_tr).reshape(-1,1)
x_ts1 = np.array(x_ts).reshape(-1,1)
x_tr1.shape,x_ts1.shape
- 模型训练
# 模型训练
lr1 = LinearRegression()
lr1.fit(x_tr1,y_tr)
- 模型预测
# 模型预测
# 分别用测试数据和训练数据计算预测值
y_tr_predict = lr1.predict(x_tr1)
y_ts_predict = lr1.predict(x_ts1)
print(y_tr_predict,y_ts_predict)
- 模型评估
# 模型评估
from sklearn.metrics import r2_score
r2_tr = r2_score(y_tr,y_tr_predict)
r2_ts = r2_score(y_ts,y_ts_predict)
print(r2_tr,r2_ts)
训练数据不准确,测试数据更是直接变负数(说明非常不符合)
- 预测结果可视化 生成新数据点
# 预测结果可视化 生成新数据点
# 生成数据点
x_range = np.linspace(40,400,300).reshape(-1,1)
print(x_range.shape,min(x_range),max(x_range))
print(x_range)
y_range_predict = lr1.predict(x_range)
print(y_range_predict)
- 可视化
# 可视化
train = plt.scatter(x_tr,y_tr,color='b',label='train_data')
test = plt.scatter(x_ts,y_ts,color='r',label='test_data')
predict_p = plt.plot(x_range,y_range_predict,'r',label='predicted')
plt.title('training_test data')
plt.xlabel('x_d')
plt.ylabel('y_d')
plt.legend()
生成二阶属性数据
- 直接调用包计算回归中的多阶属性(不用自己计算
第一次是训练模型加拟合(fit_transform),第二次不训练模型,所以不加fit,保持两结果约束一致(用同一模型拟合)
关于PolynomialFeatures的用法可以参考一下网址
sklearn 的 PolynomialFeatures 的用法
from sklearn.preprocessing import PolynomialFeatures
# 直接调用包计算回归中的多阶属性(不用自己计算)
# 第一次是训练模型加拟合,第二次不训练模型,所以不加fit,保持两结果约束一致(用同一模型拟合)
poly2 = PolynomialFeatures(degree=2)
x_2_tr = poly2.fit_transform(x_tr1)
x_2_ts = poly2.transform(x_ts1)
print(x_tr1.shape,x_2_tr.shape)
print(x_2_tr[0:5],x_2_ts[0:5])
- 利用训练的好的多阶属性来训练测试数据和训练数据
# 利用训练的好的多阶属性来训练测试数据和训练数据
model2 = LinearRegression()
model2.fit(x_2_tr,y_tr)
- 模型预测及评估( 计算r2分数)
# 模型预测及评估
y_2_tr_predict = model2.predict(x_2_tr)
y_2_ts_predict = model2.predict(x_2_ts)
# 计算r2分数
r2_2_tr = r2_score(y_tr,y_2_tr_predict)
r2_2_ts = r2_score(y_ts,y_2_ts_predict)
print(r2_2_tr,r2_2_ts)
准确率上来了,而且训练集的测试集得出的评估分数都可以
- 结果可视化 生成新数据点
# 结果可视化 生成新数据点
x_range = np.linspace(40,400,300).reshape(-1,1)
# 利用1阶数据生成要用的2阶数据
x_2_range = poly2.transform(x_range)
y_2_range_predict = model2.predict(x_2_range)
# 可视化
train = plt.scatter(x_tr,y_tr,color='b',label='train_data')
test = plt.scatter(x_ts,y_ts,color='r',label='test_data')
predict_p = plt.plot(x_range,y_2_range_predict,'r',label='predicted')
plt.title('training_test data(poly2)')
plt.xlabel('x_d')
plt.ylabel('y_d')
plt.legend()
生产6阶属性数据
就是将上面额degree=2改成6,其他不变
from sklearn.preprocessing import PolynomialFeatures
# 直接调用包计算回归中的多阶属性(不用自己计算)
# 第一次是训练模型加拟合,第二次不训练模型,所以不加fit,保持两结果约束一致(用同一模型拟合)
poly2 = PolynomialFeatures(degree=6)
x_6_tr = poly2.fit_transform(x_tr1)
x_6_ts = poly2.transform(x_ts1)
print(x_tr1.shape,x_6_tr.shape)
print(x_6_tr[0:5],x_6_ts[0:5])
- 利用训练的好的多阶属性来训练测试数据和训练数据
# 利用训练的好的多阶属性来训练测试数据和训练数据
model6 = LinearRegression()
model6.fit(x_6_tr,y_tr)
- 模型预测及评估
# 模型预测及评估
y_6_tr_predict = model6.predict(x_6_tr)
y_6_ts_predict = model6.predict(x_6_ts)
# 计算r2分数
r2_6_tr = r2_score(y_tr,y_6_tr_predict)
r2_6_ts = r2_score(y_ts,y_6_ts_predict)
# 训练数据更加精准,但是测试数据就严重不符合
print(r2_6_tr,r2_6_ts)
训练数据更加精准,但是测试数据就严重不符合
- 结果可视化 生成新数据点
# 结果可视化 生成新数据点
x_range = np.linspace(40,400,300).reshape(-1,1)
# 利用1阶数据生成要用的2阶数据
x_6_range = poly2.transform(x_range)
y_6_range_predict = model6.predict(x_6_range)
# 可视化
train = plt.scatter(x_tr,y_tr,color='b',label='train_data')
test = plt.scatter(x_ts,y_ts,color='r',label='test_data')
predict_p = plt.plot(x_range,y_6_range_predict,'r',label='predicted')
plt.title('training_test data(poly2)')
plt.xlabel('x_d')
plt.ylabel('y_d')
plt.legend()
实战二:综合提升芯片品质预测
- 加载数据
# 加载数据
import pandas as pd
import numpy as np
data2 = pd.read_csv('task2_data.csv')
data2.head()
- 赋值
# 赋值
x = data2.drop(['y'],axis=1)
y2 = data2.loc[:,'y']
x.head()
- 数据可视化
# 数据可视化
from matplotlib import pyplot as plt
fig1 = plt.figure()
bad = plt.scatter(x.loc[:,'x1'][y2==0],x.loc[:,'x2'][y2==0],label='bad',marker='x',s=150)
good = plt.scatter(x.loc[:,'x1'][y2==1],x.loc[:,'x2'][y2==1],label='good',marker='o',facecolor='none',edgecolor='red',s=150)
plt.title('chip data')
plt.xlabel('size 1')
plt.ylabel('size 2')
plt.legend()
plt.show()
- 计算高斯分布的概率密度函数(分别计算正品和次品的)
正品
import math
# 正品
x1 = data2.loc[:,'x1'][y2==1]
x2 = data2.loc[:,'x2'][y2==1]
# 计算均值与标准差
u1 = x1.mean()
sigma1 = x1.std()
u2 = x2.mean()
sigma2 = x2.std()
print(u1,sigma1,u2,sigma2)
#计算高斯分布的概率密度函数
p1 = 1/sigma1/math.sqrt(2*math.pi)*np.exp(-np.power((x1-u1),2)/2/math.pow(sigma1,2))
p2 = 1/sigma2/math.sqrt(2*math.pi)*np.exp(-np.power((x2-u2),2)/2/math.pow(sigma2,2))
p = np.multiply(p1,p2)
print(p)
print('max p:',max(p))
print('min p:',min(p))
# 差了5倍之多
print('max/min:',max(p)/min(p))
次品
import math
x1 = data2.loc[:,'x1'][y2==0]
x2 = data2.loc[:,'x2'][y2==0]
# 计算均值与标准差
u1 = x1.mean()
sigma1 = x1.std()
u2 = x2.mean()
sigma2 = x2.std()
print(u1,sigma1,u2,sigma2)
#计算高斯分布的概率密度函数
p1 = 1/sigma1/math.sqrt(2*math.pi)*np.exp(-np.power((x1-u1),2)/2/math.pow(sigma1,2))
p2 = 1/sigma2/math.sqrt(2*math.pi)*np.exp(-np.power((x2-u2),2)/2/math.pow(sigma2,2))
p = np.multiply(p1,p2)
print(p)
print('max p:',max(p))
print('min p:',min(p))
# 差了9倍之多
print('max/min:',max(p)/min(p))
- 异常数据点检测
# 异常数据点检测
from sklearn.covariance import EllipticEnvelope
# 检测次品中的异常点
ad_model = EllipticEnvelope(contamination=0.02)
ad_model.fit(x[y2==0])
y_predict_bad = ad_model.predict(x[y2==0])
print(y_predict_bad)
- 异常点可视化
# 异常点可视化
bad = plt.scatter(x.loc[:,'x1'][y2==0],x.loc[:,'x2'][y2==0],label='bad',marker='x',s=150)
good = plt.scatter(x.loc[:,'x1'][y2==1],x.loc[:,'x2'][y2==1],label='good',marker='o',facecolor='none',edgecolor='red',s=150)
# 锁定异常点
ad = plt.scatter(x.loc[:,'x1'][y2==0][y_predict_bad==-1],
x.loc[:,'x2'][y2==0][y_predict_bad==-1],marker='o',s=150)
plt.title('chip data')
plt.xlabel('size 1')
plt.ylabel('size 2')
plt.legend()
plt.show()
- 剔除异常数据点
剔除的数据点其实是刚才计算出高斯分布密度概率中的最小值
# 剔除异常数据点
print(data2.shape)
data3 = data2.drop(index=35)
print(data3.shape)
各维度的数据分布
- 可视化
fig3 = plt.figure()
plt.subplot(121)
plt.hist(x1,bins=10)
plt.title('x1 data')
plt.xlabel('x1')
plt.ylabel('counts')
plt.subplot(122)
plt.hist(x2,bins=10)
plt.title('x2 data')
plt.xlabel('x2')
plt.ylabel('counts')
# 数据分布类似
- x,y重新赋值
# x,y重新赋值
x = data3.drop(['y'],axis=1)
y = data3.loc[:,'y']
print(x.shape)
主成分分析
- 数据标准化和pca降维
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
# 标准化
x_norm = StandardScaler().fit_transform(x)
# 训练
pca = PCA(n_components=2)
x_reduced = pca.fit_transform(x_norm)
# 各成分所占比例
var_ratio = pca.explained_variance_ratio_
print(var_ratio)
fig4 = plt.figure()
plt.bar([1,2],var_ratio)
plt.xticks([1,2],['pc1','pc2'])
plt.show()
- 数据分离(使用库直接分离,不用自己分离)
random_state=1保持随机分离状态一致
test_size=0.4分离比例为0.4,即40%
# 数据分离
from sklearn.model_selection import train_test_split
x_tr,x_ts,y_tr,y_ts = train_test_split(x,y,random_state=1,test_size=0.4)
print(x_tr.shape,x_ts.shape,x.shape,y_tr.shape,y_ts.shape)
- 建立knn模型 k=3
# 建立knn模型 k=3
from sklearn.neighbors import KNeighborsClassifier
knn_3 = KNeighborsClassifier(n_neighbors=3)
knn_3.fit(x_tr,y_tr)
- 模型预测_
# 模型预测_
y_tr_predict = knn_3.predict(x_tr)
y_ts_predict = knn_3.predict(x_ts)
print(y_tr_predict,y_ts_predict)
- 结果可视化
# 结果可视化
# 生产用于结果可视化的数据集
xx,yy = np.meshgrid(np.arange(0,10,0.05),np.arange(0,10,0.05))
# 数据展开
x_range = np.c_[xx.ravel(),yy.ravel()]
print(x_range.shape)
print(x_range)
- 预测生产的数据对应类别
# 预测生产的数据对应类别
y_range_predict = knn_3.predict(x_range)
- 数据可视化
# 数据可视化
# 利用密集数据点描绘出分界的感觉
bad_p = plt.scatter(x_range[:,0][y_range_predict==0],
x_range[:,1][y_range_predict==0],
label='bad_p')
good_p = plt.scatter(x_range[:,0][y_range_predict==1],
x_range[:,1][y_range_predict==1],
label='good_p')
# 已有数据的点
bad = plt.scatter(x.loc[:,'x1'][y2==0],x.loc[:,'x2'][y2==0],label='bad',marker='x',s=150)
good = plt.scatter(x.loc[:,'x1'][y2==1],x.loc[:,'x2'][y2==1],label='good',marker='o',facecolor='none',edgecolor='red',s=150)
plt.title('chip data')
plt.xlabel('size 1')
plt.ylabel('size 2')
plt.legend()
plt.show()
计算混淆矩阵
- 计算混淆矩阵
# 计算混淆矩阵
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_ts,y_ts_predict)
print(cm)
在这里继续巩固一下混淆矩阵的概念:
•True Positives (TP): 预测准确、预测为正样本的数量(实际为1,预测为1)
•True Negatives (TN): 预测准确、预测为负样本的数量(实际为0,预测为0)
•False Positives (FP): 预测错误、预测为正样本的数量(实际为0,预测为1)
•False Negatives (FN): 预测错误、预测为负样本的数量(实际为1,预测为0)
- 获取混淆矩阵
# 获取混淆矩阵
tp = cm[1,1]
tn = cm[0,0]
fp = cm[0,1]
fn = cm[1,0]
print(tp,tn,fp,fn)
- 计算准确率:整体样本中,预测正确样本数的比例
Accuracy= (TP+ TN)/(TP+ TN+FP+ FN)
# 计算准确率:整体样本中,预测正确样本数的比例
# Accuracy= (TP+ TN)/(TP+ TN+FP+ FN)
accuracy = (tp+tn)/(tp+tn+fp+fn)
# 和上面得出的模型评估数值相同
print(accuracy)
- 灵敏度(召回率) :正样本中,预测正确的比例
Sensitivity = Recall= TP/(TP+ FN)
# 灵敏度(召回率) :正样本中,预测正确的比例
# Sensitivity = Recall= TP/(TP+ FN)
recall = tp/(tp+fn)
print(recall)
- 特异度:负样本中,预测正确的比例
Specificity= TN/(TN + FP)
# 特异度:负样本中,预测正确的比例
# Specificity= TN/(TN + FP)
specificity = tn/(tn+fp)
print(specificity)
- 精确率:预测结果为正的样本中,预测正确的比例
Precision= TP/(TP+ FP)
# 精确率:预测结果为正的样本中,预测正确的比例
# Precision= TP/(TP+ FP)
precision = tp/(tp+fp)
print(precision)
- F1分数:综合Precision和Recall的一个判断指标
F1 Score = 2*Precision X Recal/(Precision + Recal)
# F1分数:综合Precision和Recall的一个判断指标
# F1 Score = 2*Precision X Recal/(Precision + Recal)
f1_score = 2*precision*recall/(precision+recall)
print(f1_score)
尝试不同k值并计算准确率
# 尝试不同k值并计算准确率
n = [i for i in range(1,21)]
# 创建列表储存值
accuracy_tr_list = []
accuracy_ts_list = []
for i in n :
print(i)
# 创建模型
knn_i = KNeighborsClassifier(n_neighbors=i)
# 训练模型
knn_i.fit(x_tr,y_tr)
# 计算预测值
y_tr_predict = knn_i.predict(x_tr)
y_ts_predict = knn_i.predict(x_ts)
# 计算准确率
accuracy_tr_i = accuracy_score(y_tr,y_tr_predict)
accuracy_ts_i = accuracy_score(y_ts,y_ts_predict)
# 添加准确率
accuracy_tr_list.append(accuracy_tr_i)
accuracy_ts_list.append(accuracy_ts_i)
print(accuracy_tr_list,accuracy_ts_list)
- k值变化对准确率影响的可视化
# k值变化对准确率影响的可视化
fig10 = plt.figure(figsize=(12,5))
plt.subplot(121)
plt.plot(n,accuracy_tr_list,marker='o')
plt.title('training data accuracy')
plt.xlabel('k')
plt.ylabel('accuracy')
plt.subplot(122)
plt.plot(n,accuracy_ts_list,marker='o')
plt.title('test data accuracy')
plt.xlabel('k')
plt.ylabel('accuracy')