机器 进修聚类模型:K-means聚类
一、聚类介绍
1、 何是聚类
聚类:物以类聚,人以群分。
2、分类和聚类
分类(Classification)和聚类(Clustering)是机器 进修和数据挖掘中的两种重要技术。它们的主要区别在于是否需要已知的标签数据。下面分别介绍这两种技术,并通过一个通俗易懂的例子来说明它们的区别。
(1)分类(Classification)
定义:
分类是一种有监督的 进修 技巧,它根据已有的标注数据(即带有标签的数据集)来训练模型, 接着利用该模型对新的未知数据进行分类预测。简单来说,分类就是将数据归入预先定义好的类别中。
特点:
– 需要标注数据:分类任务需要有已知标签的数据作为训练集。
– 预测标签:分类模型的目标是预测新数据的标签。
– 应用场景广泛:例如垃圾邮件过滤、图像识别、情感分析等。
示例:
假设你有一个水果篮子,里面有一些苹果和一些橙子。你需要训练一个模型来自动区分苹果和橙子。
– 训练数据:
– 已知标签数据:苹果(绿色或红色)、橙子(橙色)
– 特征:颜色(绿色、红色、橙色)
– 训练 经过:
– 使用已知标签的数据(苹果和橙子的颜色)训练一个分类模型。
– 预测 经过:
– 新来的水果(例如一个绿色的水果),模型会预测这是苹果。
(2)聚类(Clustering)
定义:
聚类是一种无监督的 进修 技巧,它将没有标签的数据集分成若干个组(簇),使得同一组内的数据相似度较高,而不同组之间的相似度较低。聚类的目标是发现数据的内在结构。
特点:
– 不需要标注数据 |:聚类任务不需要已知标签的数据作为训练集。
– 发现数据结构 :聚类模型的目标是发现数据的内在分组结构。
– 应用场景广泛:例如市场细分、推荐 体系、异常检测等。
示例:
假设你有一个水果篮子,里面有一些水果,但你不知道它们是 何种类,也没有任何标签信息。你需要通过聚类算法来自动将这些水果分成几类。
– 数据集:
– 未标注数据:若干个水果(可能是苹果、橙子或其他水果)
– 特征:颜色(绿色、红色、橙色)、形状(圆形、椭圆形)
– 聚类 经过:
– 使用聚类算法(如 K-Means 或 DBSCAN)对水果进行分组。
– 算 根据颜色和形状等特征自动将水果分成 几许簇。
– 结局:
– 假设最终聚类 结局为三组:
– 第一组:绿色水果(可能是苹果)
– 第二组:红色水果(可能是苹果)
– 第三组:橙色水果(可能是橙子)
通过这个例子可以看出,分类是有监督的 进修 技巧,需要已知标签数据;而聚类是无监督的 进修 技巧,不需要已知标签数据。分类的目标是预测新数据的标签,而聚类的目标是发现数据的内在结构并进行分组。
3、常见的聚类算法
常用的聚类算法包括K均值聚类、层次聚类、DBSCAN等。
(1) K均值聚类(K-means Clustering):K均值聚类是最常用的聚类算法 其中一个。它将数据点分为K个簇,每个簇由距离最近的聚类中心负责。该算法通过迭代优化簇的中心位置,使得簇内的数据点与其聚类中心的距离最小化。
(2) 层次聚类(Hierarchical Clustering):层次聚类将数据点组织成层次结构,形成一个树状的聚类 结局。该算法可以是自下而上的聚合聚类(凝聚聚类)或自上而下的分裂聚类(分离聚类)。层次聚类不需要预先指定聚类的个数,可以通过树状结构的可视化 结局来选择合适的聚类个数。
(3) DBSCAN(Density-Based Spatial Clustering of Applications with Noise):DBSCAN是一种基于密度的聚类算法。该算法通过将密度相连的数据点分为一个簇,而将低密度区域作为噪声点。DBSCAN对簇的形状和 大致没有要求,可以处理非凸形状的簇,并能够自动识别噪声点。
聚类算法的选择取决于数据的特点和需求。不同的算法适用于不同类型的数据和 难题。在实际应用中,通常需要根据数据的分布、特征以及聚类目标来选择合适的聚类算法。
二、K-means聚类
1、K-means 算法的步骤
K-means算法是一种非常流行的无监督 进修 技巧,主要用于数据聚类。它的核心 想法是将数据集划分为K个簇(cluster),使得每个数据点归属于距离最近的簇中心。
基本 想法:
(1) 初始化:选择K个初始簇中心。
(2) 分配数据点:将每个数据点分配给最近的簇中心。
(3) 更新簇中心:重新计算每个簇的中心(通常是簇内数据点的平均值)。
(4) 重复迭代:重复第2步和第3步,直到簇中心不再发生显著变化或达到最大迭代次数。
K-means算法步骤:
(1) 初始化
– 选择K个初始簇中心。通常随机选择K个数据点作为初始簇中心,也可以采用更复杂的 技巧(如K-means++)来选择初始簇中心。
(2) 分配数据点
– 对于每个数据点,计算它与每个簇中心的距离(通常使用欧几里得距离)。
– 将每个数据点分配给距离最近的簇中心。
(3) 更新簇中心
– 对于每个簇,计算该簇内所有数据点的均值,将其作为新的簇中心。
– 如果簇中心的变化小于某个阈值或达到预设的最大迭代次数,则停止迭代;否则,返回第2步继续迭代。需要注意的是,K均值聚类 一个迭代算法,每次迭代都会更新聚类中心和重新分配数据点。因此,初始聚类中心的选择可以影响最终的聚类 结局。通常可以采用多次运行K均值聚类算法并选择最优的 结局。
2、举例说明K-means算法流程
假设有5个待聚类的数据点,如下所示:
P1 = (1, 1)
P2 = (1.5, 0.5)
P3 = (1.6, 1.5)
P4 = (3, 3)
P5 = (3.5, 3.5)
初始化质心:
我们可以随机选择两个数据点作为初始质心。这里假设初始质心为:
C1 = (1, 1)
C2 = (3, 3)
第1次迭代:
步骤-1:计算每个数据点到每个质心的距离,并分配最近的质心
根据计算 结局,可以得到每个点的归属:
步骤 2: 更新质心位置
Python绘制第1次迭代 经过图:
import tplotlib.pyplot as plt
# 数据点
points = [(1, 1), (1.5, 0.5), (1.6, 1.5), (3, 3), (3.5, 3.5)]
# 质心
centroids = [(1.367, 1.0), (3.25, 3.25)]
# 分配颜色
colors = ['blue', 'red']
plt.scatter(*zip(*points), c=['blue']*3 + ['red']*2)
plt.scatter(*zip(*centroids), c=['green']*2, rker='x')
plt.show()
第2次迭代
步骤 1: 计算新的距离并重新分配
根据计算 结局,可以得到每个点的归属:
步骤 2: 更新质心位置
由于质心没有变化,因此算法收敛。
最终 结局:
-质心 C1=(1.367,1.0)
-质心 C2=(3.25,3.25)
3、手写代码实现K-means
(1) 代码实现
为了展示K-means聚类的 经过,我们将手动实现K-means算法,并绘制每次迭代的散点图。
我们有 下面内容五个数据点:
– (1, 1)
– (1.5, 0.5)
– (1.6, 1.5)
– (3, 3)
– (3.5, 3.5)
我们希望将这些点分成两个簇。
import tplotlib.pyplot as plt
import random
# 数据点
data_points = [(1, 1), (1.5, 0.5), (1.6, 1.5), (3, 3), (3.5, 3.5)]
# 初始质心随机选取
def initialize_centroids(data, k):
centroids = random.sample(data, k)
return centroids
# 计算欧式距离
def euclidean_distance(point1, point2):
return ((point1[0] – point2[0]) |2 + (point1[1] – point2[1]) |2) |0.5
# 分配点到最近的质心
def assign_clusters(data, centroids):
clusters = {}
for i in range(len(centroids)):
clusters[i] = []
for point in data:
distances = [euclidean_distance(point, centroid) for centroid in centroids]
cluster_index = distances.index(min(distances))
clusters[cluster_index].append(point)
return clusters
# 更新质心
def update_centroids(clusters):
new_centroids = []
for cluster in clusters.values():
if cluster:
new_centroid = (sum([p[0] for p in cluster]) / len(cluster),
sum([p[1] for p in cluster]) / len(cluster))
new_centroids.append(new_centroid)
else:
new_centroids.append(None)
return new_centroids
# 绘制散点图
def plot_clusters(data, centroids, clusters, iteration):
colors = ['red', 'blue']
plt.figure()
for i, cluster in enumerate(clusters.values()):
for point in cluster:
plt.scatter(point[0], point[1], color=colors[i])
for i, centroid in enumerate(centroids):
plt.scatter(centroid[0], centroid[1], rker='x', color=colors[i], s=100)
plt.title(f”Iteration {iteration}”)
plt.show()
# K-means主函数
def k_means(data, k, x_iterations=100):
centroids = initialize_centroids(data, k)
iteration = 0
while True:
print(f”Iteration {iteration}:”)
clusters = assign_clusters(data, centroids)
print(“Clusters:”)
for i, cluster in enumerate(clusters.values()):
print(f”Cluster {i}: {cluster}”)
new_centroids = update_centroids(clusters)
print(“New centroids:”)
for i, centroid in enumerate(new_centroids):
print(f”Centroid {i}: {centroid}”)
if centroids == new_centroids or iteration >= x_iterations:
break
centroids = new_centroids
plot_clusters(data, centroids, clusters, iteration)
iteration += 1
return clusters, centroids
# 运行K-means
clusters, final_centroids = k_means(data_points, k=2)
结局输出:
Iteration 0:
Clusters:
Cluster 0: [(1, 1), (1.5, 0.5), (1.6, 1.5)]
Cluster 1: [(3, 3), (3.5, 3.5)]
New centroids:
Centroid 0: (1.3666666666666665, 1.0)
Centroid 1: (3.25, 3.25)
Iteration 1:
Clusters:
Cluster 0: [(1, 1), (1.5, 0.5), (1.6, 1.5)]
Cluster 1: [(3, 3), (3.5, 3.5)]
New centroids:
Centroid 0: (1.3666666666666665, 1.0)
Centroid 1: (3.25, 3.25)
(2) 代码解读
代码片段-1
# 初始质心随机选取
def initialize_centroids(data, k):
centroids = random.sample(data, k)
return centroids
代码解析:
【1】 函数定义:
– def initialize_centroids(data, k)::定义一个名为 initialize_centroids 的函数,该函数接收两个参数:
– data:输入数据集(通常 一个列表或数组)。
– k:需要选择的质心数量。
【2】 随机选取质心:
– centroids = random.sample(data, k):从 data 中随机选择 k 个不同的元素。这里使用了 random.sample 函数,它会返回一个包含 k 个
随机元素的列表。这些元素将作为初始质心。
【3】 返回质心:
– return centroids:返回选定的初始质心列表。
代码片段-2
# 分配点到最近的质心
def assign_clusters(data, centroids):
clusters = {}
for i in range(len(centroids)):
clusters[i] = []
for point in data:
distances = [euclidean_distance(point, centroid) for centroid in centroids]
cluster_index = distances.index(min(distances))
clusters[cluster_index].append(point)
return clusters
代码解析:
这个函数的主要 影响是根据当前的质心,将数据点分配到最近的质心所在的簇中,这是 K-means 算法中的一个重要步骤。
【1】导入必要的库:
– import th:导入数学库,用于计算平方根。
【2】 定义欧几里得距离函数:
– def euclidean_distance(point1, point2):
– 计算两个点之间的欧几里得距离。
– return th.sqrt(sum((p1 – p2) 2 for p1, p2 in zip(point1, point2))):使用列表推导式计算两个点各维度差的平方和, 接着求平方根。
【3】 定义分配簇的函数:
– def assign_clusters(data, centroids):
– 接收两个参数:
– data:输入数据集(通常 一个列表或数组)。
– centroids:质心列表。
【4】 初始化簇字典:
– clusters = {}:创建一个空字典来存储每个质心对应的簇。
– for i in range(len(centroids)): clusters[i] = []:遍历每个质心,并将其对应的簇初始化为空列表。
【5】 遍历数据点并分配到最近的质心:
– for point in data::遍历每个数据点。
– distances = [euclidean_distance(point, centroid) for centroid in centroids]:计算当前数据点与所有质心之间的距离。
– cluster_index = distances.index(min(distances)):找到距离当前数据点最近的质心的索引。
– clusters[cluster_index].append(point):将当前数据点添加到最近的质心对应的簇中。
【6】 返回分配好的簇:
– return clusters:返回最终分配好的簇字典。
代码片段-3
def update_centroids(clusters):
new_centroids = []
for cluster in clusters.values():
if cluster:
new_centroid = (sum([p[0] for p in cluster]) / len(cluster),
sum([p[1] for p in cluster]) / len(cluster))
new_centroids.append(new_centroid)
else:
new_centroids.append(None)
return new_centroids
代码解析:
这个函数的主要 影响是根据每个簇中的数据点计算新的质心坐标,并返回一个包含所有新质心的列表。如果某个簇为空,则将 None 添加到列表中。
【1】 定义更新质心的函数:
– def update_centroids(clusters):
– 接收一个参数 clusters:这 一个字典,其中键是簇的索引,值是对应簇中的数据点列表。
【2】 初始化新的质心列表:
– new_centroids = []:创建一个空列表来存储更新后的质心。
【3】 遍历每个簇:
– for cluster in clusters.values():
– 使用 values() 技巧获取字典中的值,即每个簇中的数据点列表。
【4】检查簇是否为空:
– if cluster::如果当前簇中有数据点,则进行质心计算。
– 否则,如果簇为空,则跳过此簇。
【5】计算新质心的坐标:
– new_centroid_x = sum([p[0] for p in cluster]) / len(cluster)
– 计算簇中所有数据点在 x 轴上的坐标的平均值。
– new_centroid_y = sum([p[1] for p in cluster]) / len(cluster)
– 计算簇中所有数据点在 y 轴上的坐标的平均值。
– 将新质心的坐标组合成一个元组:new_centroid = (new_centroid_x, new_centroid_y)
【6】将新质心添加到列表中:
– new_centroids.append(new_centroid):将新质心添加到新的质心列表中。
【7】 处理空簇的情况:
– else: new_centroids.append(None):如果当前簇为空,则将 None 添加到新的质心列表中。
【8】返回更新后的质心列表:
– return new_centroids:返回最终更新后的质心列表。
代码片段-4
def plot_clusters(data, centroids, clusters, iteration):
colors = ['red', 'blue']
plt.figure()
for i, cluster in enumerate(clusters.values()):
for point in cluster:
plt.scatter(point[0], point[1], color=colors[i])
for i, centroid in enumerate(centroids):
plt.scatter(centroid[0], centroid[1], rker='x', color=colors[i], s=100)
plt.title(f”Iteration {iteration}”)
plt.show()
代码解析:
这个函数的主要 影响是根据给定的数据点、质心和簇,绘制当前迭代 情形下的数据点分布和质心位置。不同簇的数据点用不同的颜色表示,质心用
x 标记并放大显示。
【1】导入绘图库:
– import tplotlib.pyplot as plt:导入 tplotlib.pyplot 模块,并简写为 plt。
【2】 定义绘图函数:
– def plot_clusters(data, centroids, clusters, iteration):
– 接收四个参数:
– data:原始数据点。
– centroids:当前的质心坐标。
– clusters:当前的簇, 一个字典,键是簇的索引,值是对应簇中的数据点列表。
– iteration:当前迭代次数。
【3】定义颜色列表:
– colors = [red, blue]:定义一个颜色列表,用于区分不同的簇。
【4】 创建一个新的图形窗口:
– plt.figure():创建一个新的图形窗口。
【5】 绘制每个簇的数据点:
– for i, cluster in enumerate(clusters.values()):
– enumerate(clusters.values()):遍历每个簇中的数据点列表,并获取索引 i 和簇 cluster。
– for point in cluster::对于每个簇中的每个数据点。
– plt.scatter(point[0], point[1], color=colors[i]):使用散点图绘制数据点,并使用不同的颜色来区分不同的簇。
【6】绘制质心:
– for i, centroid in enumerate(centroids):
– enumerate(centroids):遍历每个质心,并获取索引 i 和质心 centroid。
– plt.scatter(centroid[0], centroid[1], rker=x, color=colors[i], s=100):使用散点图绘制质心,使用 x 标记,并设置颜色和 大致。
【7】 设置图形 深入了解:
– plt.title(f”Iteration {iteration}”):设置图形 深入了解,显示当前迭代次数。
【8】显示图形:
– plt.show():显示图形。
代码片段-5
def k_means(data, k, x_iterations=100):
centroids = initialize_centroids(data, k)
iteration = 0
while True:
print(f”Iteration {iteration}:”)
clusters = assign_clusters(data, centroids)
print(“Clusters:”)
for i, cluster in enumerate(clusters.values()):
print(f”Cluster {i}: {cluster}”)
new_centroids = update_centroids(clusters)
print(“New centroids:”)
for i, centroid in enumerate(new_centroids):
print(f”Centroid {i}: {centroid}”)
if centroids == new_centroids or iteration >= x_iterations:
break
centroids = new_centroids
plot_clusters(data, centroids, clusters, iteration)
iteration += 1
return clusters, centroids
代码解析:
【1】导入必要的库:
– import numpy as np:导入 NumPy 库,用于矩阵运算。
– import tplotlib.pyplot as plt:导入 Matplotlib 库,用于绘图。
【2】初始化质心函数:
– initialize_centroids(data, k):
– 随机选择 k 个数据点作为初始质心。
– 使用 np.random.choice 从数据集中随机选择 k 个索引,并提取对应的质心。
【3】分配簇函数:
– assign_clusters(data, centroids):
– 将每个数据点分配到最近的质心所在的簇中。
– 遍历每个数据点,计算其与所有质心的距离,并找到距离最近的质心索引。
– 将数据点添加到对应的簇中。
【4】更新质心函数:
– update_centroids(clusters):
– 计算每个簇的新质心。
– 遍历每个簇,计算簇中所有数据点的均值作为新的质心。
【5】 K-means 主函数:
– k_means(data, k, x_iterations=100):
– 初始化质心。
– 迭代 经过:
– 分配簇。
– 更新质心。
– 如果质心不再变化或达到最大迭代次数,则停止迭代。
– 绘制当前迭代的 结局。
– 增加迭代计数。
– 返回最终的簇和质心。
【6】绘制聚类 结局函数:
– plot_clusters(data, centroids, clusters, iteration):
– 绘制当前迭代的聚类 结局。
– 使用不同的颜色绘制不同簇的数据点。
– 使用 'x' 标记绘制质心。
– 设置图形 深入了解并显示图形。
再详细一点的注释如下所示:
'''
import numpy as np
import tplotlib.pyplot as plt
# 初始化质心函数
def initialize_centroids(data, k):
“””
随机选择 k 个数据点作为初始质心。
参数:
– data: 输入数据集,形状为 (n_samples, n_features)
– k: 质心的数量
返回:
– centroids: 初始质心,形状为 (k, n_features)
“””
# 随机选择 k 个数据点作为初始质心
indices = np.random.choice(len(data), size=k, replace=False)
centroids = data[indices]
return centroids
# 分配簇函数
def assign_clusters(data, centroids):
“””
将每个数据点分配到最近的质心所在的簇中。
参数:
– data: 输入数据集,形状为 (n_samples, n_features)
– centroids: 当前的质心,形状为 (k, n_features)
返回:
– clusters: 簇的字典,键是簇的索引,值是该簇中的数据点列表
“””
clusters = {}
# 遍历每个数据点
for point in data:
# 计算每个数据点到所有质心的距离
distances = [np.linalg.norm(point – centroid) for centroid in centroids]
# 找到距离最近的质心的索引
closest_centroid_index = np.argmin(distances)
# 将数据点添加到对应的簇中
if closest_centroid_index not in clusters:
clusters[closest_centroid_index] = []
clusters[closest_centroid_index].append(point)
return clusters
# 更新质心函数
def update_centroids(clusters):
“””
计算每个簇的新质心。
参数:
– clusters: 簇的字典,键是簇的索引,值是该簇中的数据点列表
返回:
– new_centroids: 新的质心,形状为 (k, n_features)
“””
new_centroids = []
# 遍历每个簇
for cluster in clusters.values():
# 计算簇中所有数据点的均值作为新的质心
new_centroid = np.mean(cluster, axis=0)
new_centroids.append(new_centroid)
return np.array(new_centroids)
# K-means 主函数
def k_means(data, k, x_iterations=100):
“””
K-means 聚类算法。
参数:
– data: 输入数据集,形状为 (n_samples, n_features)
– k: 质心的数量
– x_iterations: 最大迭代次数,默认为 100
返回:
– clusters: 最终得到的簇,字典形式
– centroids: 最终得到的质心,形状为 (k, n_features)
“””
# 初始化质心
centroids = initialize_centroids(data, k)
iteration = 0
# 迭代 经过
while True:
print(f”Iteration {iteration}:”)
# 分配簇
clusters = assign_clusters(data, centroids)
print(“Clusters:”)
for i, cluster in enumerate(clusters.values()):
print(f”Cluster {i}: {cluster}”)
# 更新质心
new_centroids = update_centroids(clusters)
print(“New centroids:”)
for i, centroid in enumerate(new_centroids):
print(f”Centroid {i}: {centroid}”)
# 如果质心不再变化或达到最大迭代次数,则停止迭代
if np.array_equal(centroids, new_centroids) or iteration >= x_iterations:
break
# 更新质心
centroids = new_centroids
# 绘制当前迭代的 结局
plot_clusters(data, centroids, clusters, iteration)
# 增加迭代计数
iteration += 1
# 返回最终的簇和质心
return clusters, centroids
# 绘制聚类 结局函数
def plot_clusters(data, centroids, clusters, iteration):
“””
绘制当前迭代的聚类 结局。
参数:
– data: 输入数据集,形状为 (n_samples, n_features)
– centroids: 当前的质心,形状为 (k, n_features)
– clusters: 当前的簇,字典形式
– iteration: 当前迭代次数
“””
colors = ['red', 'blue']
plt.figure()
for i, cluster in enumerate(clusters.values()):
for point in cluster:
plt.scatter(point[0], point[1], color=colors[i])
for i, centroid in enumerate(centroids):
plt.scatter(centroid[0], centroid[1], rker='x', color=colors[i], s=100)
plt.title(f”Iteration {iteration}”)
plt.show()
4、K-means算法质心的更新 经过
(1) Python实现质心更新 经过
创建一个数据集,并使用K-means算法来演示质心的迭代 经过。每次迭代后,我们将绘制当前的数据点和质心,并用不同的颜色表示它们
所属的簇。
这个程序会执行 下面内容步骤:
【1】生成一个包含300个样本的数据集。
【2】使用随机初始化的 技巧选择初始质心。
【3】在每个迭代中分配每个点到最近的质心,并更新质心的位置。
【4】每次迭代后绘制当前的数据点和质心,并用不同的颜色表示它们所属的簇。
你可以调整 x_iters参数以改变迭代次数,也可以通过修改 ke_blobs函数中的参数来生成不同形状和 大致的数据集。
import numpy as np
import tplotlib.pyplot as plt
from sklearn.datasets import ke_blobs
# 生成数据集
X, _ = ke_blobs(n_samples=300, centers=3, random_state=42)
# 定义 K-means 算法
def k_means(X, k, x_iters=10):
# 随机选择初始质心
centroids = X[np.random.choice(X.shape[0], k, replace=False)]
for i in range( x_iters):
# 分配每个点到最近的质心
labels = assign_labels(X, centroids)
# 更新质心位置
new_centroids = update_centroids(X, labels, k)
# 绘制当前 情形
plot_clusters(X, centroids, labels, i)
# 检查质心是否变化
if np.allclose(centroids, new_centroids):
break
centroids = new_centroids
return centroids, labels
# 分配每个点到最近的质心
def assign_labels(X, centroids):
distances = np.linalg.norm(X[:, np.newaxis] – centroids, axis=2)
return np.argmin(distances, axis=1)
# 更新质心位置
def update_centroids(X, labels, k):
new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(k)])
return new_centroids
# 绘制当前 情形
def plot_clusters(X, centroids, labels, iteration):
plt.figure(figsize=(8, 6))
scatter = plt.scatter(X[:, 0], X[:, 1], c=labels, c p='viridis')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', rker='x', s=200, label='Centroids')
plt.title(f'Iteration {iteration}')
plt.legend()
plt.show()
# 执行 K-means
centroids, labels = k_means(X, k=3, x_iters=10)
(2) 代码解读
代码片段-1
def assign_labels(X, centroids):
distances = np.linalg.norm(X[:, np.newaxis] – centroids, axis=2)
return np.argmin(distances, axis=1)
代码解析:
给每个样本点分配一个最近的质心标签。
【1】参数X
– numpy.ndarray, 形状为 (n_samples, n_features); 样本数据集,其中 n_samples 是样本数量,n_features 是特征数量;样本数据集X 一个
二维数组,其中每一行表示一个样本,每一列表示一个特征。
【2】参数centroids
– numpy.ndarray, 形状为 (n_clusters, n_features);质心 ,其中 n_clusters 是聚类中心的数量。centroids也 一个二维数组,其中每一
行表示一个质心。
【3】计算距离矩阵
– X[:, np.newaxis] 将 X 的形状从 (n_samples, n_features) 变为 (n_samples, 1, n_features)。
– centroids 的形状为 (n_clusters, n_features)。
– X[:, np.newaxis] – centroids 的 结局 一个三维数组,形状为 (n_samples, n_clusters, n_features),表示每个样本到每个质心的距离向量。
– np.linalg.norm(…, axis=2) 计算每个样本到每个质心的欧氏距离,并得到一个形状为 (n_samples, n_clusters) 的距离矩阵。
【4】确定最近质心
– np.argmin(distances, axis=1) 沿着第二个维度(即对每个样本)找到最小距离的位置,即最近的质心索引。
【5】返回 结局
– 返回一个一维数组 labels,其中每个元素表示对应样本的最近质心索引。返回值为numpy.ndarray, 形状为 (n_samples,),每个样本对应的最近
质心索引(即标签)。
代码片段-2
# 更新质心位置
def update_centroids(X, labels, k):
new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(k)])
return new_centroids
代码解析:
【1】 参数说明:
– X:样本数据集, 一个二维数组,其中每一行表示一个样本,每一列表示一个特征。
– labels:每个样本对应的质心索引(即标签), 一个一维数组。
– k:聚类中心的数量, 一个整数。
【2】 更新质心位置:
– 使用列表推导式来计算新的质心位置:
[X[labels == i].mean(axis=0) for i in range(k)]
– 这里详细解释每一步操作:
– range(k):生成从 0 到 k-1 的整数序列。
– labels == i:生成一个布尔掩码,表示哪些样本的标签等于 i。
– X[labels == i]:使用布尔掩码从 X 中选择标签为 i 的样本子集。
– X[labels == i].mean(axis=0):计算这些样本在每个特征上的平均值,得到一个长度为 n_features 的一维数组。
– 列表推导式 [X[labels == i].mean(axis=0) for i in range(k)] 得到一个包含 k 个新质心的一维数组。
【3】 创建新的质心数组:
– np.array([…]) 将列表转换为一个形状为 (k, n_features) 的 NumPy 数组。
【4】返回 结局:
– 返回一个形状为 (k, n_features) 的数组 new_centroids,表示新的质心位置。
代码片段-3
def plot_clusters(X, centroids, labels, iteration):
plt.figure(figsize=(8, 6))
scatter = plt.scatter(X[:, 0], X[:, 1], c=labels, c p='viridis')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', rker='x', s=200, label='Centroids')
plt.title(f'Iteration {iteration}')
plt.legend()
plt.show()
代码解析:
【1】 导入所需的库:
import tplotlib.pyplot as plt
– tplotlib.pyplot 提供了绘制图形的功能。
【2】 定义函数 plot_clusters:
def plot_clusters(X, centroids, labels, iteration):
– X:样本数据集, 一个二维数组,其中每一行表示一个样本,每一列表示一个特征。
– centroids:当前的质心位置, 一个二维数组。
– labels:每个样本对应的质心索引(即标签), 一个一维数组。
– iteration:当前迭代次数, 一个整数。
【3】 创建图形窗口:
plt.figure(figsize=(8, 6))
– 创建一个新的图形窗口,设置图形 大致为 8×6 英寸。
【4】 绘制样本点:
scatter = plt.scatter(X[:, 0], X[:, 1], c=labels, c p='viridis')
– X[:, 0] 和 X[:, 1] 分别是样本的第一和第二特征。
– c=labels 表示根据每个样本的标签进行着色。
– c p='viridis' 使用 viridis 色彩映射方案对不同簇进行区分。
【5】 绘制质心点:
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', rker='x', s=200, label='Centroids')
– centroids[:, 0] 和 centroids[:, 1] 分别是质心的第一和第二特征。
– c='red' 表示用红色绘制质心点。
– rker='x' 使用 'x' 符号标记质心点。
– s=200 设置质心点的 大致。
– label='Centroids' 设置图例标签为 “Centroids”。
【6】 设置图形 深入了解:
plt.title(f'Iteration {iteration}')
– 设置图形 深入了解,显示当前迭代次数。
【7】 显示图例:
plt.legend()
– 在图形上显示图例。
【8】 显示图形:
plt.show()
– 在屏幕上显示绘制的图形。
5、K-means聚类K值得确定
(1)误差平方和SSE
误差平方和(Sum of Squares due to Error,简称SSE),也称为残差平方和(Residual Sum of Squares, RSS),在统计学中用于衡量一个模型预测值与实际观测值之间的差异程度。它 一个重要的度量标准,被广泛应用于线性回归分析、方差分析等场景。
误差平方和反映了数据点围绕其局部或全局拟合模型(如直线、平面等)的波动情况。具体来说,它是所有观测值与其对应预测值之间差值的平方和。
计算误差平方和有助于我们评估模型的拟合优度:误差平方和越小,表示模型对数据的拟合程度越高;反之,则说明模型与实际数据之间存在较大差距。
公式:
在实际应用中,误差平方和通常与其他指标一起使用,如均方误差(Mean Squared Error, MSE)、决定系数(R-squared)等,以更全面地评估模型性能。通过最小化误差平方和来进行参数估计是许多统计 技巧的核心 想法 其中一个,尤其是在最小二乘法中尤为重要。
(2) 手肘法确定K值
K-means聚类算法的手肘法是一种通过计算不同K值对应的簇内误差平方和(SSE)来确定最合适的K值的 技巧。SSE表示每个数据点与其所属簇的聚类中心之间的距离平方的总和。
手肘法的计算原理如下:
【1】对于给定的聚类 难题,尝试不同的K值,从较小的K开始逐步增加。
【2】对于每个K值,执行聚类算法,并计算相应的聚类 结局的总内部平方和(SSE)。SSE表示数据点与其所属聚类中心之间的距离平方和, 一个反映聚类紧密度的指标。SSE越小,表示聚类 结局越紧密。
【3】绘制K值和对应的SSE之间的关系曲线,形成一个折线图。
【4】观察折线图,寻找“手肘”处的K值。手肘处是指曲线形状突然变平缓的拐点,也就是SSE下降速度明显减缓的K值。
【5】找到手肘处的K值后,选择该K值作为最优的聚类数目。
手肘法的基本 想法是,在聚类数目逐渐增加时,SSE会逐渐减小,但减小的速度会逐渐减慢。当增加聚类数目不再显著降低SSE时,即出现拐点,该点称为“手肘”,表示聚类数目足够,进一步增加无法带来明显的改善。因此,手肘处的K值被认为是最优的聚类数目。
import numpy as np
import tplotlib.pyplot as plt
from sklearn.cluster import KMeans
import warnings
warnings.filterwarnings('ignore')
# 生成随机数据集
np.random.seed(0)
X = np.random.randn(100, 2)
#X
# 计算不同K值对应的SSE
k_values = range(1, 10)
sse_values = []
for k in k_values:
kmeans = KMeans(n_clusters=k)
kmeans.fit(X)
sse_values.append(kmeans.inertia_)
# 绘制手肘法曲线
plt.plot(k_values, sse_values)
plt.xlabel('K')
plt.ylabel('SSE')
plt.title('Elbow Method')
plt.show()
在上述代码中,X = np.random.randn(100, 2)是用来生成一个100行2列的矩阵或数组。这里使用了NumPy库的random.randn()函数,该函数返回一个由标准正态分布(均值为0,标准差为1)生成的随机数矩阵。因此,X表示一个包含100个样本的数据集,每个样本有2个特征。这里的数据集是随机生成的,用于示例目的。在实际应用中,数据集可以从现实 全球中收集到的数据中获取。
首先我们生成一个二维的随机数据集X。 接着,我们使用KMeans算法对数据集X进行聚类,并计算不同K值对应的SSE。在本例中,我们尝试了从K=1到K=9的不同K值。
接下来,我们将计算得到的SSE值绘制成手肘法曲线。横轴表示K值,纵轴表示对应K值下的SSE值。
运行以上代码,我们可以得到一个手肘法曲线。通过观察曲线的形状,我们可以找到一个”拐点”,该点对应的K值通常被认为是最合适的K值。在曲线中,我们会注意到SSE值开始下降, 然而随着K值的增加,其下降速度会变得缓慢,形成一个明显的手肘状的拐点。在本例中,我们可以看到拐点位于K=3附近,因此可以认为K=3是最合适的聚类数目。
需要注意的是,手肘法只是一种启发式 技巧,其并不是 完全准确的。在实际应用中,我们还需要结合其他评价指标和领域 智慧来选择最优的K值。
(3) 计算轮廓系数
轮廓系数(Silhouette Coefficient)是用于衡量样本与其被分配到的聚类簇之间的一致性,同时也衡量了与其他聚类簇的区分度。轮廓系数可以帮助我们评估聚类算法的效果,其值范围通常在-1到+1之间。一个较高的轮廓系数意味着样本与自己所在的簇内的其他样本相似度高, 并且与其他簇的样本相似度低。
计算轮廓系数的基本步骤如下:
【1】准备数据和 结局
首先,确保你已经对数据进行了聚类处理,并得到了聚类的 结局。每个样本都应该被分配到了某个聚类簇中。
【2】对于每个样本计算a(i)和b(i)
对于每一个样本i:
— 计算a(i),即样本i与它所在簇内所有其他样本之间的平均距离。
— 找出与样本i所在簇最接近的那个簇(但不包括样本i自身所在的簇), 接着计算样本i与这个最近邻簇内所有样本的平均距离,记作b(i)。
例如:
— 对于蓝色的簇,求样本i与它所在簇内所有其他样本之间的平均距离,a(i) = 平均值1
— 求蓝色的簇内某一点到电影簇的平均举例,得到平均值2;求蓝色的簇内某一点到绿色簇的平均举例,得到平均值3,那么b(i) = min(平均值2,平均值3)
【3】 计算轮廓系数s(i)
对于每个样本i,使用 下面内容公式来计算它的轮廓系数s(i):
如果a(i)等于0 并且b(i)也等于0,则定义s(i)为0。
【4】 计算总体轮廓系数
最后,通过对所有样本的轮廓系数取平均值得到整个数据集的轮廓系数:
其中n表示样本总数。
【5】 分析 结局
根据得到的轮廓系数S的值来评估聚类的效果。一般来说:
– 如果S接近+1,表示聚类效果很好;
– 如果S接近0,表示样本在各个簇之间的区分度不大;
– 如果S接近-1,表示样本可能被错误地分配给了错误的簇。
示例:
我们通过一个具体的例子来详细计算轮廓系数。假设我们有三个簇(Cluster A、Cluster B、Cluster C),每个簇中有三个数据点。我们将逐步计算每个数据点的 a(i) 、b(i) 和 s(i) 。假设数据点如下:
步骤-1:先计算每个数据点之间的欧氏距离
步骤-2:计算a(i)
对于每个数据点,计算其与所在簇内其他点的平均距离 a(i) 。
【1】对于Cluster A: P1(1,2), P2(2,1), P3(1,1)
【2】对于Cluster B: Q1(4,5), Q2(5,4), Q3(4,4)
【3】对于Cluster C: R1(7,8), R2(8,7), R3(7,7)
步骤-3:计算 b(i)
对于每个数据点,计算其轮廓系数 b(i) 。
【1】对于Cluster A: P1(1,2), P2(2,1), P3(1,1)
【2】对于Cluster B: Q1(4,5), Q2(5,4), Q3(4,4)
【3】对于Cluster C: R1(7,8), R2(8,7), R3(7,7)
步骤-4:计算 s(i)
对于每个数据点,计算其轮廓系数 s(i) 。
【1】对于Cluster A: P1(1,2), P2(2,1), P3(1,1)
【2】对于Cluster B: Q1(4,5), Q2(5,4), Q3(4,4)
【3】对于Cluster C: R1(7,8),R2(8,7), R3(7,7)
步骤-5: 最后计算平均轮廓系数
计算所有数据点的轮廓系数的平均值:
(4) 轮廓系数法求K值
K-means聚类算法的轮廓系数法是一种通过计算每个数据点的轮廓系数来评估聚类 结局的 技巧。轮廓系数是用于衡量聚类 结局的紧密度和分离度的指标,其值范围在[-1, 1]之间。轮廓系数越接近1表示聚类 结局越好,越接近-1表示聚类 结局越差。
Kmeans算法通过轮廓系数(Silhouette Coefficient)来确定最佳的K值的步骤如下:
【1】执行K-means:首先,你需要选择一个K值并运行K-means算法。这将会为每个样本分配一个簇。
【2】 计算轮廓系数
【3】更改K值并重复:更改K值,并重复上述步骤。通常来说,改变的K值在合理的范围内(比如从2到10)。
【4】选择最佳K值:具有最高平均轮廓系数的K值即为最佳K值。如果存在多个K值产生相同的轮廓系数,则需要根据具体 难题进行选择。
注意: 轮廓系数适用于簇的形状和 大致差异不大的情况,在处理具有较大尺寸或密度差异的数据集时可能无法获得较好的 结局。 除了这些之后,当数据量非常大时,计算轮廓系数的 时刻开销可能会比较大。
轮廓系数的取值范围在[-1, 1]之间。当轮廓系数接近1时,表示聚类 结局紧密且分离良好;当轮廓系数接近0时,表示聚类 结局存在重叠;当轮廓系数接近-1时,表示聚类 结局分离度较差。
import numpy as np
import tplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
# 生成随机数据集
np.random.seed(0)
X = np.random.randn(100, 2)
# 计算不同K值对应的轮廓系数
k_values = range(2, 10)
silhouette_scores = []
for k in k_values:
kmeans = KMeans(n_clusters=k)
kmeans.fit(X)
labels = kmeans.labels_
score = silhouette_score(X, labels)
silhouette_scores.append(score)
# 绘制轮廓系数法曲线
plt.plot(k_values, silhouette_scores)
plt.xlabel('K')
plt.ylabel('Silhouette Coefficient')
plt.title('Silhouette Method')
plt.show()
在上述代码中,我们首先生成一个二维的随机数据集X。 接着,我们使用KMeans算法对数据集X进行聚类,并计算不同K值对应的轮廓系数。
在本例中,我们尝试了从K=2到K=9的不同K值。对于每个K值,我们计算KMeans算法得到的类别标签,并使用sklearn库中的`silhouette_score`函数计算对应的轮廓系数。
接下来,我们将计算得到的轮廓系数绘制成轮廓系数法曲线。横轴表示K值,纵轴表示对应K值下的轮廓系数。
运行以上代码,我们可以得到一个轮廓系数法曲线。通过观察曲线的高低,我们可以找到一个峰值点,该点对应的K值通常被认为是最合适的聚类数目。在曲线中,我们会注意到轮廓系数值越接近1,代表聚类 结局越好。在本例中,我们可以看到峰值点位于K=8附近,因此可以认为K=8是最合适的聚类数目。
需要注意的是,轮廓系数法也只是一种评估聚类 结局的 技巧,其并不是 完全准确的。在实际应用中,我们还需要结合其他评价指标和领域 智慧来选择最优的K值。
三、K-means算法的例子
1、案例需求
现在我们对某些地区、省市的玉米进行聚类分类, 下面内容是用户的主要诉求:
【1】分析哪些地区是高产高面积区、中等产量区、低产低面积区
【2】分析哪些地区常量类似
假设我们的数据集如下:
import pandas as pd
data = { '省份': ['黑龙江', '吉林', '辽宁', '内蒙古', '河北', '山东', '河南', '山西', '陕西', '甘肃', '新疆', '四川', '云南', '贵州', '广西'], '产量': [3800, 2800, 1500, 2200, 1800, 2200, 2900, 800, 900, 600, 700, 1200, 1300, 700, 800], '面积': [5800, 4200, 2500, 3200, 2800, 3100, 3800, 1300, 1500, 1000, 1100, 1800, 1900, 1100, 1200] }
df = pd.DataFrame(data) print(“原始数据集:”) df
2、功能实现
步骤-1:引入类库、处理图像乱码、忽略警告
import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import confusion_ trix import tplotlib.pyplot as plt import seaborn as sns import warnings
# 1. 设置中文显示和忽略警告 plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文显示 plt.rcParams['axes.unicode_minus'] = False # 解决负号显示 难题 warnings.filterwarnings('ignore') # 忽略警告
步骤-2:定义数据集
# 2. 定义数据集 data = { '省份': ['黑龙江', '吉林', '辽宁', '内蒙古', '河北', '山东', '河南', '山西', '陕西', '甘肃', '新疆', '四川', '云南', '贵州', '广西'], '产量': [3800, 2800, 1500, 2200, 1800, 2200, 2900, 800, 900, 600, 700, 1200, 1300, 700, 800], '面积': [5800, 4200, 2500, 3200, 2800, 3100, 3800, 1300, 1500, 1000, 1100, 1800, 1900, 1100, 1200] }
df = pd.DataFrame(data) print(“原始数据集:”) df
步骤-3:产量标签
# 3. 创建基于产量的 诚恳分类标签(高、中、低) df[' 诚恳类别'] = pd.cut(df['产量'], bins=[0, 1000, 2000, 4000], labels=['低产', '中产', '高产'])
步骤-4:数据预处理
# 4. 数据预处理 X = df[['产量', '面积']] scaler = StandardScaler() X_scaled = scaler.fit_transform(X)
步骤-5:执行K-means聚类
# 5. 执行K-means聚类 (K=3) k = 3 kmeans = KMeans(n_clusters=k, random_state=42) df['Cluster'] = kmeans.fit_predict(X_scaled)
步骤-6:处理标签
# 6. 对齐聚类标签与 诚恳类别( 由于K-means标签是随机的) # 找到聚类中心对应的产量水平 cluster_centers = scaler.inverse_transform(kmeans.cluster_centers_) cluster_rank = np.argsort(cluster_centers[:, 0]) # 按产量排序
# 创建标签映射:将聚类标签映射为低、中、高 label_ p = { 0: '低产', 1: '中产', 2: '高产' }
# 根据产量排序调整映射 for i in range(3): df.loc[df['Cluster'] == cluster_rank[i], '预测类别'] = label_ p[i]
步骤-7:生成混淆矩阵
# 7. 生成混淆矩阵 cm = confusion_ trix(df[' 诚恳类别'], df['预测类别'], labels=['低产', '中产', '高产'])
# 8. 可视化混淆矩阵 plt.figure(figsize=(8, 6)) sns.heat p(cm, annot=True, fmt='d', c p='Blues', xticklabels=['低产', '中产', '高产'], yticklabels=['低产', '中产', '高产']) plt.xlabel('预测类别') plt.ylabel(' 诚恳类别') plt.title('K-means聚类混淆矩阵(基于产量分级)') plt.show()
步骤-9:解读混淆矩阵
# 9. 详细解释混淆矩阵 print(” 混淆矩阵详细解释:”) print(“行表示 诚恳类别(基于产量分级),列表示预测类别(K-means聚类 结局) “)
class_names = ['低产', '中产', '高产'] for i, true_class in enumerate(class_names): for j, pred_class in enumerate(class_names): count = cm[i, j] provinces = df[(df[' 诚恳类别']==true_class) & (df['预测类别']==pred_class)]['省份'].tolist() print(f” 诚恳类别为'{true_class}'被预测为'{pred_class}'的省份有 {count} 个:{provinces}”) correct = cm[i, i] total = sum(cm[i, :]) accuracy = correct / total print(f”'{true_class}'类别的准确率:{accuracy:.2%} “)
结局输出:
混淆矩阵详细解释: 行表示 诚恳类别(基于产量分级),列表示预测类别(K-means聚类 结局) 诚恳类别为'低产'被预测为'低产'的省份有 6 个:['山西', '陕西', '甘肃', '新疆', '贵州', '广西'] 诚恳类别为'低产'被预测为'中产'的省份有 0 个:[] 诚恳类别为'低产'被预测为'高产'的省份有 0 个:[] '低产'类别的准确率:100.00% 诚恳类别为'中产'被预测为'低产'的省份有 2 个:['四川', '云南'] 诚恳类别为'中产'被预测为'中产'的省份有 2 个:['辽宁', '河北'] 诚恳类别为'中产'被预测为'高产'的省份有 0 个:[] '中产'类别的准确率:50.00% 诚恳类别为'高产'被预测为'低产'的省份有 0 个:[] 诚恳类别为'高产'被预测为'中产'的省份有 4 个:['吉林', '内蒙古', '山东', '河南'] 诚恳类别为'高产'被预测为'高产'的省份有 1 个:['黑龙江'] '高产'类别的准确率:20.00%步骤-10:可视化聚类 结局
# 10. 可视化聚类 结局(原代码保持不变) centers = scaler.inverse_transform(kmeans.cluster_centers_) plt.figure(figsize=(10, 6)) sns.scatterplot(data=df, x='产量', y='面积', hue='预测类别', palette='viridis', s=100) plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.5, rker='X', label='聚类中心') for i in range(len(df)): plt.text(df['产量'][i]+50, df['面积'][i]+50, df['省份'][i], fontsize=9) plt.xlabel('玉米产量(万吨)') plt.ylabel('种植面积(千公顷)') plt.title('全国玉米产区K-means聚类分析 (K=3)') plt.legend() plt.grid(True) plt.tight_layout() plt.show()
# 聚类特征分析(原代码保持不变) cluster_sum ry = df.groupby('预测类别').agg({ '产量': ['mean', 'min', ' x'], '面积': ['mean', 'min', ' x'], '省份': 'count' }) print(” 聚类特征分析:”) print(cluster_sum ry)
聚类特征分析: 产量 面积 省份 mean min x mean min x count 预测类别 中产 2233.333333 1500 2900 3266.666667 2500 4200 6 低产 875.000000 600 1300 1362.500000 1000 1900 8 高产 3800.000000 3800 3800 5800.000000 5800 5800 13、K-means主要函数
(1) fit_predict(X) 技巧
''' K-Means聚类算法中的fit_predict 技巧是scikit-learn库提供的一个便捷函数,它结合了fit()和predict()两个步骤的功能。 fit_predict(X) 技巧一次性完成 下面内容两个操作: 【1】拟合模型:根据输入数据X找到聚类中心(类似于fit()) 【2】预测聚类标签:返回每个样本所属的簇索引(类似于predict())
函数原型: fit_predict(X, y=None, sample_weight=None)
X:要聚类的数据,形状通常为(n_samples, n_features)
y:在K-Means中忽略此参数(保持API一致性)
sample_weight:样本权重,可选的数组,形状为(n_samples,)
返回一个形状为(n_samples,)的数组,包含每个样本所属的簇索引(从0开始)。 '''
from sklearn.cluster import KMeans import numpy as np
# 示例数据 X = np.array([[1, 2], [1, 4], [1, 0], [10, 2], [10, 4], [10, 0]])
# 创建KMeans实例并拟合预测 kmeans = KMeans(n_clusters=2, random_state=0) labels = kmeans.fit_predict(X)
print(labels) # 输出可能是: [1 1 1 0 0 0]
(2) inverse_transform 技巧
''' 在scikit-learn的K-Means聚类算法中,inverse_transform 技巧 一个不太常用但有其特定用途的功能。 inverse_transform(X) 技巧的 影响是将数据从聚类空间”转换回”原始特征空间。不过需要注意的是,K-Means的转换本质上是离散的(分配到某个簇), 因此这种”逆转换”有其 独特性。
正向变换:当使用transform(X)时,K-Means计算每个样本到所有聚类中心的距离 逆变换:inverse_transform(X)则是用聚类中心的值来”代表”原始数据
具体来说,对于每个输入样本,该 技巧会: [1] 找到它最接近的聚类中心 [2] 返回该聚类中心的坐标值
inverse_transform(X) 参数和返回值: X:要逆变换的数据,形状通常为(n_samples, n_features)
返回:形状相同的数组,但每个样本被其最近的聚类中心替代
实际用途:
数据压缩:可以用聚类中心代表原始数据,减少数据量
数据平滑:用中心点替代噪声数据
预处理步骤:在某些特征工程流水线中使用 '''
4、完整代码实现
import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import confusion_ trix import tplotlib.pyplot as plt import seaborn as sns import warnings
# 1. 设置中文显示和忽略警告 plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文显示 plt.rcParams['axes.unicode_minus'] = False # 解决负号显示 难题 warnings.filterwarnings('ignore') # 忽略警告
# 2. 定义数据集 data = { '省份': ['黑龙江', '吉林', '辽宁', '内蒙古', '河北', '山东', '河南', '山西', '陕西', '甘肃', '新疆', '四川', '云南', '贵州', '广西'], '产量': [3800, 2800, 1500, 2200, 1800, 2200, 2900, 800, 900, 600, 700, 1200, 1300, 700, 800], '面积': [5800, 4200, 2500, 3200, 2800, 3100, 3800, 1300, 1500, 1000, 1100, 1800, 1900, 1100, 1200] }
df = pd.DataFrame(data) print(“原始数据集:”) print(df)
# 3. 创建基于产量的 诚恳分类标签(高、中、低) df[' 诚恳类别'] = pd.cut(df['产量'], bins=[0, 1000, 2000, 4000], labels=['低产', '中产', '高产'])
# 4. 数据预处理 X = df[['产量', '面积']] scaler = StandardScaler() X_scaled = scaler.fit_transform(X)
# 5. 执行K-means聚类 (K=3) k = 3 kmeans = KMeans(n_clusters=k, random_state=42) df['Cluster'] = kmeans.fit_predict(X_scaled)
# 6. 对齐聚类标签与 诚恳类别( 由于K-means标签是随机的) # 找到聚类中心对应的产量水平 cluster_centers = scaler.inverse_transform(kmeans.cluster_centers_) cluster_rank = np.argsort(cluster_centers[:, 0]) # 按产量排序
# 创建标签映射:将聚类标签映射为低、中、高 label_ p = { 0: '低产', 1: '中产', 2: '高产' }
# 根据产量排序调整映射 for i in range(3): df.loc[df['Cluster'] == cluster_rank[i], '预测类别'] = label_ p[i]
# 7. 生成混淆矩阵 cm = confusion_ trix(df[' 诚恳类别'], df['预测类别'], labels=['低产', '中产', '高产'])
# 8. 可视化混淆矩阵 plt.figure(figsize=(8, 6)) sns.heat p(cm, annot=True, fmt='d', c p='Blues', xticklabels=['低产', '中产', '高产'], yticklabels=['低产', '中产', '高产']) plt.xlabel('预测类别') plt.ylabel(' 诚恳类别') plt.title('K-means聚类混淆矩阵(基于产量分级)') plt.show()
# 9. 详细解释混淆矩阵 print(” 混淆矩阵详细解释:”) print(“行表示 诚恳类别(基于产量分级),列表示预测类别(K-means聚类 结局) “)
class_names = ['低产', '中产', '高产'] for i, true_class in enumerate(class_names): for j, pred_class in enumerate(class_names): count = cm[i, j] provinces = df[(df[' 诚恳类别']==true_class) & (df['预测类别']==pred_class)]['省份'].tolist() print(f” 诚恳类别为'{true_class}'被预测为'{pred_class}'的省份有 {count} 个:{provinces}”) correct = cm[i, i] total = sum(cm[i, :]) accuracy = correct / total print(f”'{true_class}'类别的准确率:{accuracy:.2%} “)
# 10. 可视化聚类 结局(原代码保持不变) centers = scaler.inverse_transform(kmeans.cluster_centers_) plt.figure(figsize=(10, 6)) sns.scatterplot(data=df, x='产量', y='面积', hue='预测类别', palette='viridis', s=100) plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.5, rker='X', label='聚类中心') for i in range(len(df)): plt.text(df['产量'][i]+50, df['面积'][i]+50, df['省份'][i], fontsize=9) plt.xlabel('玉米产量(万吨)') plt.ylabel('种植面积(千公顷)') plt.title('全国玉米产区K-means聚类分析 (K=3)') plt.legend() plt.grid(True) plt.tight_layout() plt.show()
# 聚类特征分析(原代码保持不变) cluster_sum ry = df.groupby('预测类别').agg({ '产量': ['mean', 'min', ' x'], '面积': ['mean', 'min', ' x'], '省份': 'count' }) print(” 聚类特征分析:”) print(cluster_sum ry)
输出 结局:
原始数据集: 省份 产量 面积 0 黑龙江 3800 5800 1 吉林 2800 4200 2 辽宁 1500 2500 3 内蒙古 2200 3200 4 河北 1800 2800 5 山东 2200 3100 6 河南 2900 3800 7 山西 800 1300 8 陕西 900 1500 9 甘肃 600 1000 10 新疆 700 1100 11 四川 1200 1800 12 云南 1300 1900 13 贵州 700 1100 14 广西 800 1200 混淆矩阵详细解释: 行表示 诚恳类别(基于产量分级),列表示预测类别(K-means聚类 结局) 诚恳类别为'低产'被预测为'低产'的省份有 6 个:['山西', '陕西', '甘肃', '新疆', '贵州', '广西'] 诚恳类别为'低产'被预测为'中产'的省份有 0 个:[] 诚恳类别为'低产'被预测为'高产'的省份有 0 个:[] '低产'类别的准确率:100.00% 诚恳类别为'中产'被预测为'低产'的省份有 2 个:['四川', '云南'] 诚恳类别为'中产'被预测为'中产'的省份有 2 个:['辽宁', '河北'] 诚恳类别为'中产'被预测为'高产'的省份有 0 个:[] '中产'类别的准确率:50.00% 诚恳类别为'高产'被预测为'低产'的省份有 0 个:[] 诚恳类别为'高产'被预测为'中产'的省份有 4 个:['吉林', '内蒙古', '山东', '河南'] 诚恳类别为'高产'被预测为'高产'的省份有 1 个:['黑龙江'] '高产'类别的准确率:20.00% 聚类特征分析: 产量 面积 省份 mean min x mean min x count 预测类别 中产 2233.333333 1500 2900 3266.666667 2500 4200 6 低产 875.000000 600 1300 1362.500000 1000 1900 8 高产 3800.000000 3800 3800 5800.000000 5800 5800 1