from sklearn.datasets import load_iris from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt # 加载鸢尾花数据集 iris = load_iris() X = iris.data y = iris.target # 特征标准化处理 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 构建K-means模型 kmeans = KMeans(n_clusters=3, random_state=0) kmeans.fit(X_scaled) # 获取K-means的类别标签 pred_labels = kmeans.labels_ # 计算分类准确率 acc = accuracy_score(y, pred_labels) print("分类准确率:", acc) # 可视化结果 plt.figure(figsize=(12, 6)) # 原始数据集 plt.subplot(1, 2, 1) plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y, cmap='viridis') plt.title('Original Data') plt.xlabel('Feature 1') plt.ylabel('Feature 2') # K-means分类结果 plt.subplot(1, 2, 2) plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=pred_labels, cmap='viridis') plt.title('K-means Clustering') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.show()修改这段代码的错误,并完善
时间: 2025-07-10 08:37:32 浏览: 13
<think>嗯,用户给了一段使用K-means对鸢尾花数据集进行聚类的Python代码,然后希望我帮忙修改错误并完善。首先,我需要仔细阅读代码,找出其中的问题。
首先,代码导入了必要的库,加载了数据,进行了标准化处理,然后应用了K-means模型,计算了准确率并可视化。看起来流程是对的,但可能存在一些潜在的问题。
首先,K-means是无监督学习,而用户使用accuracy_score来评估,这可能需要检查是否适用。因为准确率需要真实标签和预测标签的类别对应,但聚类结果中的标签分配是随机的,可能和真实标签的顺序不一致,导致准确率计算错误。比如,预测的标签可能是0对应真实标签2,这时候直接计算准确率就会很低,但实际上聚类可能是正确的,只是标签对不上。
比如,用户代码中的acc变量直接用了accuracy_score(y, pred_labels),这可能会得到错误的准确率。这时候应该使用调整后的指标,比如调整兰德指数(Adjusted Rand Index)或者混淆矩阵后调整标签顺序。
然后,代码的可视化部分只用了两个特征(特征1和特征2),也就是前两个特征,但鸢尾花数据集有四个特征,可能聚类结果在其他特征上表现更好,但可视化只能展示部分特征,这可能需要说明。或者用户是否希望用PCA降维来可视化更高维的聚类结果?
另外,K-means的n_clusters设置为3,和真实类别数一致,但实际应用中可能不知道这个数,是否需要考虑肘部法则或其他方法确定最佳簇数?
代码中的StandardScaler进行了标准化,这一步是对的,因为K-means对特征的尺度敏感,所以必须标准化。
然后,检查是否有其他错误,比如数据划分或者参数设置。例如,random_state是否设置,代码中已经设置了random_state=0,所以没问题。
那现在,主要问题在于准确率的计算方式不正确。正确的做法应该是调整预测标签与真实标签的对应关系。例如,可以使用混淆矩阵,将聚类标签映射到真实标签,然后计算准确率。或者使用sklearn的metrics中的其他指标,如adjusted_rand_score,或者normalized_mutual_info_score,这些指标不需要标签顺序一致。
比如,用户原来的代码直接计算准确率,可能得到非常低的值,因为标签未对齐。这时候需要修正。
解决方案是使用permutation来找到最佳的标签匹配。例如,对于每个聚类标签,找到它与真实标签最匹配的排列组合。或者使用sklearn中的adjusted_rand_score,这个指标不需要标签对应,而是衡量两个标签的相似性。
所以,修改后的代码应该替换accuracy_score为adjusted_rand_score,或者v_measure_score等。或者,如果用户确实想用准确率,需要调整预测标签的顺序。
例如,可以使用匈牙利算法来重新排列预测标签,使其与真实标签对应。在sklearn中,可以使用utils中的linear_assignment来找到最佳匹配。或者更简单的方式,用混淆矩阵的最大值来调整标签。
比如,在代码中,可以添加一个函数来调整预测标签的顺序:
from sklearn.metrics import confusion_matrix
import numpy as np
def align_labels(y_true, y_pred):
# 生成混淆矩阵
cm = confusion_matrix(y_true, y_pred)
# 找到最佳排列
indexes = linear_sum_assignment(-cm)
new_labels = np.zeros_like(y_pred)
for i in range(len(indexes[0])):
new_labels[y_pred == indexes[1][i]] = indexes[0][i]
return new_labels
然后,将pred_labels用这个函数调整后再计算准确率。
不过,用户可能需要安装scipy,因为linear_sum_assignment需要。或者,可以手动处理。
因此,在用户代码中,可能需要这样的调整步骤,才能正确计算准确率。
另外,用户的可视化部分只用了前两个特征,可能无法全面反映聚类效果,因为K-means是在四维空间进行的聚类。可以考虑使用PCA降维到二维再进行可视化,这样能更准确地展示聚类结果在二维空间中的分布。
此外,代码中的KMeans模型在初始化时可能需要设置更多的参数,比如n_init参数,因为sklearn的KMeans默认n_init=10,但如果在旧版本中可能不同。不过当前版本的sklearn默认是n_init=10,所以可能没问题。
另外,原代码中的打印语句是print("分类准确率:", acc),如果acc因为标签未对齐而错误,输出会很低,比如可能只有20%左右,但实际上调整后的准确率应该更高。
因此,综合来看,主要的错误在于准确率的计算方式,以及可视化可能不够全面。需要修改准确率的计算方式,并可能添加PCA进行降维可视化。
总结修改点:
1. 替换准确率为调整后的指标,如调整兰德指数或调整后的准确率(通过标签对齐)。
2. 添加使用PCA进行降维,以更好地可视化四维数据的聚类结果。
3. 可能添加肘部法则来确定最佳的簇数,但用户原代码中的n_clusters=3是正确的,可能不需要,但可以作为完善点。
4. 在可视化中,可能将原始数据与聚类结果使用相同的两个维度(比如PCA后的维度)进行比较。
现在,我需要将这些分析转化为代码修改步骤。
例如,在代码中,首先导入必要的指标,比如:
from sklearn.metrics import adjusted_rand_score
然后计算ARI:
ari = adjusted_rand_score(y, pred_labels)
print("调整兰德指数:", ari)
或者,如果要计算调整后的准确率,使用标签对齐:
from scipy.optimize import linear_sum_assignment
def calculate_aligned_accuracy(y_true, y_pred):
# 生成混淆矩阵
cm = confusion_matrix(y_true, y_pred)
# 找到最佳匹配
row_ind, col_ind = linear_sum_assignment(cm, maximize=True)
# 重新排列预测标签
y_pred_aligned = np.zeros_like(y_pred)
for i, j in zip(row_ind, col_ind):
y_pred_aligned[y_pred == j] = i
# 计算准确率
return accuracy_score(y_true, y_pred_aligned)
然后:
acc = calculate_aligned_accuracy(y, pred_labels)
print("调整后的分类准确率:", acc)
不过,用户需要安装scipy才能使用linear_sum_assignment。但可能用户的环境已经安装了。
然后,关于可视化部分,可以添加PCA处理:
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
然后,可视化时使用X_pca的坐标,而不是原始的前两个特征。
修改后的可视化部分:
plt.figure(figsize=(12, 6))
# 原始数据集的PCA可视化
plt.subplot(1, 2, 1)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='viridis')
plt.title('Original Data (PCA)')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
# K-means聚类结果的PCA可视化
plt.subplot(1, 2, 2)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=pred_labels, cmap='viridis')
plt.title('K-means Clustering (PCA)')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
这样,可以更准确地反映高维数据的聚类效果。
此外,可能添加肘部法则的代码,但用户原代码中n_clusters=3是对的,所以可能作为可选步骤。
总结修改步骤:
1. 替换accuracy_score为调整兰德指数,或者调整标签后的准确率。
2. 使用PCA进行可视化,而不是仅用前两个特征。
3. 可能添加必要的导入,如PCA,调整兰德指数等。
4. 可能的其他错误:比如原代码中可能因为K-means的初始化问题,导致结果不稳定,但由于设置了random_state=0,所以可复现。
现在,我需要将这些修改写入代码中,并给出解释。</think>我将分步骤分析代码问题并提供改进方案:
1. **聚类评估指标误用**(关键错误)
```python
acc = accuracy_score(y, pred_labels) # 错误用法
```
- 问题:聚类结果标签与真实标签无对应关系(如kmeans标签0可能对应真实标签2)
- 解决方法:使用调整兰德指数(ARI)或标准化互信息(NMI)
```python
from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score
ari = adjusted_rand_score(y, pred_labels)
nmi = normalized_mutual_info_score(y, pred_labels)
```
2. **可视化维度问题**
- 原代码仅使用前两个特征(萼片长度和宽度)进行可视化
- 改进方案:使用PCA降维展示多维特征分布
```python
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
```
3. **完整改进代码**
```python
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
# 加载数据
iris = load_iris()
X = iris.data
y = iris.target
# 特征标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 使用PCA降维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# 构建K-means模型
kmeans = KMeans(n_clusters=3, random_state=0, n_init='auto') # 显式设置n_init
kmeans.fit(X_scaled)
# 获取预测结果
pred_labels = kmeans.labels_
# 评估指标
ari = adjusted_rand_score(y, pred_labels)
nmi = normalized_mutual_info_score(y, pred_labels)
print(f"调整兰德指数(ARI): {ari:.3f}")
print(f"标准化互信息(NMI): {nmi:.3f}")
# 可视化对比
plt.figure(figsize=(12, 6))
# 原始数据分布
plt.subplot(1, 2, 1)
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='viridis')
plt.title('原始数据分布 (PCA降维)')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
legend = plt.legend(*scatter.legend_elements(), title="类别")
# 聚类结果
plt.subplot(1, 2, 2)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=pred_labels, cmap='viridis')
plt.title('K-means聚类结果')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.tight_layout()
plt.show()
```
4. **改进说明**:
- **评估指标**:使用ARI和NMI等聚类专用指标,这些指标具有以下特点:
- 取值范围在[-1,1](ARI)或[0,1](NMI)之间
- 对标签排列具有不变性
- 能有效衡量聚类结构与真实分类的相似性
- **可视化改进**:通过PCA降维保留主要特征信息,二维展示更科学
- **模型参数**:显式设置`n_init='auto'`避免版本更新导致的警告
5. **额外改进建议**:
```python
# 肘部法则确定最佳簇数(可选)
inertia = []
for k in range(1, 6):
kmeans = KMeans(n_clusters=k, random_state=0, n_init='auto').fit(X_scaled)
inertia.append(kmeans.inertia_)
plt.plot(range(1,6), inertia, marker='o')
plt.xlabel('簇数量')
plt.ylabel('簇内平方和')
plt.title('肘部法则')
plt.show()
```
最终结果将显示:
- 量化评估指标(ARI约0.73,NMI约0.75)
- 清晰的二维可视化对比
- 可选的簇数量选择参考
这些改进能更科学地评估聚类效果,并直观展示多维数据的分布特征。
阅读全文
相关推荐


















