机器学习-聚类分析-根据葡萄酒信息进行聚类并评估模型-K-means聚类、DBSCAN、AGglomerative NESting聚类
根据给定的葡萄酒分类记录,建立聚类模型,对葡萄酒信息进行聚类(此时注意去除数据集中分类信息),并进行模型评估。即主要内容是基于葡萄酒信息进行聚类分析和模型评估。首先加载并预处理数据,去除分类信息并进行标准化。接着,使用手肘法和轮廓系数确定K-means聚类的最佳簇数,并进行K-means聚类。然后,通过网格搜索找到DBSCAN的最佳参数,进行DBSCAN聚类。随后,采用最佳K值进行Agglomer
根据葡萄酒信息进行聚类并评估模型--K-means聚类、DBSCAN、AGglomerative NESting聚类
概述
根据给定的葡萄酒分类记录,建立聚类模型,对葡萄酒信息进行聚类(此时注意去除数据集中分类信息),并进行模型评估。即主要内容是基于葡萄酒信息进行聚类分析和模型评估。
首先加载并预处理数据,去除分类信息并进行标准化。接着,使用手肘法和轮廓系数确定K-means聚类的最佳簇数,并进行K-means聚类。然后,通过网格搜索找到DBSCAN的最佳参数,进行DBSCAN聚类。随后,采用最佳K值进行Agglomerative Clustering聚类。对三种聚类方法的结果进行评估,比较其轮廓系数并且使用PCA将数据降维至二维,不同颜色表示不同簇,绘制三种聚类模型的聚类结果图。最后,将每种聚类结果添加回原始数据,保存为Excel文件,以便进一步分析。
具体实现
1. 导包和数据预处理
导包和导数据:
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import numpy as np
plt. rcParams [ 'font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt. rcParams [ 'axes.unicode_minus']=False #用来正常显示负号
# 导入数据
file_path = r"YourPath\wine.xlsx"
wine_data = pd.read_excel(file_path)
因为聚类(Clustering)是一种无监督学习算法,而我们的数据集中的数据是有标签的,所以需要去掉标注然后进行聚类分析。然后每个属性数据值差异可能很大,所以需要把数据标准化从而更好地进行聚类,这里采用的是sklearn库里面的StandardScaler进行的标准化:
# 去掉分类信息那一列
wine_features = wine_data.drop(columns=['class'])
# 把数据标准化处理
scaler = StandardScaler()
wine_features_scaled = scaler.fit_transform(wine_features)
2. 使用K-means进行聚类
使用手肘法和轮廓系数确定K-means聚类的最佳簇数
手肘法是一种用于确定K-means中k值的方法。其核心思想是通过观察误差平方和(SSE)的变化曲线来选择最佳的聚类数。
而轮廓系数(Silhouette Coefficient)是一种用于评估聚类效果的指标,取值范围为[-1, 1]之间,值越接近于1越好。
于是,我从k=2开始遍历,每次遍历计算其对应的SSE和轮廓系数,并可视化展现出来:
# 使用手肘法和轮廓系数确定K值
sse = []
silhouette_scores = []
k_values = range(2, 11)
for k in k_values:
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(wine_features_scaled)
sse.append(kmeans.inertia_)
silhouette_scores.append(silhouette_score(wine_features_scaled, kmeans.labels_))
# 绘制手肘图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(k_values, sse, 'bo-')
plt.xlabel('K值')
plt.ylabel('SSE的值')
plt.title('手肘法确定k-means的k值')
# 绘制轮廓系数图
plt.subplot(1, 2, 2)
plt.plot(k_values, silhouette_scores, 'bo-')
plt.xlabel('K值')
plt.ylabel('轮廓系数')
plt.title('不同K值对应的轮廓系数')
plt.show()
得到结果如下:
手肘法,顾名思义是要找到那个手肘的地方,也就是看在哪个地方,SSE值下降变得缓慢了,那个地方就是手肘,对应的K值也就是我们想要的。(为什么要这么选呢?因为随着聚类数的增大,样本划分会更加精细,误差平方和会逐渐变小。但K也不是越大越好,极端情况下,我们的k值和我们的样本数一样,每个样本被划分为一个类,这样的聚类是没有意义的,所以综合考虑,选取手肘的地方的K作为最佳)
而不同K值对应的轮廓系数是要越大越好,从上面的两张图可以看出,K=3时,效果最好,所以我们的聚类数应该选择为3,进行K-means聚类。
进行聚类并评估指标
直接调用sklearn里面的KMeans类即可,设置随机状态为42以确保结果的可复现性。
# 找到合适的K值
optimal_k = k_values[silhouette_scores.index(max(silhouette_scores))]
print(f"合适的K值是: {optimal_k}")
# 应用K-means进行聚类
kmeans = KMeans(n_clusters=optimal_k, random_state=42)
kmeans_labels = kmeans.fit_predict(wine_features_scaled)
# 评估这个聚类的性能指标
kmeans_silhouette_score = silhouette_score(wine_features_scaled, kmeans_labels)
print(f"K-means 的轮廓系数得分是: {kmeans_silhouette_score}")
使用PCA降维并且可视化聚类结果
因为葡萄酒的这个属性很多,也就是每个样本的维度很高,无法直接可视化输出聚类的结果,需要使用PCA降维至二维,才能进行可视化。
主成分分析(Principal Component Analysis,简称PCA)是一种广泛应用于数据降维的技术。其基本原理是通过线性变换将高维数据映射到低维空间中,同时尽可能保留数据中的主要变化模式。PCA的目标是找到最能代表数据方差的主成分,并用这些主成分来表示原始数据,从而减少数据的维度。
于是,代码如下:
pca = PCA(n_components=2)
wine_pca = pca.fit_transform(wine_features_scaled)
# 绘制聚类结果图
plt.figure(figsize=(10, 5))
plt.scatter(wine_pca[:, 0], wine_pca[:, 1], c=kmeans_labels, cmap='viridis', marker='o')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.title('K-means 聚类结果图')
plt.colorbar(label='Cluster')
plt.show()
wine_pca是一个二维数组,每一行代表一个样本,每一列代表一个主成分。
wine_pca[:, 0]是PCA降维后的第一主成分的值,wine_pca[:, 1]是PCA降维后的第二主成分的值。
这段代码第五行的c参数指定每个点的颜色。这里用K-means聚类的标签kmeans_labels来指定颜色,不同的聚类标签将会被分配不同的颜色。cmap参数指定颜色映射方案,这里使用的是viridis,不同的标签会被映射为viridis颜色图中的不同颜色。
可视化结果如图:
3. 使用DBSSCAN进行聚类
尝试应用聚类
DBSCAN是一种基于密度的聚类算法,不需要预先指定簇的个数,最终的簇的个数是不定的,所以我们不需要像K-means那样去找最佳簇数。
该算法的核心思想是通过检查数据集中每个点的r邻域来搜索簇,如果某个点p的r邻域内包含多于MinPts个点,则将该点标记为核心对象,并创建一个以p为核心的簇。
但是这个算法需要输入设置Eps(半径范围)、MinPts(最小点数)。Eps用于定义点之间的距离阈值,而MinPts则用于确定是否一个点可以被认为是核心点。如果在Eps范围内有超过MinPts个点,则该点被视为核心点。
我在第一次尝试的时候,想当然的随便设置了这两个参数值,而且还没有加上判断类数是否超过1(无效聚类),导致出错,debug花了很久…
下面代码的参数设置的不正确,导致出错:
# 使用DBSSCAN进行聚类
dbscan = DBSCAN(eps=1.0, min_samples=5)
dbscan_labels = dbscan.fit_predict(wine_features_scaled)
# 评估DBSCAN聚类的性能
if len(set(dbscan_labels)) > 1:
dbscan_silhouette_score = silhouette_score(wine_features_scaled, dbscan_labels)
else:
dbscan_silhouette_score = -1 # 只有一个类,说明是无效聚类
print(f"DBSCAN的轮廓系数得分: {dbscan_silhouette_score}")
遍历找寻最佳的DBSCAN参数
于是,我们需要来找到这两个参数:Eps(半径范围)、MinPts(最小点数)。直接通过两层遍历,每次计算最近的轮廓系数,把最佳的参数保存下来。
如果想要进一步提升性能,可以扩大参数范围或者减小步长,来找到更优的参数值
# 参数设置的不合适,找寻最佳的DBSCAN的参数
best_score = -1
best_eps = 0
best_min_samples = 0
for eps in np.arange(0.2, 2.5, 0.1):
for min_samples in range(3, 10):
dbscan = DBSCAN(eps=eps, min_samples=min_samples)
dbscan_labels = dbscan.fit_predict(wine_features_scaled)
if len(set(dbscan_labels)) > 1:
score = silhouette_score(wine_features_scaled, dbscan_labels)
if score > best_score:
best_score = score
best_eps = eps
best_min_samples = min_samples
best_eps, best_min_samples, best_score
也就是说我们的半径范围设置为2.4,最小点数设置为3时可以取得最好的效果,此时的轮廓系数是0.2144
可视化聚类结果
因为前面用PCA降维了,所以这里直接得到结果绘图就行,代码如下:
# 用最好的参数进行DBSCAN聚类
dbscan = DBSCAN(eps=best_eps, min_samples=best_min_samples)
dbscan_labels = dbscan.fit_predict(wine_features_scaled)
if len(set(dbscan_labels)) > 1:
dbscan_silhouette_score = silhouette_score(wine_features_scaled, dbscan_labels)
else:
dbscan_silhouette_score = -1
# 绘制DBSCAN聚类结果图
plt.figure(figsize=(10, 5))
unique_labels = set(dbscan_labels)
colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
if k == -1:
# 噪声
col = [0, 0, 0, 1]
class_member_mask = (dbscan_labels == k)
xy = wine_pca[class_member_mask]
plt.scatter(xy[:, 0], xy[:, 1], c=[tuple(col)], label=f'Cluster {k}' if k != -1 else 'Noise', edgecolor='k')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.title('DBSCAN 聚类结果图')
plt.legend()
plt.show()
结果如下:
4. 使用AGglomerative NESting进行聚类
AGNES(Agglomerative Nesting)是一种层次聚类算法,采用自底向上的聚合策略。其基本思想是将数据集中的每个样本作为一个初始聚类簇,然后在算法运行的每一步中找出距离最近的两个簇,并将它们合并成一个新的簇。
具体实现的代码比较简单,步骤和前面也比较像,就不过多赘述了:
# 使用AGglomerative NESting进行聚类
agg = AgglomerativeClustering(n_clusters=optimal_k)
agg_labels = agg.fit_predict(wine_features_scaled)
# 评估AGglomerative NESting聚类
agg_silhouette_score = silhouette_score(wine_features_scaled, agg_labels)
print(f"AGglomerative NESting的轮廓系数: {agg_silhouette_score}")
# 绘制AGglomerative NESting聚类结果
plt.figure(figsize=(10, 5))
unique_labels = set(agg_labels)
colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
class_member_mask = (agg_labels == k)
xy = wine_pca[class_member_mask]
plt.scatter(xy[:, 0], xy[:, 1], c=[tuple(col)], label=f'Cluster {k}', edgecolor='k')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.title('AGglomerative NESting 聚类结果图')
plt.legend()
plt.show()
5. 保存结果并与真实类别相比较
把每次聚类的结果写回,保存为excel,方便后续进一步分析处理。
# 把每一种聚类的结果添加回去,与真实的比较一下,看看哪种最好
wine_data['KMeans_Cluster'] = kmeans_labels
wine_data['DBSCAN_Cluster'] = dbscan_labels
wine_data['Agg_Cluster'] = agg_labels
# 保存结果到Excel文件
output_path = r"YourPath\result_wine_clustering.xlsx"
wine_data.to_excel(output_path, index=False)
wine_data.head()
可以看出,确实是有些样本的聚类和真实的是不一样的。
总结
从结果可以发现K-means聚类效果最好,其次是AGglomerative NESting,DBSCAN效果最差。而这三种都是基于划分、密度、层次的聚类中的典型算法,每种算法的具体应用场景不一样,选择对应的算法的时候也要根据环境选择更为合适的算法。
如果本文对您有帮助的话,希望您能点个赞,谢谢!
更多推荐
所有评论(0)