1. 机器学习原理
常见名词
- 训练数据
- 类
- samples数据样本表
- 训练集 X_train,y_train
- 测试集 X_test,y_test
2. 机器学习分类
有监督学习
- 分类
- K近邻、朴素贝叶斯、决策树、SVM
- 回归
- 线性回归、逻辑回归、岭回归
无监督学习
- 聚类
- K-means
半监督学习
- 深度学习
3. 深度剖析
思考
机器学习相关内容过多,错综复杂
原理及分类已经大致了解了,
还未掌握部分:
- 各个分类下算法原理
- 使用方法
- 各自解决什么样的问题
- 最终返回什么内容
3.1 k-近邻算法
原理
K-近邻算法采用测量不同特征值之间的距离方法进行分类。
- 优点:精度高、对异常值不敏感、无数据输入假定。
- 缺点:时间复杂度高、空间复杂度高。
- 适用数据范围:数值型和标称型。
如上图 通过训练已知数据分析AB分类点的特征,然后给一数据,通过一定范围内该点到AB分类各点的距离来得出该点属于AB哪个分类
因为数据多、特征值不确定,所有很容易看出缺点(时间、空间复杂度高)
示例
案例一:
KNN算法解决电影分类问题,通过对已有数据训练,从而预测新数据属于哪类电影(爱情片/动作片)
# 读取文件
films = pd.read_excel('tests.xlsx',sheet_name=1)
samples = films[['武打镜头','接吻镜头']]
# 样本标签
target = films['分类情况']
# 创建一个新电影,武打镜头6个,接吻镜头9个
dancer = np.array([[6,9]])
# 画关系图
plt.scatter(samples['武打镜头'],samples['接吻镜头'])
plt.scatter(dancer[:,0],dancer[:,1],c='red')
plt.ylabel('kiss',fontsize=20)
plt.xlabel('action',fontsize=20)
# 构建KNN算法模型
from sklearn.neighbors import KNeighborsClassifier
knnclf = KNeighborsClassifier()
# 训练数据
knnclf.fit(samples,target)
# 预测新的样本
knnclf.predict(dancer)
在scikit-learn
库中使用k-近邻算法
- 分类问题:from sklearn.neighbors import
KNeighborsClassifier
- 回归问题:from sklearn.neighbors import
KNeighborsRegressor
分类问题
示例1.
身高、体重、鞋子尺码数据对应性别
并可以分析该算法的准确率
# 部分代码 提供解决问题的思想
1.获取数据样本集
samples=pd.read_excel(...)
# 特征
features = samples[['身高','体重','尺码']]
# 结果
target = samples['性别']
2.拆分数据集(训练集、测试集)
# 用于训练数据
X_train = features[:8]
y_train = target[:8]
# 用于测试算法模型是否准确
X_test = features[8:]
y_test = target[8:]
3.构建算法模型对象
# 构建算法模型对象
from sklearn.neighbors import KNeighborsClassifier
# 预测点跟离它最近的5个点进行比较
knnclf = KNeighborsClassifier(n_neighbors=5)
4.训练模型
knnclf.fit(X_train,y_train)
5.预测测试集
y_ = knnclf.predict(X_test)
6.对结果进行评分
可以用score()方法
示例2.鸢尾花
前面仍然是导包,读取样本集,拆分训练集测试集
问题:
# 因为鸢尾花有4个特征,无法绘制4维空间
# 所以选择前两个特征来绘制一个二维空间来查看鸢尾花的分布情况
plt.scatter(train.values[:,0],train.values[:,1],c=target)
回归问题
回归用于对趋势的预测
- 生成模型,训练数据
- 使用模型,预测数据
- 绘图显示数据
注:生成的趋势可能欠拟合、过拟合、最佳拟合状态
欠拟合就是过于偏离真实数据(类似于判别男女,得到有眼睛 有鼻子的都是男人结论)
过拟合是过于贴近每个数据特征(类似于得到 会唱歌,姓王的都是男人结论)
例1. 随机生成一组数据,对数据添加噪声,测试最终数据是否满足预估趋势(正弦)
from sklearn.neighbors import KNeighborsRegressor
1.生成样本数据
x = np.linspace(-np.pi,np.pi,60)
y = np.sin(x)
plt.scatter(x,y)
2.增加噪音
np.random.seed(2)
noise = np.random.random(size=30) - 0.5
y[::2] += noise
3.生成测试数据结果
knn = KNeighborsRegressor(n_neighbors=7)
knn.fit(x.reshape(-1,1),y)
4.获取测试数据
X_test = np.linspace(x.min(),x.max(),100).reshape(-1,1)
y_ = knn.predict(X_test)
5.绘图显示
plt.plot(X_test,y_,color='orange',label='predict')
plt.scatter(x,y,color='green',label='true-data')
plt.legend()
再来分析一个复杂案例
例2.判断美国一个州人群年收入与年龄、职业、工作时长、受教育程度之间的关联
思考:
- 很明显几个特征都与年收入有关联,但有些特征(如职业)是字符无法参与运算
- 结果(年薪)是按照”>50k”,”<50k”来显示的,也需要转换为可以参与运算的值
- 特征之间怎样建立联系才能使结果偏差不那么大
问题解决
1.将职业这一列去重转换为相对应的映射
def mytransfunc(item):
# 假设这个列表中的职业,从前到后,职业的相关性越来越差
occ_unique = train['occupation'].unique()
# 返回与职业对应的索引
return np.argwhere(item == occ_unique)[0,0]
train['occupation'] = train['occupation'].map(mytransfunc)
2.将结果集分类
# 如果标签项并不是离散性数据,可以定义一个阈值,来对数据进行二分,或者多分
def mytargetfunc(item):
if item == '<=50K':
return 0
else:
return 1
target = target.map(mytargetfunc)
3.特征预处理
# 由于age和hours_per_week起到主导作用,所以需要进行归一处理,让各个特征对结果的影响更加公平
# 每一个数据/每一列的总和
for column in train.columns:
train[column] = train[column]/train[column].sum()
优化数据集的方式:
- 特征选择、归一化模型、数据清洗、降维
- 调整参数
3.2 Linear
回归算法
问题
对连续型的数据做出预测
原理
连续型的数据肯定满足线性关系
Y=X*W
如果确定W?
可以使用预测Y值与真实y值差平方的累加使正负误差相互抵消,来找出误差最小的W
最小二乘法
实例
查看特征S1与血糖含量的关系
对比线性回归与knn回归的使用
1.导包、获取数据。。。
2.还是导包
# knn
from sklearn.neighbors import KNeighborsRegressor
# 线性回归
from sklearn.linear_model import LinearRegression
3.拆分训练集和结果集
4.选择knn回归和linear回归,分别进行
knn = KNeighborsRegressor()
line = LinearRegression()
knn.fit(X_train,y_train)
line.fit(X_train,y_train)
y1_ = knn.predict(X_test)
y2_ = line.predict(X_test)
3.3 岭回归ridge
相关小知识:
- 矩阵,单位矩阵,方阵,逆矩阵
- 满秩矩阵
解决问题:
- 数据点少于变量个数
- 变量间存在共线性(最小二乘回归得到的系数不稳定,方差很大)
- 岭回归作为一种缩减算法可以判断哪些特征重要或者不重要,有点类似于降维的效果
- 缩减算法可以看作是对一个模型增加偏差的同时减少方差
原理:
岭回归是加了二阶正则项的最小二乘,主要适用于过拟合严重或各变量之间存在多重共线性的时候,岭回归是有bias的,这里的bias是为了让variance更小。
步骤:
- 训练
- 预测
- 绘制图形
示例
同时使用线性回归与岭回归处理一组数据(随机生成),
练习岭回归的同时加深下线性回归印象
1.导包...
2.生成数据
n_samples = 50
n_features = 200
x = np.random.random(size=(n_samples,n_features))
y = np.random.random(n_samples)
3.分别使用两种回归模型训练,查看两种模型的系数变化
line = LinearRegression()
# 调整岭回归系数,观察结果
ridge = Ridge(alpha=30)
# 训练
line.fit(x,y)
ridge.fit(x,y)
# 系数
coef1 = line.coef_
coef2 = ridge.coef_
4.画图比较
plt.plot(coef1,label='linear')
plt.plot(coef2,label='ridge')
plt.legend()
# 岭回归有缩减系数的功能
【备注】coef_
函数可以获取机器学习模型中各个特征值的系数
拓展:岭回归系数
1. 创建一个假象数据样本集
X = 1. / (np.arange(1, 11) + np.arange(0, 10).reshape(-1,1))
y = np.array([1,2,3,4,5,6,7,8,9,0])
2. 创建一个alpha集合,用以验证种不同alpha值对预测系数的结果的影响
# 创建100个λ系数
alphas = np.logspace(-10,-2,100)
3. 创建岭回归机器学习算法对象
4. 使用不同的alpha进行数据训练,保存所有训练结果的coef_
ridge = Ridge()
coefs = []
for alpha in alphas:
ridge.set_params(alpha=alpha)
ridge.fit(X,y)
coef = ridge.coef_
coefs.append(coef)
5. 绘图查看alpha参数和coefs的关系
6. 通过岭迹线来观察alpha值的最优区间
# alpha作为横轴 coefs作为纵轴
plt.plot(alphas,coefs)
plt.xscale('log')
结论
由图可以看出随系数越来越大,准确度越来越高,但λ等于0时没有意义,所以取绿色圆圈部分为最优区间最合适
3.4 lasso
回归
原理:
【拉格朗日乘数法】
- 对于参数w增加一个限定条件,能到达和岭回归一样的效果:
- 在lambda足够小的时候,一些系数会因此被迫缩减到0
思考:
缩减系数有什么好处?
- 对一些对结果影响不大甚至无关的特征缩减系数使之为0,
- 降低特征维度,方便提高运算效率与准确度
- 降低过拟合
示例
普通线性回归、岭回归与lasso回归比较
导包,并导入sklearn.metrics.r2_score用于给模型打分
使用numpy创建数据X,创建系数,对系数进行处理,对部分系数进行归零化操作,然后根据系数进行矩阵操作求得目标值
n_samples = 50 n_features = 200 X = np.random.randint(-100,100,size=(n_samples,n_features)) coef = np.random.random(size=200)
随机选出10个系数作为有效系数,其他全部清零
# 先生成数据特征的所有索引 index = np.arange(n_features) # 把索引进行随机排序 np.random.shuffle(index) # 取出排序后的后190个索引 zero_index = index[10:] coef[zero_index] = 0
增加噪声
# 利用原始系数跟样本集进行点乘,得到真实的标签值 y = np.dot(X,coef) # 对标签添加噪声数据 np.random.seed(0) noise = np.random.random(50) - 0.5 y += noise
数据训练、预测
linear = LinearRegression() ridge = Ridge() lasso = Lasso() linear.fit(X,y) ridge.fit(X,y) lasso.fit(X,y)
数据视图,此处获取各个算法的训练数据的coef_系数
coef1 = linear.coef_ coef2 = ridge.coef_ coef3 = lasso.coef_ plt.figure(figsize=(10,6)) axes1 = plt.subplot(2,2,1) axes1.plot(coef,color='yellow') axes1.set_title('true-coef') axes2 = plt.subplot(2,2,2) axes2.plot(coef1,color='pink') axes2.set_title('linear-coef') axes3 = plt.subplot(2,2,3) axes3.plot(coef2,color='green') axes3.set_title('ridge-coef') axes4 = plt.subplot(2,2,4) axes4.plot(coef3,color='cyan') axes4.set_title('lasso-coef')
结论
可以看出来,lasso
回归与原数据系数图像最为拟合
但在生产中,数据并不像我们生成的这样有引导性,score
得到的评分也并非那么高
所以需要我们不断的练习,凭经验选择最优方案,提高准确度
3.5 逻辑斯蒂回归logistics
思想:
利用Logistics回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的“回归” 一词源于最佳拟合,表示要找到最佳拟合参数集
原理:
- 找一个合适的预测函数
h函数
用来预测输入数据的判断结果,预测函数大概是线性还是非线性- 构造一个
Cost函数
(损失函数),来表示预测的输出与训练数据类别之间的偏差,计算偏差的函数记为J(θ) 函数
- 显然,偏差越小预测越准,最终只需要找J(θ) 函数的最小值。这就是逻辑斯蒂回归的原理
解决问题:
分类
问题,名为回归 实则解决分类问题优缺点:
- 实现简单,易于理解与实现,计算代价较低,速度快,存储资源低
- 容易欠拟合,分类精度不高
示例:
手写数字数据集的分类
- 导入
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
- 处理数据
digits = datasets.load_digits()
x_digits = digits.data
y_digits = digits.target
x_train = x_digits[:round(.9*len(x_digits))]
x_test = x_digits[round(.9*len(x_digits)):]
y_train = y_digits[:round(.9*len(y_digits))]
y_test = y_digits[round(.9*len(y_digits)):]
- 训练和预测
knn = KNeighborsClassifier()
logistic = LogisticRegression()
display('KNN score: %f'%knn.fit(x_train,y_train).score(x_test,y_test),
'Logistic Score: %f'%logistic.fit(x_train,y_train).score(x_test,y_test))
使用make_blobs产生数据集进行分类
- 导入
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import make_blobs #生成用于聚类的各向同性高斯斑点
from sklearn.linear_model import LogisticRegression
- 处理数据
# 设置三个中心点,建立一个三分类问题
centers = [[-5,0],[0,1.5],[5,-1]]
X,y = make_blobs(n_samples=1000, centers=centers, random_state=40)
- 训练数据
clf = LogisticRegression()
clf.fit(X,y)
- 图片背景图片点
# 背景(网格)
h = 0.02
x_min,x_max = X[:,0].min()-1,X[:,0].max()+1
y_min,y_max = X[:,1].min()-1,X[:,1].max()+1
# 从坐标向量返回坐标矩阵
# 图片的背景显示坐标
xx,yy = np.meshgrid(np.arange(x_min,x_max,h),
np.arange(y_min,y_max,h))
- 预测数据
# 得到网格上每个点的分类情况
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
z = Z.reshape(xx.shape)
#预测背景图片的点,从而知道划分区域
- 画图
# 画图
plt.figure()
#绘制轮廓线,填充轮廓
#plt.contourf(xx,yy,z,cmap = plt.cm.Paired)
plt.pcolormesh(xx,yy,z,cmap = plt.cm.Paired)
plt.title("Logistic Regression")
plt.axis('tight')
colors = 'bry'
for i,color in zip(clf.classes_,colors):
idx = np.where(y==i)
plt.scatter(X[idx,0],X[idx,1],c=color,cmap = plt.cm.Paired)