聚类算法是一种无监督学习的算法,用于将数据集中的数据分成不同的聚类或组。聚类算法是数据挖掘和机器学习领域中常见的技术之一,具有广泛的应用。 以下是聚类算法的一些知识点:
- 聚类算法的目的是将数据集划分为不同的组,使得组内的数据点相似度高,组间的相似度低。
- 聚类算法可以分为层次聚类和非层次聚类两种。层次聚类可以分为聚合聚类和分裂聚类两种。
- 常用的聚类算法包括K均值聚类、层次聚类、DBSCAN聚类等。其中,K均值聚类是最常见的聚类算法之一,它将数据集分为K个簇,每个簇的中心点被称为质心。
- 聚类算法的评价指标包括轮廓系数、Calinski-Harabasz指数、Davies-Bouldin指数等。
- 聚类算法的应用包括客户分群、文本聚类、图像分割等。
- 聚类算法的优化方法包括选择合适的聚类算法、确定合适的聚类簇数、选择合适的相似度度量等。
- 聚类算法的局限性包括需要事先确定聚类簇数、对初始质心的选择敏感、对异常值敏感等。
基于划分的聚类算法
K-Means 聚类算法
K-Means 聚类算法是一种非层次聚类算法,它将数据集分为K个簇,每个簇的中心点被称为质心。K-Means 算法的基本思想是通过不断迭代,将数据点划分到最近的质心所在的簇中,然后重新计算每个簇的质心,直到簇中心不再发生变化或达到最大迭代次数为止。
步骤:
- 随机的选取K个中心点,代表K个类别;
- 计算N个样本点和K个中心点之间的欧氏距离;
- 将每个样本点划分到最近的(欧氏距离最小的)中心点类别中——迭代1;
- 计算每个类别中样本点的均值,得到K个均值,将K个均值作为新的中心点——迭代2;
- 重复步骤2、3、4;
- 满足收敛条件后,得到收敛后的K个中心点(中心点不再变化)。
K-Means 聚类可以用欧式距离,欧式距离很简单,二维平面就是两个点的距离公式,在多维空间里,假设两个样本为 𝑎(𝑥1,𝑥2,𝑥3,𝑥4...𝑥𝑛) , 𝑏(𝑦1,𝑦2,𝑦3,𝑦4...𝑦𝑛) ,求两个样本的欧式距离。
欧式距离是两个样本之间的距离度量,它是最常用的距离度量方式之一。欧式距离指的是两个样本在 n 维空间中的坐标差的平方和的开方,即:
𝑑(𝑥,𝑦)=∑𝑖=1𝑛(𝑥𝑖−𝑦𝑖)2
其中, 和𝑥和𝑦 分别表示两个样本在 n 维空间中的坐标, 和𝑥𝑖和𝑦𝑖 分别表示两个样本在第 i 个维度上的坐标。
python代码实现:
#生成随机点
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets.samples_generator import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4,
cluster_std=0.60, random_state=0)
plt.scatter(X[:, 0], X[:, 1], s=50)
plt.show()
#K-Means 聚类算法
from sklearn.cluster import KMeans
"""
KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300,
tol=0.0001, precompute_distances='auto', verbose=0,
random_state=None, copy_x=True, n_jobs=1, algorithm='auto')
Parameters:
n_clusters: 聚类个数
max_iter: 最大迭代数
n_init: 用不同的质心初始化值运行算法的次数
init: 初始化质心的方法
precompute_distances:预计算距离
tol: 关于收敛的参数
n_jobs: 计算的进程数
random_state: 随机种子
copy_x:是否修改原始数据
algorithm:“auto”, “full” or “elkan”
”full”就是我们传统的K-Means算法,
“elkan”elkan K-Means算法。默认的
”auto”则会根据数据值是否是稀疏的,来决定如何选择”full”和“elkan”,稠密的选 “elkan”,否则就是”full”
Attributes:
cluster_centers_:质心坐标
Labels_: 每个点的分类
inertia_:每个点到其簇的质心的距离之和。
"""
m_kmeans = KMeans(n_clusters=4)
from sklearn import metrics
def draw(m_kmeans,X,y_pred,n_clusters):
centers = m_kmeans.cluster_centers_
print(centers)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, s=50, cmap='viridis')
#中心点(质心)用红色标出
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.5)
print("Calinski-Harabasz score:%lf"%metrics.calinski_harabasz_score(X, y_pred) )
plt.title("K-Means (clusters = %d)"%n_clusters,fontsize=20)
plt.show()
m_kmeans.fit(X)
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
n_clusters=4, n_init=10, n_jobs=None, precompute_distances='auto',
random_state=None, tol=0.0001, verbose=0)
y_pred = m_kmeans.predict(X)
draw(m_kmeans,X,y_pred,4)
K-Means 聚类算法升级
- K-Means++ 算法:K-Means++ 算法是 K-Means 算法的改进版,它通过改进初始质心的选择方式,提高了算法的聚类效果。K-Means++ 算法的初始质心选择方式是在数据集中随机选择一个点作为第一个质心,然后选择与前面已选质心距离最大的点作为下一个质心,直到选出 K 个质心。与 K-Means 算法相比,K-Means++ 算法的聚类效果更好,收敛速度更快。
- Mini-Batch K-Means 算法:Mini-Batch K-Means 算法是 K-Means 算法的一种变体,它采用了一种随机梯度下降的方式更新质心,从而加速了算法的收敛速度。Mini-Batch K-Means 算法将数据集划分为多个小批量,每个小批量包含一部分数据,然后在每个小批量上执行 K-Means 算法,更新质心。与 K-Means 算法相比,Mini-Batch K-Means 算法的计算速度更快,但聚类效果可能略有下降。
- K-Means++-C 算法:K-Means++-C 算法是一种基于 K-Means++ 算法的并行聚类算法,它可以加速大规模数据集的聚类过程。K-Means++-C 算法将数据集划分为多个子集,然后在每个子集上执行 K-Means++ 算法,得到每个子集的聚类结果。最后,将所有子集的聚类结果合并,得到最终的聚类结果。与 K-Means++ 算法相比,K-Means++-C 算法的计算速度更快,适用于大规模数据集的聚类。 这些升级版的 K-Means 算法可以根据不同的需求选择使用,以获得更好的聚类效果和更快的计算速度。
K-Means++ 算法对比K-Means 聚类算法示例
#导入必要的库
import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
#生成数据集
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
#定义 K-Means++ 聚类算法函数
def k_means_pp(X, K):
centroids = []
# 随机选择一个初始质心
i = np.random.randint(0, len(X))
centroids.append(X[i])
# 选择剩余的质心
for k in range(1, K):
# 计算每个样本离最近质心的距离的平方和
D2 = np.array([min([np.linalg.norm(x-c)**2 for c in centroids]) for x in X])
# 按照概率分布选择下一个质心
probs = D2 / D2.sum()
cumprobs = probs.cumsum()
r = np.random.rand()
j = np.where(cumprobs >= r)[0][0]
centroids.append(X[j])
return centroids
#定义 K-Means 聚类算法函数
def k_means(X, K, centroids):
# 初始化聚类结果、距离矩阵和聚类中心
clusters = np.zeros(len(X))
D = np.zeros((len(X), K))
for k in range(K):
D[:, k] = np.linalg.norm(X - centroids[k], axis=1)
# 迭代更新聚类结果、距离矩阵和聚类中心
while True:
# 更新聚类结果
new_clusters = np.argmin(D, axis=1)
if np.array_equal(new_clusters, clusters):
break
clusters = new_clusters
# 更新聚类中心
centroids = [X[clusters == k].mean(axis=0) for k in range(K)]
# 更新距离矩阵
for k in range(K):
D[:, k] = np.linalg.norm(X - centroids[k], axis=1)
return clusters, centroids
#调用函数进行聚类
K = 4
centroids = k_means_pp(X, K)
clusters, centroids = k_means(X, K, centroids)
#可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=clusters)
plt.scatter(np.array(centroids)[:, 0], np.array(centroids)[:, 1], marker='*', s=200, c='k')
plt.show()
基于密度的聚类算法
DBSCAN聚类算法
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)聚类算法是一种基于密度的聚类算法,它可以自动识别任意形状的聚类簇,并能够有效地处理包含噪声的数据。DBSCAN 算法的基本思想是通过寻找数据点周围的相邻点,以及这些相邻点周围的相邻点,来判断数据点是否属于同一个簇中。DBSCAN 算法的核心有两个参数:半径 𝜖 和最小的样本个数 𝑀𝑖𝑛𝑃𝑡𝑠 。其中,半径 𝜖 定义了数据点之间的邻域范围,即距离某个数据点不超过 𝜖 的数据点都被认为是它的邻居;最小的样本个数 𝑀𝑖𝑛𝑃𝑡𝑠 定义了一个簇的最小密度,即在一个数据点的邻域范围内,如果包含的数据点个数不少于 𝑀𝑖𝑛𝑃𝑡𝑠,则认为该点是核心点,可以构成一个簇。DBSCAN 算法的具体实现步骤如下:
- 随机选择一个未访问过的数据点 p。
- 计算数据点 p 的邻域范围内所有数据点的距离,如果距离不超过半径 𝜖 ,则认为这些点是相互可达的,将它们加入同一个簇中。
- 对于簇中的每个数据点,递归地执行步骤 2,直到无法继续扩展该簇为止。
- 重复步骤 1 到步骤 3,直到所有数据点都被访问过为止。
示例:
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
# 生成随机数据
X, y = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 使用DBSCAN算法进行聚类
dbscan = DBSCAN(eps=0.5, min_samples=5)
y_pred = dbscan.fit_predict(X)
# 绘制聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title('DBSCAN Clustering')
plt.show()
Mean Shift聚类算法
Mean Shift 算法是一种基于密度的非参数聚类算法。它通过寻找密度函数的局部最大值来确定聚类簇的中心,进而将数据点分配到相应的聚类簇中。具体来说,Mean Shift 算法从任意一个数据点开始,通过迭代的方式不断移动该点,直到达到局部最大值为止。在移动过程中,Mean Shift 算法会不断地将数据点向密度函数值最大的方向移动,直到无法再移动为止,这样就能找到该点所在的聚类簇中心。然后,对于每个中心,可以找到与之相似的数据点并将它们分配到该簇中。最终,所有数据点都被分配到相应的聚类簇中。
import numpy as np
def euclidean_distance(x1, x2):
return np.sqrt(np.sum((x1 - x2)**2))
#Mean Shift聚类算法
class MeanShift:
def __init__(self, radius=4):
self.radius = radius
def fit(self, X):
centroids = []
for i in range(len(X)):
point = X[i]
while True:
# Find all points within the given radius
neighbors = []
for j in range(len(X)):
if euclidean_distance(point, X[j]) <= self.radius:
neighbors.append(X[j])
# Calculate the mean of all points within the radius
new_point = np.mean(neighbors, axis=0)
# If the new point is within a certain distance of the last point, stop
if euclidean_distance(point, new_point) < 0.00001:
break
point = new_point
centroids.append(point)
self.centroids = np.unique(centroids, axis=0)
def predict(self, X):
labels = []
for i in range(len(X)):
distances = [euclidean_distance(X[i], c) for c in self.centroids]
label = np.argmin(distances)
labels.append(label)
return labels
测试:
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
X, y = make_blobs(n_samples=200, centers=3, cluster_std=0.5, random_state=0)
model = MeanShift()
model.fit(X)
labels = model.predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels)
plt.show()
层次聚类算法
凝聚层次聚类(Aglomerative Hierarchical Clustering,简称 AGNES)
从一个个单独的数据点开始,不断合并最近的两个聚类簇,直到所有数据点都被合并成一个聚类簇为止。凝聚层次聚类的核心是距离计算和聚类合并规则的选择。常用的距离计算方法有欧几里得距离、曼哈顿距离、余弦距离等。常用的聚类合并规则有最小距离法、最大距离法、重心法等。
分裂层次聚类(Divisive Hierarchical Clustering,简称 DIANA)
从所有数据点的整体开始,不断将数据点划分成两个或多个子集,直到每个子集都成为一个聚类簇为止。分裂层次聚类的核心是划分方法的选择,常用的划分方法有 K-Means、PAM 等。 层次聚类算法的优点在于可以自动确定聚类簇的数量和层次结构,但其缺点在于算法的时间复杂度较高,在大数据集上的计算时间可能非常长,并且容易受到噪声数据和异常值的影响。
基于图的聚类算法
谱聚类算法(Spectral Clustering)
将数据点看作图上的节点,通过计算节点之间的相似度矩阵和拉普拉斯矩阵来确定节点之间的相似性和距离,然后通过对拉普拉斯矩阵进行特征分解来得到聚类簇的划分。
import numpy as np
import scipy.spatial.distance as dist
class SpectralClustering:
def __init__(self, n_clusters=2, affinity='rbf', gamma=1.0):
self.n_clusters = n_clusters
self.affinity = affinity
self.gamma = gamma
def fit_predict(self, X):
# 计算相似度矩阵
if self.affinity == 'rbf':
S = self._rbf_kernel(X, gamma=self.gamma)
else:
S = self._knn_kernel(X, k=self.gamma)
# 计算拉普拉斯矩阵
L = self._laplacian_matrix(S)
# 计算特征值和特征向量
eigvals, eigvecs = np.linalg.eig(L)
# 取出前k个特征向量
idx = eigvals.argsort()[:self.n_clusters]
U = eigvecs[:, idx]
# 对U进行归一化处理
norm = np.linalg.norm(U, axis=1, keepdims=True)
U_norm = U / norm
# 对U_norm进行k-means聚类
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=self.n_clusters)
return kmeans.fit_predict(U_norm)
def _rbf_kernel(self, X, gamma):
dists = dist.squareform(dist.pdist(X, 'euclidean'))
return np.exp(-gamma * dists ** 2)
def _knn_kernel(self, X, k):
dists = dist.squareform(dist.pdist(X, 'euclidean'))
W = np.zeros_like(dists)
for i in range(X.shape[0]):
idx = np.argsort(dists[i])[:k+1]
W[i, idx] = 1
return W
def _laplacian_matrix(self, S):
# 计算度矩阵
D = np.diag(np.sum(S, axis=1))
# 计算拉普拉斯矩阵
L = D - S
return L
社区发现算法(Community Detection)
将数据点看作社交网络上的节点,通过计算节点之间的社交关系和相似度来确定节点之间的相似性,然后利用社区发现算法将相似度高的节点划分到同一个社区中。
import networkx as nx
import community
# 构建图
G = nx.karate_club_graph()
# 使用Louvain算法进行社区发现
partition = community.modularity_max.greedy_modularity_communities(G)
# 输出每个节点属于哪个社区
for i, com in enumerate(partition):
print("Community %d: %s" % (i, com))
聚类算法使用领域
类算法是一种常用的无监督学习算法,可以将相似的数据点分组成簇,通常用于以下领域:
- 数据挖掘:聚类算法可以用于数据挖掘中的分析和分类,例如用户行为分析、产品定位、市场细分等。
- 图像处理:聚类算法可以用于图像分割、目标检测、图像压缩等应用,通过将图像像素聚类成不同的簇,实现对图像的分割和压缩。
- 自然语言处理:聚类算法可以用于文本聚类和主题模型,例如新闻分类、情感分析、文本推荐等。
- 生物信息学:聚类算法可以用于基因表达数据的聚类和分类,例如基因功能预测、新药研发等。
- 物联网:聚类算法可以用于传感器网络中的数据聚合和分类,例如智能交通、智能医疗等。 聚类算法在各个领域都有广泛的应用,可以帮助解决大规模数据的分类和分析问题,提高数据处理的效率和准确率。
总结
聚类算法是一种无监督学习算法,可以将相似的数据点分组成簇,是数据挖掘和机器学习领域中的重要技术之一。常用的聚类算法包括上文的K-Means、层次聚类、DBSCAN等。聚类算法的优点在于可以自动发现数据的内在结构和规律,可以用于数据挖掘、图像处理、自然语言处理、生物信息学、物联网等领域。在笔者看来,聚类算法的缺点在于需要大量计算资源和时间,容易受到噪声数据和异常值的影响,聚类结果也需要经过人工分析和解释,需要专业性,熟练性人才进入市场才能发挥这款无监督学习算法的强大作用。
原文链接:机器学习实战教程(一):聚类算法 - 知乎