第14章聚类方法

本文是李航老师的《统计学习方法》一书的代码复现。作者:黄海广

备注:代码都可以在github中下载。我将陆续将代码发布在公众号“机器学习初学者”,可以在这个专辑在线阅读。

1.聚类是针对给定的样本,依据它们属性的相似度或距离,将其归并到若干个“类”或“簇”的数据分析问题。一个类是样本的一个子集。直观上,相似的样本聚集在同类,不相似的样本分散在不同类。

2.距离或相似度度量在聚类中起着重要作用。

常用的距离度量有闵可夫斯基距离,包括欧氏距离曼哈顿距离、切比雪夫距离、、以及马哈拉诺比斯距离。常用的相似度度量有相关系数、夹角余弦。用距离度量相似度时,距离越小表示样本越相似;用相关系数时,相关系数越大表示样本越相似。

3.类是样本的子集,比如有如下基本定义:用表示类或簇,用,;等表示类中的样本,用表示样本与样本之间的距离。如果对任意的,有

则称为一个类或簇。

描述类的特征的指标有中心、直径、散布矩阵、协方差矩阵。

4.聚类过程中用到类与类之间的距离也称为连接类与类之间的距离包括最短距离、最长距离、中心距离、平均距离。

5.层次聚类假设类别之间存在层次结构,将样本聚到层次化的类中层次聚类又有聚合或自下而上、分裂或自上而下两种方法。

聚合聚类开始将每个样本各自分到一个类;之后将相距最近的两类合并,建立一个新的类,重复此操作直到满足停止条件;得到层次化的类别。分裂聚类开始将所有样本分到一个类;之后将已有类中相距最远的样本分到两个新的类,重复此操作直到满足停止条件;得到层次化的类别。

聚合聚类需要预先确定下面三个要素:

(1)距离或相似度;(2)合并规则;(3)停止条件。

根据这些概念的不同组合,就可以得到不同的聚类方法。

6.均值聚类是常用的聚类算法,有以下特点。基于划分的聚类方法;类别数k事先指定;以欧氏距离平方表示样本之间的距离或相似度,以中心或样本的均值表示类别;以样本和其所属类的中心之间的距离的总和为优化的目标函数;得到的类别是平坦的、非层次化的;算法是迭代算法,不能保证得到全局最优。

均值聚类算法,首先选择k个类的中心,将样本分到与中心最近的类中,得到一个聚类结果;然后计算每个类的样本的均值,作为类的新的中心;重复以上步骤,直到收敛为止。

层次聚类

  1. 聚合(自下而上):聚合法开始将每个样本各自分裂到一个类,之后将相距最近的两类合并,建立一个新的类,重复次操作知道满足停止条件,得到层次化的类别。

  2. 分裂(自上而下):分裂法开始将所有样本分到一个类,之后将已有类中相距最远的样本分到两个新的类,重复此操作直到满足停止条件,得到层次化的类别。

k均值聚类

k均值聚类是基于中心的聚类方法,通过迭代,将样本分到k个类中,使得每个样本与其所属类的中心或均值最近,得到k个平坦的,非层次化的类别,构成对空间的划分。

import math
import random
import numpy as np
from sklearn import datasets,cluster
import matplotlib.pyplot as plt
iris = datasets.load_iris()
gt = iris['target'];gt
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

3类

iris['data'][:,:2].shape
(150, 2)
data = iris['data'][:,:2]
x = data[:,0]
y = data[:,1]
plt.scatter(x, y, color='green')
plt.xlim(4, 8)
plt.ylim(1, 5)
plt.show()

# 定义聚类数的节点class ClusterNode:def __init__(self, vec, left=None, right=None, distance=-1, id=None, count=1):""":param vec: 保存两个数据聚类后形成新的中心:param left: 左节点:param right:  右节点:param distance: 两个节点的距离:param id: 用来标记哪些节点是计算过的:param count: 这个节点的叶子节点个数"""self.vec = vecself.left = leftself.right = rightself.distance = distanceself.id = idself.count = count
def euler_distance(point1: np.ndarray, point2: list) -> float:"""计算两点之间的欧拉距离,支持多维"""distance = 0.0for a, b in zip(point1, point2):distance += math.pow(a - b, 2)return math.sqrt(distance)
# 层次聚类(聚合法)class Hierarchical:def __init__(self, k):self.k = kself.labels = Nonedef fit(self, x):nodes = [ClusterNode(vec=v, id=i) for i, v in enumerate(x)]distances = {}point_num, feature_num = x.shapeself.labels = [-1] * point_numcurrentclustid = -1while(len(nodes)) > self.k:min_dist = math.infnodes_len = len(nodes)closest_part = Nonefor i in range(nodes_len - 1):for j in range(i+1, nodes_len):d_key = (nodes[i].id, nodes[j].id)if d_key not in distances:distances[d_key] = euler_distance(nodes[i].vec, nodes[j].vec)d = distances[d_key]if d < min_dist:min_dist = dclosest_part = (i, j)part1, part2 = closest_partnode1, node2 = nodes[part1], nodes[part2]new_vec = [ (node1.vec[i] * node1.count + node2.vec[i] * node2.count ) / (node1.count + node2.count)for i in range(feature_num)]new_node = ClusterNode(vec=new_vec,left=node1,right=node2,distance=min_dist,id=currentclustid,count=node1.count + node2.count)currentclustid -= 1del nodes[part2], nodes[part1]nodes.append(new_node)self.nodes = nodesself.calc_label()def calc_label(self):"""调取聚类的结果"""for i, node in enumerate(self.nodes):# 将节点的所有叶子节点都分类self.leaf_traversal(node, i)def leaf_traversal(self, node: ClusterNode, label):"""递归遍历叶子节点"""if node.left == None and node.right == None:self.labels[node.id] = labelif node.left:self.leaf_traversal(node.left, label)if node.right:self.leaf_traversal(node.right, label)# https://zhuanlan.zhihu.com/p/32438294
my = Hierarchical(3)
my.fit(data)
labels = np.array(my.labels)
print(labels)
[2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 2 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 2 0 0 0 1 0 0 1 2 1 0 1 00 0 0 0 0 0 1 1 0 0 0 1 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 00 0]
# visualize resultcat1 = data[np.where(labels==0)]
cat2 = data[np.where(labels==1)]
cat3 = data[np.where(labels==2)]plt.scatter(cat1[:,0], cat1[:,1], color='green')
plt.scatter(cat2[:,0], cat2[:,1], color='red')
plt.scatter(cat3[:,0], cat3[:,1], color='blue')
plt.title('Hierarchical clustering with k=3')
plt.xlim(4, 8)
plt.ylim(1, 5)
plt.show()

sk = cluster.AgglomerativeClustering(3)
sk.fit(data)
labels_ = sk.labels_
print(labels_)
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 2 0 2 0 1 0 1 1 0 2 0 2 0 2 2 2 2 0 0 2 00 0 0 0 0 2 2 2 2 0 2 0 0 2 2 2 2 0 2 1 2 2 2 0 1 2 0 2 0 0 0 0 1 0 0 0 00 0 2 2 0 0 0 0 2 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 2 00 0]
# visualize result of sklearncat1_ = data[np.where(labels_==0)]
cat2_ = data[np.where(labels_==1)]
cat3_ = data[np.where(labels_==2)]plt.scatter(cat1_[:,0], cat1_[:,1], color='green')
plt.scatter(cat2_[:,0], cat2_[:,1], color='red')
plt.scatter(cat3_[:,0], cat3_[:,1], color='blue')
plt.title('Hierarchical clustering with k=3')
plt.xlim(4, 8)
plt.ylim(1, 5)
plt.show()

# kmeansclass MyKmeans:def __init__(self, k, n=20):self.k = kself.n = ndef fit(self, x, centers=None):# 第一步,随机选择 K 个点, 或者指定if centers is None:idx = np.random.randint(low=0, high=len(x), size=self.k)centers = x[idx]#print(centers)inters = 0while inters < self.n:#print(inters)#print(centers)points_set = {key: [] for key in range(self.k)}# 第二步,遍历所有点 P,将 P 放入最近的聚类中心的集合中for p in x:nearest_index = np.argmin(np.sum((centers - p) ** 2, axis=1) ** 0.5)points_set[nearest_index].append(p)# 第三步,遍历每一个点集,计算新的聚类中心for i_k in range(self.k):centers[i_k] = sum(points_set[i_k])/len(points_set[i_k])inters += 1return points_set, centers
m = MyKmeans(3)
points_set, centers = m.fit(data)
centers
array([[5.006     , 3.428     ],[6.81276596, 3.07446809],[5.77358491, 2.69245283]])
# visualize resultcat1 = np.asarray(points_set[0])
cat2 = np.asarray(points_set[1])
cat3 = np.asarray(points_set[2])for ix, p in enumerate(centers):plt.scatter(p[0], p[1], color='C{}'.format(ix), marker='^', edgecolor='black', s=256)plt.scatter(cat1_[:,0], cat1_[:,1], color='green')
plt.scatter(cat2_[:,0], cat2_[:,1], color='red')
plt.scatter(cat3_[:,0], cat3_[:,1], color='blue')
plt.title('Hierarchical clustering with k=3')
plt.xlim(4, 8)
plt.ylim(1, 5)
plt.show()

# using sklearn
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, max_iter=100).fit(data)
gt_labels__ = kmeans.labels_
centers__ = kmeans.cluster_centers_
gt_labels__
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0,2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0,0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0,0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2])
centers__
array([[6.81276596, 3.07446809],[5.006     , 3.428     ],[5.77358491, 2.69245283]])
# visualize resultcat1 = data[gt_labels__ == 0]
cat2 = data[gt_labels__ == 1]
cat3 = data[gt_labels__ == 2]for ix, p in enumerate(centers__):plt.scatter(p[0], p[1], color='C{}'.format(ix), marker='^', edgecolor='black', s=256)plt.scatter(cat1_[:,0], cat1_[:,1], color='green')
plt.scatter(cat2_[:,0], cat2_[:,1], color='red')
plt.scatter(cat3_[:,0], cat3_[:,1], color='blue')
plt.title('kmeans using sklearn with k=3')
plt.xlim(4, 8)
plt.ylim(1, 5)
plt.show()

寻找 K 值

from sklearn.cluster import KMeansloss = []for i in range(1, 10):kmeans = KMeans(n_clusters=i, max_iter=100).fit(data)loss.append(kmeans.inertia_ / len(data) / 3)plt.title('K with loss')
plt.plot(range(1, 10), loss)
plt.show()

例 14.2
X = [[0, 2], [0, 0], [1, 0], [5, 0], [5, 2]]
np.asarray(X)
array([[0, 2],[0, 0],[1, 0],[5, 0],[5, 2]])
m = MyKmeans(2, 100)
points_set, centers = m.fit(np.asarray(X))
points_set
{0: [array([0, 2]), array([0, 0]), array([1, 0])],1: [array([5, 0]), array([5, 2])]}
centers
array([[0, 0],[5, 1]])
kmeans = KMeans(n_clusters=2, max_iter=100).fit(np.asarray(X))
kmeans.labels_
array([0, 0, 0, 1, 1])
kmeans.cluster_centers_
array([[0.33333333, 0.66666667],[5.        , 1.        ]])

本章代码来源:https://github.com/hktxt/Learn-Statistical-Learning-Method

下载地址

https://github.com/fengdu78/lihang-code

参考资料:

[1] 《统计学习方法》: https://baike.baidu.com/item/统计学习方法/10430179

[2] 黄海广: https://github.com/fengdu78

[3]  github: https://github.com/fengdu78/lihang-code

[4]  wzyonggege: https://github.com/wzyonggege/statistical-learning-method

[5]  WenDesi: https://github.com/WenDesi/lihang_book_algorithm

[6]  火烫火烫的: https://blog.csdn.net/tudaodiaozhale

[7]  hktxt: https://github.com/hktxt/Learn-Statistical-Learning-Method

复现经典:《统计学习方法》第14章 聚类方法相关推荐

  1. 李航《统计学习方法》第二章课后答案链接

    李航<统计学习方法>第二章课后答案链接 李航 统计学习方法 第二章 课后 习题 答案 http://blog.csdn.net/cracker180/article/details/787 ...

  2. 李航《统计学习方法》第一章课后答案链接

    李航<统计学习方法>第一章课后答案链接 李航 统计学习方法 第一章 课后 习题 答案 http://blog.csdn.net/familyshizhouna/article/detail ...

  3. 统计学习方法——第1章(个人笔记)

    统计学习方法--第1章 统计学习及监督学习概论 <统计学习方法>(第二版)李航,学习笔记 1.1 统计学习 1.特点 (1)以计算机及网络为平台,是建立在计算机及网络上的: (2)以数据为 ...

  4. 统计学习方法笔记第二章-感知机

    统计学习方法笔记第二章-感知机 2.1 感知机模型 2.2感知机学习策略 2.2.1数据集的线性可分型 2.2.2感知机学习策略 2.3感知机学习算法 2.3.1感知机算法的原始形式 2.3.2算法的 ...

  5. 第十四章聚类方法.14.2.3距离公式证明

    文章目录 主要内容 系统聚类法的性质 1. 单调性 2. 空间的浓缩和扩张 系统聚类法的比较 本课程来自深度之眼,部分截图来自课程视频以及李航老师的<统计学习方法>第二版. 公式输入请参考 ...

  6. 统计学习方法 | 第7章 支持向量机

    第7章 支持向量机 <统计学习方法>Python代码实现 [转载自Github开源项目]https://github.com/fengdu78/lihang-code 1.支持向量机最简单 ...

  7. 第十四章聚类方法.14.3K均值聚类

    文章目录 主要内容 k均值聚类的定义 样本空间划分 k均值聚类策略 算法步骤 例题 k均值聚类算法特性 收敛性 初始类的选择 类别数k的选择 k均值聚类缺点改进 本课程来自深度之眼,部分截图来自课程视 ...

  8. 一篇详解带你再次重现《统计学习方法》——第二章、感知机模型

    个性签名:整个建筑最重要的是地基,地基不稳,地动山摇. 而学技术更要扎稳基础,关注我,带你稳扎每一板块邻域的基础. 博客主页:七归的博客 专栏:<统计学习方法>第二版--个人笔记 创作不易 ...

  9. 统计学习方法 - 第1章 - 概论

    全书章节 第1章 统计学习方法概论 第2章 感知机 第3章 k近邻法 第4章 朴素贝叶斯法 第5章 决策树 第6章 逻辑斯谛回归与最大熵模型 第7章 支持向量机 第8章 提升方法 第9章 EM算法及其 ...

最新文章

  1. git用法小结(2)--git分支
  2. 关于Qt Designer程序/UI文件打开未响应的解决方法
  3. 10 种机器学习算法的要点
  4. 最小操作系统的代码解释、NASM的初步使用
  5. 延长笔记本电脑寿命的四个简单方法
  6. mysql语句随机数_程序生成随机数与SQL语句生成随机数
  7. windows 找不到本地配置文件用临时配置文件让您登录
  8. HTML DOM 树形结构
  9. 如何为新建网站选择好的域名
  10. 太原理工大学ACM队简介(2018版)
  11. C语言数字3转变字符 3 程序,C语言重点知识点
  12. win10子系统安装php,win10 ubuntu 子系统安装php
  13. 自媒体学习教程 新手怎么开始学习自媒体
  14. 【BZOJ1001】狼抓兔子
  15. Win10系统上搭建GIT本地服务器
  16. Golang#Typora-Golang笔记
  17. catkin_make报错: ROS Base path和Source space不一致问题,
  18. 2021年危险化学品经营单位主要负责人考试报名及危险化学品经营单位主要负责人证考试
  19. 点计算机图标就自动关机了,为什么点计算机的关机图标不能自动关机
  20. ANSYS Workbench 16 - 黄志新(图书阅读总结)

热门文章

  1. 第四篇: python函数续
  2. (解决)mysql1366中文显示错误的终极解决方案
  3. 浙江巨丰管业有限公司网站
  4. error C1189: #error : WINDOWS.H already included. MFC apps must not #include windows.h
  5. 人工智能技术的新突破:MIT科学家发明Church AI语言
  6. Windows 窗设计时结构
  7. 简单的多目标遗传算法实现
  8. Matlab | Matlab从入门到放弃(6)——数组
  9. 软件项目管理的75条建议
  10. Debug下正常,而Release失败的真正原因