目录
1. k近邻学习
k近邻学习:一种常用的监督学习方法,没有显式的训练过程。此类学习技术在训练阶段仅仅是把样本保存起来,训练时间开销为零,待收到测试样本后再进行处理;相应的,那些在训练阶段就对样本进行学习处理的方法,称为“急切学习”
工作机制:
- 给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,
- 然后基于这k个“邻居”的信息来进行预测.
方法:
- 在分类任务中可使用“投票法”,即选择这k个样本中出现最多的类别标记作为预测结果;
- 在回归任务中可使用“平均法”,即将这k个样本的实值输出标记的平均值作为预测结果;
- 还可基于距离远近进行加权平均或加权投票,距离越近的样本权重越大.
如下图所示:
给定测试样本x,若其最近邻样本为z,则最近邻分类器出错的概率就是x与z类别标记不同的概率,即·
假设样本独立同分布,且对任意x和任意小正数,在x附近距离范围内总能找到一个训练样本;
结论:泛化错误率不超过贝叶斯最优分类器的错误率的两倍
2. 低维嵌入
k近邻分类器基于一个假设:任意测试样本x附近任意小的距离范围内总能找到一个训练样本,即训练样本的采样密度足够大,或称为“密采样”(dense sample).
然而,这个假设在现实任务中通常很难满足
维度灾难:在高维情形下出现的数据样本稀疏、距离计算困难等问题
方法:
- 降维:通过某种数学变换将原始高维属性空间转变为一个低维“子空间”(subspace),
在很多时候,人们观测或收集到的数据样本虽是高维的,但与学习任务密切相关的也许仅是某个低维分布,即高维空间中的一个低维“嵌入”(embedding).如下图所示:
多维缩放:原始空间中样本之间的距离在低维空间中得以保持
降维后样本的内积矩阵,,有
令降维后的样本Z被中心化,显然,矩阵B的行与列之和均为零.易知
令
最后可得:
由此即可通过降维前后保持不变的距离矩阵D求取内积矩阵B.
对矩阵B做特征值分解,而且仅需降维后的距离与原始空间中的距离尽可能接近,而不必严格相等.则Z可表达为:
低维空间:对原始高维空间进行线性变换
变换后样本:
线性降维方法:基于线性变换来进行降维的方法,不同之处是对低维子空间的性质有不同的要求,相当于对W施加了不同的约束.
3. 主成分分析
主成分分析:一种常用的降维方法
可以表达所有样本的超平面性质:
- 最近重构性:样本点到这个超平面的距离都足够近;
- 最大可分性:样本点在这个超平面上的投影能尽可能分开.
从最近重构性进行推导:
考虑整个训练集,原样本点与基于投影重构的样本点之间的距离为
根据最近重构性,上式应被最小化,考虑到是标准正交基,是协方差矩阵,有
这就是主成分分析的优化目标
从最大可分性进行推导:
于是优化目标可写为
所有样本点的投影能尽可能分开,且使投影后样本点的方差最大化,如图3.1所示.
降维后低维空间的维数d'通常是由用户事先指定,或通过在d'值不同的低维空间中对k近邻分类器(或其他开销较小的学习器)进行交叉验证来选取较好的出值.对PCA,还可从重构的角度设置一个重构阈值,例如t = 95%,然后选取使下式成立的最小d'值:
4. 核化线性降维
线性降维方法假设:从高维空间到低维空间的函数映射是线性的,
然而,在不少现实任务中,可能需要非线性峡射才能找到恰当的低维嵌入.如下图所示:
为了对“原本采样的”低维空间与降维后的低维空间加以区别,我们称前者为“本真”(intrinsic)低维空间.
核主成分分析:一种常用的非线性降维方法,基于核技巧对线性降维进行“核化”
将高维特征空间中把数据投影到超平面,即:
对新样本x,其投影后的第j (j=1,2,.. ., d')维坐标为
KPCA需对所有样本求和,因此它的计算开销较大.
5. 流形学习
流形学习:一种借助拓扑流形概念的降维方法,
流形:指在局部与欧式空间同胚的空间,即在局部与欧式空间具有相同的性质,能用欧氏距离计算样本之间的距离。
这样即使高维空间的分布十分复杂,但是在局部上依然满足欧式空间的性质,基于流形学习的降维正是这种“邻域保持”的思想。
等度量映射(Isomap)试图在降维前后保持邻域内样本之间的距离,
局部线性嵌入(LLE)则是保持邻域内样本之间的线性关系
5.1 等度量映射(Isomap)
等度量映射出发点:高维空间中的直线距离具有误导性,因为有时高维空间中的直线距离在低维空间中是不可达的。因此利用流形在局部上与欧式空间同胚的性质,可以使用近邻距离来逼近测地线距离,即对于一个样本点,它与近邻内的样本点之间是可达的,且距离使用欧式距离计算,这样整个样本空间就形成了一张近邻图,高维空间中两个样本之间的距离就转为最短路径问题。可采用著名的Dijkstra算法或Floyd算法计算最短距离,得到高维空间中任意两点之间的距离后便可以使用MDS算法来其计算低维空间中的坐标。
从MDS算法的描述中我们可以知道:MDS先求出了低维空间的内积矩阵B,接着使用特征值分解计算出了样本在低维空间中的坐标,但是并没有给出通用的投影向量w,因此对于需要降维的新样本无从下手,书中给出的权宜之计是利用已知高/低维坐标的样本作为训练集学习出一个“投影器”,便可以用高维坐标预测出低维坐标。
对于近邻图的构建,常用的有两种方法:
- 一种是指定近邻点个数,像kNN一样选取k个最近的邻居;
- 另一种是指定邻域半径,距离小于该阈值的被认为是它的近邻点。
但两种方法均会出现下面的问题:
- 若邻域范围指定过大,则会造成“短路问题”,即本身距离很远却成了近邻,将距离近的那些样本扼杀在摇篮。
- 若邻域范围指定过小,则会造成“断路问题”,即有些样本点无法可达了,整个世界村被划分为互不可达的小部落。
5.2 局部线性嵌入(LLE)
不同于Isomap算法去保持邻域距离,LLE算法试图去保持邻域内的线性关系,假定样本xi的坐标可以通过它的邻域样本线性表出:
LLE算法分为两步走:
- 首先第一步根据近邻关系计算出所有样本的邻域重构系数w:
令有闭式解:
2.接着根据邻域重构系数不变,去求解低维坐标:
令
这样利用矩阵M,优化问题可以重写为:
M特征值分解后最小的d’个特征值对应的特征向量组成Z
6 度量学习
度量学习:一种机器学习方法,旨在学习一种度量或距离度量,以便在特定任务中更好地衡量样本之间的相似性或距离。
在度量学习中,我们试图通过学习一个映射函数,将输入样本从原始特征空间映射到一个新的特征空间,使得在新的特征空间中,相似的样本之间的距离较小,而不相似的样本之间的距离较大。
度量学习的目标是在保持样本之间的关系的同时,优化样本之间的度量或距离。
- 有监督度量学习:在有监督的设置下,我们利用标记的训练样本来学习一个度量函数,使得同一类别的样本之间的距离尽可能小,而不同类别的样本之间的距离尽可能大。典型的有监督度量学习方法包括最近邻度量学习(Nearest Neighbor Metric Learning)和支持向量机度量学习(Support Vector Machine Metric Learning)等。
- 无监督度量学习:在无监督的设置下,我们没有类别标签的信息,但仍然希望学习一个合适的度量函数。无监督度量学习方法尝试通过数据自身的结构信息来学习距离度量,例如,典型的方法包括流形学习(Manifold Learning)和聚类优化(Cluster Optimization)等。
度量学习的应用广泛,特别是在许多涉及相似性比较和距离度量的任务中,如人脸识别、目标跟踪、图像检索和推荐系统等。通过学习合适的距离度量,可以改善这些任务的效果,并提高模型的鲁棒性和泛化能力。
首先要学习出距离度量必须先定义一个合适的距离度量形式。对两个样本xi与xj,它们之间的平方欧式距离为:
若各个属性重要程度不一样即都有一个权重,则得到加权的平方欧式距离:
此时各个属性之间都是相互独立无关的,但现实中往往会存在属性之间有关联的情形,例如:身高和体重,一般人越高,体重也会重一些,他们之间存在较大的相关性。这样计算距离就不能分属性单独计算,于是就引入经典的马氏距离(Mahalanobis distance):
标准的马氏距离中M是协方差矩阵的逆,马氏距离是一种考虑属性之间相关性且尺度无关(即无须去量纲)的距离度量。
矩阵M也称为“度量矩阵”,为保证距离度量的非负性与对称性,M必须为(半)正定对称矩阵,这样就为度量学习定义好了距离度量的形式,换句话说:度量学习便是对度量矩阵进行学习。
机器学习算法几乎都是在优化目标函数,从而求解目标函数中的参数。同样对于度量学习,也需要设置一个优化目标:
假定我们是希望提高近邻分类器的性能,则可将M直接嵌入到近邻分类器的评价指标中去,通过优化该性能指标相应地求得M.
近邻成分分析:用概率投票法.对于任意样本xj,它对xi分类结果影响的概率为
最终的优化目标:
通过求解下面这个凸优化问题获得适当的度量矩阵M
二、实验
1. MDS算法
- Step 1: 构造原始数据
假设我们有一个5个样本的高维数据集,每个样本有10个特征
- Step 2: 计算样本间的距离矩阵
在MDS中,我们需要提供一个距离或相似性矩阵作为输入。
这里我们使用欧氏距离作为示例,但实际应用中可根据数据特性和需求选择其他距离度量。
- Step 3: 实例化MDS模型并进行降维
我们使用度量MDS(Metric MDS),并指定目标维度为2,以便于后续可视化
- Step 4: 可视化降维后的结果
import numpy as np
from sklearn.manifold import MDS
import matplotlib.pyplot as plt
np.random.seed(0)
X_high_dim = np.random.rand(5, 10)
from sklearn.metrics.pairwise import euclidean_distances
dist_matrix = euclidean_distances(X_high_dim)
mds = MDS(n_components=2, dissimilarity='precomputed')
X_mds = mds.fit_transform(dist_matrix)
plt.figure(figsize=(8, 6))
plt.scatter(X_mds[:, 0], X_mds[:, 1], s=100, color='steelblue', alpha=0.8)
plt.title('2D MDS Visualization')
plt.xlabel('Dimension 1')
plt.ylabel('Dimension 2')
plt.grid(True, linestyle='dotted')
plt.show()
2.PCA算法
import numpy as np
import matplotlib.pyplot as plt
X=np.empty((100,2))
X[:,0]=np.random.uniform(0,100,size=100)
X[:,1]=0.6*X[:,0]+3+np.random.normal(0,10,size=100)
plt.scatter(X[:,0],X[:,1])
#对数据进行中心化处理:减去每个特征的均值
def demean(X):
return X-np.mean(X,axis=0)
X_demean=demean(X) #保存中心化后的数据
plt.figure(2)
plt.scatter(X_demean[:,0],X_demean[:,1])
#定义目标函数:数据在投影到方向 w 上时的方差
def f(w,X):
return np.sum((X.dot(w)**2))/len(X)
#目标函数关于参数 w 的梯度
def df_math(w,X):
return X.T.dot(X.dot(w))*2/len(X)
def direction(w):
return w / np.linalg.norm(w)
def gradient_ascent(df, X, initial_w, eta, n_iters = 1e4, epsilon=1e-8):
w = direction(initial_w)
cur_iter = 0
while cur_iter < n_iters:
gradient = df(w, X)
last_w = w
w = w + eta * gradient
w = direction(w) # 注意1:每次求一个单位方向
if(abs(f(w, X) - f(last_w, X)) < epsilon):
break
cur_iter += 1
return w
initial_w = np.random.random(X.shape[1]) # 注意2:不能用0向量开始
eta = 0.001
w = gradient_ascent(df_math, X_demean, initial_w, eta)
plt.figure(3)
plt.scatter(X_demean[:,0], X_demean[:,1])
plt.plot([0, w[0]*50], [0 , w[1]*50], color='r')
原始数据散点图:
中心化之后的数据散点图:
主成分的方向(图中红色直线):
3. isomap算法
import numpy
from cffi.backend_ctypes import xrange
from matplotlib import pyplot
from sklearn import datasets, metrics
from sklearn.datasets import make_blobs
def floyd(D,n_neighbors=15):
Max=numpy.max(D)*1000
n1,n2=D.shape
k=n_neighbors
D1=numpy.ones((n1,n1))*Max
D_arg=numpy.argsort(D,axis=1)
for i in range(n1):
D1[i,D_arg[i,0:k+1]]=D[i,D_arg[i,0:k+1]]
for k in xrange(n1):
for i in xrange(n1):
for j in xrange(n1):
if D1[i,k]+D1[k,j]<D1[i,j]:
D1[i,j]=D1[i,k]+D1[k,j]
return D1
def calculate_distance(x, y):
d = numpy.sqrt(numpy.sum((x - y) ** 2))
return d
def calculate_distance_matrix(x, y):
d = metrics.pairwise_distances(x, y)
return d
def cal_B(D):
(n1, n2) = D.shape
DD = numpy.square(D)
Di = numpy.sum(DD, axis=1) / n1
Dj = numpy.sum(DD, axis=0) / n1
Dij = numpy.sum(DD) / (n1 ** 2)
B = numpy.zeros((n1, n1))
for i in xrange(n1):
for j in xrange(n2):
B[i, j] = (Dij + DD[i, j] - Di[i] - Dj[j]) / (-2)
return B
def MDS(data, n=2):
D = calculate_distance_matrix(data, data)
B = cal_B(D)
Be, Bv = numpy.linalg.eigh(B)
Be_sort = numpy.argsort(-Be)
Be = Be[Be_sort]
Bv = Bv[:, Be_sort]
Bez = numpy.diag(Be[0:n])
Bvz = Bv[:, 0:n]
Z = numpy.dot(numpy.sqrt(Bez), Bvz.T).T
return Z
def Isomap(data,n=2,n_neighbors=30):
D=calculate_distance_matrix(data,data)
D_floyd=floyd(D)
B=cal_B(D_floyd)
Be,Bv=numpy.linalg.eigh(B)
Be_sort=numpy.argsort(-Be)
Be=Be[Be_sort]
Bv=Bv[:,Be_sort]
Bez=numpy.diag(Be[0:n])
Bvz=Bv[:,0:n]
Z=numpy.dot(numpy.sqrt(Bez),Bvz.T).T
return Z
def generate_curve_data():
xx,target=datasets.make_s_curve(400, random_state=9)
return xx,target
if __name__=='__main__':
data,target=generate_curve_data()
Z_Isomap=Isomap(data,n=2)
Z_MDS=MDS(data)
figure=pyplot.figure()
pyplot.suptitle('ISOMAP COMPARE TO MDS')
pyplot.subplot(1,2,1)
pyplot.title('ISOMAP')
pyplot.scatter(Z_Isomap[:,0],Z_Isomap[:,1],c=target,s=60)
pyplot.subplot(1,2,2)
pyplot.title('MDS')
pyplot.scatter(Z_MDS[:,0],Z_MDS[:,1],c=target,s=60)
pyplot.show()
原始数据:
降维结果: