机器学习基础 第四章 聚类算法

聚类算法是无监督学习算法,对于没有打上标签的数据,可以采用聚类算法。下面介绍两种常用的算法KMeans和谱聚类。

1 Kmeans

假设有数据集合 {xi} 1iN xiRn ,如果想把该数据集合分成k个类,应该如何划分?这就是聚类问题。例如有如下二维数据(以二维为例方便展示)


这里写图片描述
图1.1 三类数据

对于图1.1所示的数据可以使用KMeans方法对其进行聚类,KMeans算法是最简单高效稳健的算法,而且很容易并行化,但是其有个问题就是无法处理非凸集问题,处理非凸集问题的算法,将在下一节中介绍谱聚类将解决非凸集问题。

KMeans算法的流程如下:

(1)适当选择 k 个类的初始中心,可以随机初始化;
(2)在第k次迭代中,对任意一个样本,求其到 k 个中心的距离,将该样本归到距离最短的中心所在的类;
(3)利用均值等方法更新该类的中心值;
(4)对于所有的k聚类中心,如果利用(2)(3)的迭代法更新后,值保持不变,则迭代结束,否则继续迭代。

对于以上的流程实现的代码如下

def kmeans(data, k, tol = 1e-6):
    data = np.array(data)
    import random 
    index = np.arange(0, len(data))
    random.shuffle(index)
    index = index[0: k]
    #(1)随机初始化初始的聚类中心
    init_center = data[index, :]
    labels = np.zeros((data.shape[0],),dtype=np.int)
    iter_ = 0
    while iter_ < 100 :
        err = 0.0
        #(2)在k次迭代中将样本分配到最近的聚类中心中
        for i in xrange(data.shape[0]):
            di = data[i, :]
            max_dist = 1e100
            tmp = []
            for center in init_center:
                dis = pdist([di, center])
                tmp.append(dis[0])
            labels[i] = np.argmin(tmp)
        #(3)计算新类的聚类中心
        new_center = []
        for label in set(labels):
            label_data = data[labels == label, :]
            new_center.append(np.sum(label_data, axis=0) / len(label_data))
        #(4)计算新的聚类中心和旧的聚类中心的差异
        for i in range(0, k):
            err = err + norm(new_center[i] - init_center[i])
        init_center = new_center
        iter_ = iter_ + 1
        #画出每次迭代后的类别
        observer(iter_, data, labels, new_center)
        #如果新的聚类中和旧的聚类中心的误差小于阈值停止迭代
        if err < tol:
            break
    return labels

图1.2是图1.1经过十次迭代后的结果


这里写图片描述
这里写图片描述!
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
图1.2 KMeans十次迭代的过程图

2 谱聚类


这里写图片描述
图2.1 谱聚类的原始数据

对于图2.1所示的数据KMeans就无能为力了,用KMeans对图2.1聚类的结果如下


这里写图片描述
图2.2 KMeans对图2.1的聚类结果

下面看下谱聚类对图2.1的聚类结果


这里写图片描述
图2.2 谱聚类对图2.1的聚类结果

谱聚类的计算流程如下:

假设存在数据点集

S={s1,,sn}Rl
,将其聚成C类

(0)对S进行中性化

(1)构造相似矩阵 AR{n×n} Ai,j=exp(d2(si,sj)σ2) ij Ai,i=0 d2(si,sj) 为距离函数,通常为 si sj 的欧拉距离, σ 为一重要的标量参数,下面会有详细介绍。

(2)构造对角矩阵 D Di,i=j=1nAi,j,构造正规化的相似矩阵 L=D12AD12

(3)选择一个期望聚类的数目C

(4)找出L中最大的C个最大的特征值向量 x1,,xc ,构成矩阵 X=[x1,,xc]Rn×c

(5)将矩阵 X 的行向量单位化,得到矩阵YRn×c Yij=Xij(X2ij)12

(6)将 Y 的每行看作属于Rc的点,并通过k-means进行聚类。

(7)对Y进行聚类,聚类的结果就代表了原始数据点 si 的聚类结果。

谱聚类之所以能处理非凸集数据问题就是因为其对数据首先进行了变换,变换流程如流程中的(1)-(4),下面看下图2.1所示的数据经过(1)-(4)变换后的结果图


这里写图片描述
图2.3 经过(1)(4)变换后的数据

程序解析

第一步:加载数据

def readData(path):
    data = []
    for line in open(path, 'r'):
        ele = line.split('\t')
        tmp = []
        for e in ele:
            tmp.append(float(e))
        data.append(tmp)
    return data

第二步:对数据进行中性化,对应与流程中的(0)

def normalize(data):
    mean = np.mean(data, axis = 0)
    data = (data - mean)
    max_ = np.max(np.abs(data))
    data = data / max_
    return data

第三步:计算相似矩阵,相当于(1)

def affinity(data, knn):
    data = np.array(data)
    d = cdist(data,data,'sqeuclidean')
    sigma_list = np.zeros(data.shape[0])
    dis_matrix = np.zeros((data.shape[0], data.shape[0]))
    i = 0
    for e in d:
        ec = copy.deepcopy(e)
        ec.sort()
        index = ec > 0.0
        tmp = ec[index]
        sigma_list[i] = tmp[knn]
        i = i + 1
    dis_matrix = updataAffinity(d, sigma_list)
    return dis_matrix    

第四步:计算拉普拉斯矩阵,相当于(2)

def lMatrix(dis_matrix):
    d = dMatrix(dis_matrix)
    if (len(d.shape) == 1):
        d = np.array([d])
    if(d.shape[0] == 1):
        d_row = copy.deepcopy(d.transpose())
        d_col = copy.deepcopy(d)
    else:
        d_row = copy.deepcopy(d)
        d_col = copy.deepcopy(d.transpose())

    tmp = d_col * dis_matrix
    l = tmp * d_row
    return l

第五步:计算拉普拉斯矩阵的奇异值,相当于(3)(4)

def svd(l):
    u,s,v = svds(l,2)
    return u

第六步:对奇异值分解的结果进行单位化,相当于(5)

def unit(data):
    norm2 = np.array([[norm(di) for di in data]]).transpose()
    u = data / norm2
    return u

第七步:调用第一节中的KMeans算法对结果进行聚类,相当于(6)

KMeans算法见上一节
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值