七月在线机器学习笔记
#谱和谱聚类
'''
方阵的谱:方阵作为线性算子,它的所有特征值的全体
谱半径:方阵最大的特征值
矩阵A的谱半径:的最大特征值,T即转置
谱聚类:一般的说,是一种基于图论的聚类方法,通过对样本数据的拉普拉斯矩阵的特征向量进行聚类,从而达到对样本数据聚类的目的。
'''
#谱分析的整体过程
'''
给定一组数据x1,x2,...xn,记任意两个点之间的相似度(“距离”的减函数)为Sij=<xi,xj>,形成相似度图(similarity graph):G=(V,E) 。如果xi和xj之间
的相似度Sij大于一定的阈值,那么,两个点是连接的,权值记做Sij。[往往大于阈值的放到矩阵里,小于的直接置0]
接下来,可以用相似度图来解决样本数据的聚类问题:找到图的一个划分,形成若干个组(Group),使得不同组之间有较低的权值,组内有较高的权值。
W:邻接矩阵(wij) ,i,j=1,...,n 相似度矩阵
顶点的度di-->度矩阵D(对角阵)
A和B是图G的不相交子图,则定义子图的连接权:
即两个图之间所有点连接权之间的加和,越小表明应该断开
相似度图G的建立方法:
全连接图:高斯相似度函数---距离越大,相似度越小
使用高斯相似度函数可以很好的建立权值矩阵。但缺点是建立的矩阵不是稀疏的
ε近邻图:(当数据有不同的“密度”时,往往发生部分连接不紧密问题)
给定参数ε,如何确定?---- 图G的权值的均值;图G的最小生成树的最大边
k近邻图:(可以解决数据存在不同密度时有些无法连接的问题)--优先尝试
若vi的k最近邻包含vj,vj的k最近邻不一定包含vi:有向图
忽略方向的图,往往简称“k近邻图”
两者都满足才连接的图,称作“互k近邻图(mutual)”
'''
#拉普拉斯矩阵及其性质:
'''
L=D - W
(因为前面W的定义,wii=0,则W矩阵第i行的加和即为该顶点i的度),因此D-1W的每行加和为1,因此可以表示顶点i跳到j的转移概率,pij值较大的表明i向j转移的概率较大
按照这个点的转移概率,依次转移到别的点上去,然后最终得到的那个图的过程就是它的聚类的过程------随机游走的思路
子图A的指示向量:
定理:令G是权值非负的无向图,正则拉普拉斯矩阵Lsym和Lrw的特征值0的重数k等于图 G的连通分量数。记G的连通分量为 A1,A2...Ak,则特征值0的特征向量由下列指示向量确定
性质:
1) L是对称半正定矩阵;
2) L的最小特征值是0
3) L有n个非负实特征值
4) (λ,u)是Lrw的特征值和特征向量,当且仅当是Lsym的特征值和特征向量;
5) (0,E)是Lrw的特征值和特征向量,是Lsym的特征值和特征向量;
########马尔可夫链
'''
#谱聚类算法:------可以作为一个参考,如果某个聚类效果比它好,说明该聚类方法还不错-----实践中首选随机游走拉普拉斯矩阵
'''
输入:n个点{Pi},簇的数目k
计算n*n的相似度矩阵W和度矩阵D;
计算拉普拉斯矩阵L=D - W Lsym=D^-1/2 L D-1/2 /// Lrw=D-1L=I - D-1W
计算L的前k个特征向量u1,u2,...,uk[特征值(降维)从小到大排的前k个]
将k个列向量组成矩阵U,U为n*k的实数阵
对于i=1,2,...,n ,令yi(k维列向量)为U的第 i 行的向量
###对于i=1,2,...,n ,将yi(k维列向量)依次单位化,使得|yi|=1###【对称拉普拉斯聚类 ,步骤】
使用k-means算法将点(yi)聚类成簇C1,C2,...,Ck
输出:簇A1,A2,...,Ak, 其中,Ai={j | yj∈Ci}#U的第j行属于第i个簇,那么原来的第j个点就属于第i个簇
#流式聚类
'''
RatioCut
聚类问题的本质:
对于定值k和图G,选择一组划分: A1,A2,...,Ak,最小化下面的式子:
修正目标函数
上述的目标函数存在问题:在很多情况下, minCut的解,将图分成了一个点和其余的n- 1个点。为了避免这个问题,目标函数应该显示的要求A1,A2,...,Ak足够大。
当k=2时的RatioCut
目标函数:
定义向量,
RatioCut与拉普拉斯矩阵的关系
f的约束条件
目标函数约束条件的放松relaxation
若划分为k个子集
考察指示向量组成的矩阵
目标函数
Rayleigh-Ritz理论
下面只是每一步的代码实现,但是我并没有得到理想的结果,并且在用np.linalg.eig()求拉普拉斯矩阵特征值和特征向量时,出现了无限接近于0但小于0的特征值,以及复数,所以还不能不能直接运行,我也找了很多办法,但可能当局者迷,我就先搁置这里了。。。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from pandas import DataFrame, Series
from keras import models, layers, optimizers, losses, metrics
from keras.utils.np_utils import to_categorical
plt.rcParams['font.sans-serif'] = ['SimHei'] #指定默认字体
plt.rcParams['axes.unicode_minus'] = False #解决保存图像是负号'-'显示为方块的问题
from sklearn.cluster import KMeans
import matplotlib.colors as colors
import matplotlib.cm as cmx
class Spectral_Cluster(object):
def __init__(self,data,k):
self.data=data
self.k=k#k近邻的k值
self.w=np.zeros((data.shape[0],data.shape[0]))#保存knn图相似度矩阵w
def similar_matric(self,is_sqrt=True):#得到欧氏距离矩阵
n = self.data.shape[0]
w = np.zeros((n, n))
for i in range(n):
for j in range(i+1,n):
if is_sqrt:
distance=np.sqrt(np.sum(np.square(self.data[i]-self.data[j])))
else:
distance=1.0*np.sum(np.square(self.data[i]-self.data[j]))
w[i,j]=distance
w[j,i]=distance
return w
#knn相似度矩阵
def get_knn_sm(self,sigma=1):#sigma,高斯核函数,带宽
w=self.similar_matric()
# print(w[0])
order_w=np.argsort(w,axis=1)#得到升序后的列索引
idx=order_w[:,1:self.k+1]#取除自身的k个
# print(idx.shape)#n*k+1包含自身
w_sm=np.exp(-self.similar_matric(is_sqrt=False)/(2*sigma**2))#高斯核函数,相似度函数
for i in range(idx.shape[0]):
for j in idx[i]:
# self.w[i,j]=w[i,j]
self.w[i,j]=w_sm[i,j]#将对应列放入初始化定义的self.w中
# self.w[i,i]=0
# print(self.w[0])
return
def get_diag_degree_matric(self,w):#得到D顶点度矩阵(每行元素和)
sum_w=np.sum(w,axis=1)
return np.diag(sum_w)
def get_laplacian(self,sigma):#拉普拉斯矩阵
self.get_knn_sm(sigma)
d = self.get_diag_degree_matric(self.w)
la=np.dot(np.linalg.inv(d),d-self.w)
# la=d-self.w
return np.float64(la)
def calculate_eigenvectors(self,laplacian):#计算特征值,特征向量
return np.linalg.eig(laplacian)#返回eigen_val,eigen_vec
def spectral_cluster(self,laplacian,c):#k-means聚类
eigen_val, eigen_vec=self.calculate_eigenvectors(laplacian)
# eigen_vec=np.float64(eigen_vec)
print(np.sort(eigen_val))
fig=plt.figure()
ax1=fig.add_subplot(1,1,1)
ax1.plot(np.sort(eigen_val)[:10])
plt.show()
# eigen_val_idx=np.argsort(eigen_val)
# y=eigen_vec[:,eigen_val_idx[:c]]
sp_kmeans=KMeans(c).fit(eigen_vec)
results=sp_kmeans.labels_
# print(y)
# np.random.shuffle(y)
# clusters=y[:c]
# # print(clusters)
# km=KMEANS(c,clusters,y)
# results=km.start()
# print(results)
return results
def color_list(self, color_nums):
np.random.seed(101)
curves = [np.random.random(20) for i in range(color_nums)]
values = range(color_nums)
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
print(scalarMap.get_clim())
colorVals = [scalarMap.to_rgba(values[i]) for i in range(len(curves))]
x = np.array(colorVals)
color_rgb = x[:, :3]
# print(color_rgb)
return color_rgb
def plot(self, data,c):
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1)
ax1.scatter(self.data[:, 0], self.data[:, 1])
ax2 = fig.add_subplot(2, 1, 2)
colors = self.color_list(c)
for i in range(c):
t = np.array(data.get(i))
for j in t:
ax2.scatter(self.data[j,0],self.data[j,1],color=colors[i])
plt.show()
def start(self,c,sigma):
la=self.get_laplacian(sigma)
results=self.spectral_cluster(la,c)
# print(results)
self.plot(results,c)
from sklearn import datasets
def genTwoCircles(n_samples=200):
X,y = datasets.make_circles(n_samples, factor=0.5, noise=0.05)
return X, y
x,y=genTwoCircles()
n=2
data=x
sc=Spectral_Cluster(data=data,k=10)
sc.start(c=2,sigma=1)#导致谱聚类效果不太好的原因可能包含三个方面:即k:k近邻参数大小;c:划分的类别数目;sigma:高斯核函数带宽大小
#