一.编程生成模拟数据集,进行LDA算法练习
1.线性判别准则LDA
1.LDA的基本思想
LDA是一种监督学习的降维技术,也就是说它的数据集的每个样本是有类别输出的。这点和PCA不同。PCA是不考虑样本类别输出的无监督降维技术。LDA的思想可以用一句话概括,就是“投影后类内方差最小,类间方差最大”。什么意思呢? 我们要将数据在低维度上进行投影,投影后希望每一种类别数据的投影点尽可能的接近,而不同类别的数据的类别中心之间的距离尽可能的大。
假设我们有两类数据 分别为红色和蓝色,如下图所示,这些数据特征是二维的,我们希望将这些数据投影到一维的一条直线,让每一种类别数据的投影点尽可能的接近,而红色和蓝色数据中心之间的距离尽可能的大。
2.多分类LDA原理
有了二类LDA的基础,我们再来看看多类别LDA的原理。
假设我们的数据集D={(x1,y1),(x2,y2),…,((xm,ym))},其中任意样本xi为n维向量,yi∈{C1,C2,…,Ck}。我们定义Nj(j=1,2…k)为第j类样本的个数Xj(j=1,2…k)为第j类样本的集合,而μj(j=1,2…k)为第j类样本的均值向量,定义Σj(j=1,2…k)为第j类样本的协方差矩阵。在二类LDA里面定义的公式可以很容易的类推到多类LDA。
由于我们是多类向低维投影,则此时投影到的低维空间就不是一条直线,而是一个超平面了。假设我们投影到的低维空间的维度为d,对应的基向量为(w1,w2,…wd),基向量组成的矩阵为W, 它是一个n×d的矩阵。
此时我们的优化目标应该可以变成为:
其中Sb=∑j=1kNj(μj−μ)(μj−μ)T,μ为所有样本均值向量。Sw=∑j=1kSwj=∑j=1k∑x∈Xj(x−μj)(x−μj)T但是有一个问题,就是WTSbW
和WTSwW都是矩阵,不是标量,无法作为一个标量函数来优化!也就是说,我们无法直接用二类LDA的优化方法,怎么办呢?一般来说,我们可以用其他的一些替代优化目标来实现。
常见的一个LDA多类优化目标函数定义为:
其中∏diagA为A的主对角线元素的乘积,W为n×d的矩阵。
J(W)的优化过程可以转化为:
仔细观察上式最右边,这不就是广义瑞利商嘛!最大值是矩阵S−1wSb
的最大特征值,最大的d个值的乘积就是矩阵S−1wSb的最大的d个特征值的乘积,此时对应的矩阵W为这最大的d个特征值对应的特征向量张成的矩阵。
由于W是一个利用了样本的类别得到的投影矩阵,因此它的降维到的维度d最大值为k-1。为什么最大维度不是类别数k呢?因为Sb中每个μj−μ的秩为1,因此协方差矩阵相加后最大的秩为k(矩阵的秩小于等于各个相加矩阵的秩的和),但是由于如果我们知道前k-1个μj后,最后一个μk可以由前k-1个μj线性表示,因此Sb的秩最大为k-1,即特征向量最多有k-1个。
2.算法实现
1.包引入与生成模拟数据集
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as lda
from sklearn.datasets._samples_generator import make_classification
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
x,y=make_classification(n_samples=200,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[:60, :60]
y_train=y[:60]
x_test=x[40:, :]
y_test=y[40:]
2.数据集分组
x_train=x[:150, :150]
y_train=y[:150]
x_test=x[50:, :]
y_test=y[50:]
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)))
二.对月亮数据集进行SVM分类,分别采用线性核、多项式核和高斯核以及不同的参数(比如惩罚系数C),对比分析结果。
1.线性分类算法
- 支持向量机(SVM)
支持向量机(support vector machines)是一种二分类模型,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化,最终转化为一个凸二次规划问题来求解。由简至繁的模型包括:
当训练样本线性可分时,通过硬间隔最大化,学习一个线性可分支持向量机;
当训练样本近似线性可分时,通过软间隔最大化,学习一个线性支持向量机;
当训练样本线性不可分时,通过核技巧和软间隔最大化,学习一个非线性支持向量机;
2.对月亮数据集进行SVM分类
import matplotlib.pyplot as plt
from sklearn.pipeline import Pipeline
import numpy as np
import matplotlib as mpl
from sklearn.datasets import make_moons
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
# 为了显示中文
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False#rc配置或rc参数,通过rc参数可以修改默认的属性,包括窗体大小、每英寸的点数、线条宽度、颜色、样式、坐标轴、坐标和网络属性、文本、字体等。
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)#生成月亮数据集
def plot_dataset(X, y, axes):#绘制图形
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.axis(axes)
plt.grid(True, which='both')
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plt.title("月亮数据",fontsize=20)
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
3.使用SVM对月亮数据集聚类:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_moons
# 导入数据集
X,y = make_moons(n_samples=200,random_state=0,noise=0.05)
h = .02 # 网格中的步长
# 创建支持向量机实例,并拟合出数据
C = 1.0 # SVM正则化参数
svc = svm.SVC(kernel='linear', C=C).fit(X, y) # 线性核
rbf_svc = svm.SVC(kernel='rbf', gamma=0.7, C=C).fit(X, y) # 径向基核
poly_svc = svm.SVC(kernel='poly', degree=3, C=C).fit(X, y) # 多项式核
lin_svc = svm.LinearSVC(C=C).fit(X, y) #线性核
# 创建网格,以绘制图像
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))
# 图的标题
titles = ['SVC with linear kernel',
'LinearSVC (linear kernel)',
'SVC with RBF kernel',
'SVC with polynomial (degree 3) kernel']
for i, clf in enumerate((svc, lin_svc, rbf_svc, poly_svc)):
# 绘出决策边界,不同的区域分配不同的颜色
plt.subplot(2, 2, i + 1) # 创建一个2行2列的图,并以第i个图为当前图
plt.subplots_adjust(wspace=0.4, hspace=0.4) # 设置子图间隔
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) #将xx和yy中的元素组成一对对坐标,作为支持向量机的输入,返回一个array
# 把分类结果绘制出来
Z = Z.reshape(xx.shape) #(220, 280)
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.8) #使用等高线的函数将不同的区域绘制出来
# 将训练数据以离散点的形式绘制出来
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.xticks(())
plt.yticks(())
plt.title(titles[i])
plt.show()
总结
LDA算法优点
- 在降维过程中可以使用类别的先验知识经验,而像PCA这样的无监督学习则无法使用类别先验知识。
- LDA在样本分类信息依赖均值而不是方差的时候,比PCA之类的算法较优。
LDA算法缺点
- LDA不适合对非高斯分布样本进行降维,PCA也有这个问题。
- LDA降维最多降到类别数k-1的维数,如果我们降维的维度大于k-1,则不能使用LDA。当然目前有一些LDA的进化版算法可以绕过这个问题。
- LDA在样本分类信息依赖方差而不是均值的时候,降维效果不好。
参考
https://icode9.com/content-1-1207197.html
https://blog.csdn.net/gwplovekimi/article/details/80299070