k-means算法通过迭代将数据分配到最近的簇中心并更新中心,直至收敛;2. 优化策略包括使用n_init多次运行选择最优结果、k-means++初始化减少对初始值敏感、肘部法则和轮廓系数法确定k值;3. 局限性有对初始值和异常值敏感、需预设k值、假设簇为球形且密度均匀;4. 改进方法包括mini-batch k-means加速计算、k-medoids提升鲁棒性、x-means自动选k、降维预处理提升效果;5. 其他聚类算法如dbscan可发现任意形状簇并识别噪声、层次聚类无需预设k且可可视化树状图、gmm提供概率性聚类更灵活;6. 实际应用中应根据数据特征选择合适算法,通常从k-means入手,效果不佳时尝试dbscan或gmm,结合多种方法优化聚类结果。

Python实现数据聚类,K-means是常用且直观的算法。它通过迭代将数据点分配到最近的簇中心,并更新中心点位置,直至收敛。优化K-means通常涉及初始中心选择、评估指标和变种算法,以克服其对初始值敏感、易陷入局部最优等局限性。
K-means算法,说实话,第一次接触时觉得它简单得有点粗暴,但正是这种直观性,让它在很多场景下都非常实用。不过,粗暴不代表没有技巧,它的优化空间可不小。
在Python中,我们通常会用到
scikit-learn
立即学习“Python免费学习笔记(深入)”;
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# 生成一些示例数据
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# 初始化KMeans模型,设定簇的数量为4
# n_init='auto' (或一个整数) 告诉算法运行多少次不同的初始质心,并选择最好的结果,这本身就是一种优化
kmeans = KMeans(n_clusters=4, random_state=0, n_init='auto')
# 拟合数据
kmeans.fit(X)
# 获取聚类结果和簇中心
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=200, alpha=0.7, marker='X')
plt.title('K-means Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
print("簇中心点:\n", centroids)这里面,
n_init='auto'
n_init=10
init='k-means++'
K值,也就是聚类的簇数量,这玩意儿选不好,结果可能就差强人意。我个人感觉,这就像是给数据点找家,家分多了太散,分少了又挤,得有个合适的度。确定K值没有一个放之四海而皆准的“最佳”方法,但“肘部法则”和“轮廓系数法”是两种非常常用的经验性方法。
肘部法则 (Elbow Method)
它的核心思想是:随着K值的增加,每个簇内部的平方和(WCSS,Within-Cluster Sum of Squares,也就是
inertia_
wcss = []
# 尝试不同的K值
for i in range(1, 11): # 尝试从1到10个簇
kmeans = KMeans(n_clusters=i, random_state=0, n_init='auto')
kmeans.fit(X)
wcss.append(kmeans.inertia_) # inertia_ 就是WCSS
plt.plot(range(1, 11), wcss)
plt.title('Elbow Method')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('WCSS')
plt.show()看上面这张图,你会发现WCSS一开始下降很快,然后逐渐平缓。那个“拐点”就是我们希望找到的K值。不过,有时候这个“肘部”并不那么明显,这确实让人有点头疼。
轮廓系数法 (Silhouette Score)
轮廓系数则提供了一个更量化的评估指标,它衡量了每个样本点与其所属簇的相似度(内聚性)以及与其他簇的相异度(分离性)。轮廓系数的取值范围是-1到1:
我们通常会选择使平均轮廓系数最大的K值。
from sklearn.metrics import silhouette_score
silhouette_scores = []
# K值至少需要2个簇才能计算轮廓系数
for i in range(2, 11):
kmeans = KMeans(n_clusters=i, random_state=0, n_init='auto')
kmeans.fit(X)
score = silhouette_score(X, kmeans.labels_)
silhouette_scores.append(score)
plt.plot(range(2, 11), silhouette_scores)
plt.title('Silhouette Score Method')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('Silhouette Score')
plt.show()
# 找到最佳K值
best_k = np.argmax(silhouette_scores) + 2 # 因为我们从K=2开始
print(f"根据轮廓系数法,最佳K值可能是:{best_k}")我个人更偏爱轮廓系数,因为它提供了一个明确的数值,不像肘部法则那样需要“肉眼识别”。但两者结合使用,往往能得到更可靠的K值。
说句实在的,K-means虽然好用,但它也不是万能药。总有些时候,你会发现它的表现不尽如人意,甚至有些“脾气”。比如,你跑了几次,结果可能都不一样,这多半是初始中心点搞的鬼。
K-means的常见局限性:
k-means++
n_init
针对这些局限性,除了前面提到的n_init
k-means++
sklearn.cluster
sklearn
有时候,K-means确实满足不了需求,比如你的数据形状很奇特,或者你压根不知道该分几类。这时候,就得请出其他“高手”了。我个人对DBSCAN情有独钟,因为它能找出那些不规则的“甜甜圈”形状的簇,这可是K-means的盲区。
1. DBSCAN (Density-Based Spatial Clustering of Applications with Noise)
DBSCAN是一种基于密度的聚类算法。它不需要预设簇的数量,能够发现任意形状的簇,并且能有效识别噪声点(异常值)。它的核心思想是:如果一个数据点周围足够密集,它就属于一个簇。
eps
min_samples
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
# DBSCAN对特征缩放敏感,通常需要先进行标准化
X_scaled = StandardScaler().fit_transform(X)
# eps: 邻域半径, min_samples: 形成核心点所需的最小样本数
dbscan = DBSCAN(eps=0.3, min_samples=5)
clusters = dbscan.fit_predict(X_scaled)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, s=50, cmap='viridis')
plt.title('DBSCAN Clustering')
plt.xlabel('Scaled Feature 1')
plt.ylabel('Scaled Feature 2')
plt.show()
print("DBSCAN发现的簇标签:", np.unique(clusters)) # -1表示噪声点2. 层次聚类 (Hierarchical Clustering / Agglomerative Clustering)
层次聚类构建了一个簇的层次结构。它可以是凝聚的(Agglomerative,从单个点开始,逐步合并最近的簇)或分裂的(Divisive,从一个大簇开始,逐步分裂)。最常用的是凝聚层次聚类。它不需要预设K值,你可以通过“剪切”树状图(dendrogram)来选择簇的数量。
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
# 生成一些新的数据,以便更好地展示层次聚类
X_hier, _ = make_blobs(n_samples=50, centers=3, cluster_std=0.8, random_state=42)
# 凝聚层次聚类
# n_clusters=None 表示不预设簇的数量,可以后续通过linkage矩阵和dendrogram来确定
# linkage='ward' 是一种合并策略,尝试最小化合并后簇内方差的增加
agg_cluster = AgglomerativeClustering(n_clusters=3, linkage='ward')
agg_labels = agg_cluster.fit_predict(X_hier)
plt.scatter(X_hier[:, 0], X_hier[:, 1], c=agg_labels, s=50, cmap='viridis')
plt.title('Agglomerative Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
# 绘制树状图(需要scipy库)
linked = linkage(X_hier, method='ward')
plt.figure(figsize=(10, 7))
dendrogram(linked,
orientation='top',
distance_sort='descending',
show_leaf_counts=True)
plt.title('Dendrogram for Agglomerative Clustering')
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.show()3. 高斯混合模型 (Gaussian Mixture Models, GMM)
GMM是一种概率模型,它假设数据点是由若干个高斯分布(正态分布)混合生成的。每个簇对应一个高斯分布。GMM不仅能给出每个点属于哪个簇,还能给出属于每个簇的概率,这比K-means的硬性划分要更灵活。
from sklearn.mixture import GaussianMixture
# n_components 对应于簇的数量
gmm = GaussianMixture(n_components=4, random_state=0)
gmm.fit(X)
gmm_labels = gmm.predict(X)
plt.scatter(X[:, 0], X[:, 1], c=gmm_labels, s=50, cmap='viridis')
plt.title('Gaussian Mixture Model Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
# 还可以获取每个样本属于每个簇的概率
# probabilities = gmm.predict_proba(X)
# print("部分样本属于各簇的概率:\n", probabilities[:5])选择哪种聚类算法,最终还是得看你的数据特点和具体需求。没有绝对的“最好”,只有最适合。我通常会先用K-means快速跑一下看看大概情况,如果效果不理想,再尝试DBSCAN或GMM。毕竟,数据科学很多时候就是一场不断尝试和优化的过程。
以上就是Python怎样实现数据聚类?K-means算法优化的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号