线性判别准则与线性分类编程实践
人工智能与机器学习第7-8周作业学习线性判别准则(LDA)和线性分类算法(支持向量机,SVM)。采用Sklearn库 1、编程生成模拟数据集,进行LDA算法练习; 2、对月亮数据集进行SVM分类,分别采用线性核、多项式核和高斯核以及不同的参数(比如惩罚系数C),对比分析结果。
目录
一、线性判别准则
1.原理
线性判别式分析(Linear Discriminant Analysis, LDA),也叫做Fisher线性判别(Fisher Linear Discriminant ,FLD),是模式识别的经典算法,它是在1996年由Belhumeur引入模式识别和人工智能领域的。
线性鉴别分析的基本思想是将高维的模式样本投影到最佳鉴别矢量空间,以达到抽取分类信息和压缩特征空间维数的效果,投影后保证模式样本在新的子空间有最大的类间距离和最小的类内距离,即模式在该空间中有最佳的可分离性。因此,它是一种有效的特征抽取方法。使用这种方法能够使投影后模式样本的类间散布矩阵最大,并且同时类内散布矩阵最小。就是说,它能够保证投影后模式样本在新的空间中有最小的类内距离和最大的类间距离,即模式在该空间中有最佳的可分离性。
公式推导
根据符号说明可得类i的样本均值为:
同理我们也可以得到总体样本均值:
根据类间离散度矩阵和类内离散度矩阵定义,可以得到如下式子:
当然还有另一中类间的离散度矩阵表达方式:
其中是指i类样本的先验概率,即样本中属于i类的概率
2.算法流程
-
计算类内散度矩阵
-
计算类间散度矩阵
-
计算矩阵
-
对矩阵进行特征分解,计算最大的d个最大的特征值对应的特征向量组成。
-
计算投影后的数据点
二、线性分类算法
1.支持向量机
支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)
SVM使用铰链损失函数(hinge loss)计算经验风险(empirical risk)并在求解系统中加入了正则化项以优化结构风险(structural risk),是一个具有稀疏性和稳健性的分类器 [2] 。SVM可以通过核方法(kernel method)进行非线性分类,是常见的核学习(kernel learning)方法之一
2. 历史
SVM是由模式识别中广义肖像算法(generalized portrait algorithm)发展而来的分类器 ,其早期工作来自前苏联学者Vladimir N. Vapnik和Alexander Y. Lerner在1963年发表的研究 。1964年,Vapnik和Alexey Y. Chervonenkis对广义肖像算法进行了进一步讨论并建立了硬边距的线性SVM [7] 。此后在二十世纪70-80年代,随着模式识别中最大边距决策边界的理论研究 、基于松弛变量(slack variable)的规划问题求解技术的出现 ,和VC维(Vapnik-Chervonenkis dimension, VC dimension)的提出 ,SVM被逐步理论化并成为统计学习理论的一部分 。1992年,Bernhard E. Boser、Isabelle M. Guyon和Vapnik通过核方法得到了非线性SVM 。1995年,Corinna Cortes和Vapnik提出了软边距的非线性SVM并将其应用于手写字符识别问题 ,这份研究在发表后得到了关注和引用,为SVM在各领域的应用提供了参考。
三、LDA算法练习
随机数据集
- 导入包
x,y=make_classification(n_samples=500,n_features=2,n_redundant=0,n_classes=2,n_informative=1,n_clusters_per_class=1,class_sep=0.5,random_state=100)
plt.scatter(x[:,0],x[:,1], marker='o', c=y)
plt.show()
x_train=x[:80, :80]
y_train=y[:80]
x_test=x[40:, :]
y_test=y[40:]
- 获得数据集
#分为训练集和测试集,进行模型训练并测试
x_train=x[:350, :350]
y_train=y[:350]
x_test=x[200:, :]
y_test=y[200:]
lda_test=lda()
lda_test.fit(x_train,y_train)
predict_y=lda_test.predict(x_test)#获取预测的结果
count=0
for i in range(len(predict_y)):
if predict_y[i]==y_test[i]:
count+=1
print("预测准确个数为"+str(count))
print("准确率为"+str(count/len(predict_y)))![请添加图片描述](https://img-blog.csdnimg.cn/49dbd2d820bd4c0bbefb1b24d63c9a2a.png)
- 结果
四、SVM编程实现
1.python 3环境下使用scikit-learn封装模块的SVM编程实现
# 导入模块
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm, datasets
% matplotlib inline
# 鸢尾花数据
iris = datasets.load_iris()
X = iris.data[:, :2] # 为便于绘图仅选择2个特征
y = iris.target
# 测试样本(绘制分类区域)
xlist1 = np.linspace(X[:, 0].min(), X[:, 0].max(), 200)
xlist2 = np.linspace(X[:, 1].min(), X[:, 1].max(), 200)
XGrid1, XGrid2 = np.meshgrid(xlist1, xlist2)
# 非线性SVM:RBF核,超参数为0.5,正则化系数为1,SMO迭代精度1e-5, 内存占用1000MB
svc = svm.SVC(kernel='rbf', C=1, gamma=0.5, tol=1e-5, cache_size=1000).fit(X, y)
# 预测并绘制结果
Z = svc.predict(np.vstack([XGrid1.ravel(), XGrid2.ravel()]).T)
Z = Z.reshape(XGrid1.shape)
plt.contourf(XGrid1, XGrid2, Z, cmap=plt.cm.hsv)
plt.contour(XGrid1, XGrid2, Z, colors=('k',))
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', linewidth=1.5, cmap=plt.cm.hsv)
结果
2.SVM处理非线性数据集(月亮数据集)
- 导入包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
- 构建月亮的特征数据并可视化
X, y = datasets.make_moons() #使用生成的数据
#print(X.shape) # (100,2)
#print(y.shape) # (100,)
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()
- 结果
- 生成噪声点并可视化
X, y = datasets.make_moons(noise=0.15,random_state=777) #随机生成噪声点,random_state是随机种子,noise是方差
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()
- 结果
3.核函数
- 随机数据构建
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-4,5,1)#生成测试数据
y = np.array((x >= -2 ) & (x <= 2),dtype='int')
plt.scatter(x[y==0],[0]*len(x[y==0]))# x取y=0的点, y取0,有多少个x,就有多少个y
plt.scatter(x[y==1],[0]*len(x[y==1]))
plt.show()
- 结果
4.核函数处理月亮数据集
- 导入包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
- 月亮数据集
X,y = datasets.make_moons(noise=0.15,random_state=777)
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()
5. 多项式核
# 导入月亮数据集和svm方法
#这是多项式核svm
from sklearn import datasets #导入数据集
from sklearn.svm import LinearSVC #导入线性svm
from sklearn.pipeline import Pipeline #导入python里的管道
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
import numpy as np
from sklearn.preprocessing import StandardScaler,PolynomialFeatures #导入多项式回归和标准化
#生成数据,也是月亮数据集,和线性svm一致
data_x,data_y=datasets.make_moons(noise=0.15,random_state=777)#生成月亮数据集
# random_state是随机种子,nosie是方
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
data_x=data_x[data_y<2,:2]#只取data_y小于2的类别,并且只取前两个特征
plt.show()#此时同上一部分有输出,此处笔主不再示出
def plot_decision_boundary(model,axis):
x0,x1=np.meshgrid(
np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
# meshgrid函数是从坐标向量中返回坐标矩阵
x_new=np.c_[x0.ravel(),x1.ravel()]
y_predict=model.predict(x_new)#获取预测值
zz=y_predict.reshape(x0.shape)
custom_cmap=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,cmap=custom_cmap)
#利用pipeline进行一体化编程,为了方便,将它放入函数中
def PolynomialSVC(degree,c=10):#多项式svm
return Pipeline([
# 将源数据 映射到 3阶多项式
("poly_features", PolynomialFeatures(degree=degree)),
# 标准化
("scaler", StandardScaler()),
# SVC线性分类器
("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42,max_iter=10000))
])
# 进行模型训练并画图
poly_svc=PolynomialSVC(degree=3)
poly_svc.fit(data_x,data_y)
plot_decision_boundary(poly_svc,axis=[-1.5,2.5,-1.0,1.5])#绘制边界
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')#画点
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
结果
6.高斯核
## 导入包 高斯核
from sklearn import datasets #导入数据集
from sklearn.svm import SVC #导入svm
from sklearn.pipeline import Pipeline #导入python里的管道
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
from sklearn.preprocessing import StandardScaler,PolynomialFeatures #导入多项式回归和标准化
#导入数据集
data_x,data_y=datasets.make_moons(noise=0.15,random_state=777)#生成月亮数据集
# random_state是随机种子,nosie是方
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1])
data_x=data_x[data_y<2,:2]#只取data_y小于2的类别,并且只取前两个特征
plt.show()#此时同样有输出,不再示出
# 边界绘制函数,为下面可视化分类做准备
def plot_decision_boundary(model,axis):
x0,x1=np.meshgrid(
np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
# meshgrid函数是从坐标向量中返回坐标矩阵
x_new=np.c_[x0.ravel(),x1.ravel()]
y_predict=model.predict(x_new)#获取预测值
zz=y_predict.reshape(x0.shape)
custom_cmap=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,cmap=custom_cmap)
#利用pipeline进行一体化编程,为了方便,将它放入函数中
def RBFKernelSVC(gamma=1.0):
return Pipeline([
('std_scaler',StandardScaler()),
('svc',SVC(kernel='rbf',gamma=gamma))
])
#进行模型训练画出图形,这里面的gamma参数也很重要,gamma参数越大,支持向量越小,和C是差不多,改变gamma的值,判断区域会发生变化
svc=RBFKernelSVC(gamma=100)#gamma参数很重要,gamma参数越大,支持向量越小
svc.fit(data_x,data_y)
plot_decision_boundary(svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')#画点
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
五、总结
这次作业我学习了线性判别准则(LDA)和线性分类算法(SVM),对月亮数据集进行SVM分类,分别采用线性核、多项式核和高斯核等,了解了LDA和SVM的一些适用范围及其分别的优缺点。当然算法本身的难度会更高,在查阅了一些资料之后也算是解决了这些问题。
六、参考文献
基于jupyter notebook的python编程-----支持向量机学习二(SVM处理线性[鸢尾花数据集]和非线性数据集[月亮数据集])
机器学习 jupyter Python 有监督学习 SVM算法
CS231n——机器学习算法——线性分类(上: 线性分类器)