使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

使用 Scikit-Learn 进行 K-Means 聚类的权威指南

介绍

K均值聚类 是使用最广泛的无监督机器学习算法之一,它根据数据实例之间的相似性形成数据集群。

在本指南中,我们将首先看一个简单的示例,以了解 K-Means 算法的工作原理,然后再使用 Scikit-Learn 实现它。 然后,我们将讨论如何确定 K-Means 中的聚类数 (Ks),并讨论距离度量、方差和 K-Means 的优缺点。

动机

想象一下下面的情况。 有一天,当你在附近走动时,你注意到有 10 家便利店,并开始想知道哪些商店是相似的——彼此靠得更近。 在寻找回答该问题的方法时,您遇到了一种有趣的方法,它根据商店在地图上的坐标将商店分组。

例如,如果一家商店位于西边 5 公里和北边 3 公里处——你会分配 (5, 3) 坐标到它,并在图中表示它。 让我们绘制第一个点以可视化正在发生的事情:

import matplotlib.pyplot as plt

plt.title("Store With Coordinates (5, 3)")
plt.scatter(x=5, y=3)

这只是第一点,因此我们可以了解如何代表一家商店。 假设我们已经收集了 10 个商店的 10 个坐标。 在将它们组织成一个 numpy 数组,我们还可以绘制它们的位置:

import numpy as np

points = np.array([[5, 3], [10, 15], [15, 12], [24, 10], [30, 45], [85, 70], [71, 80], [60, 78], [55, 52],[80, 91]])

xs = points[:,0] 
ys = points[:,1]  

plt.title("10 Stores Coordinates")
plt.scatter(x=xs, y=ys)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

如何手动实现 K-Means 算法

现在我们可以在一张图上查看这 10 家商店,主要问题是找到一种方法可以根据距离将它们分成不同的组吗? 只需快速浏览一下图表,我们可能会注意到 两组店铺 – 一个是左下角的下点,另一个是右上角的点。 也许,我们甚至可以将中间的这两个点区分为一个单独的组——因此创建 三个不同的组.

在本节中,我们将介绍手动聚类点的过程——将它们分成给定数量的组。 这样,我们基本上会仔细检查所有步骤 K-Means 聚类算法. 在本节结束时,您将对 K-Means 聚类期间执行的所有步骤有一个直观和实用的理解。 之后,我们会将其委托给 Scikit-Learn。

确定是否有两组或三组点的最佳方法是什么? 一种简单的方法是简单地选择一组数量——例如,两个——然后尝试根据该选择对点进行分组。

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

假设我们已经决定有 两组 我们的商店(积分)。 现在,我们需要找到一种方法来了解哪些点属于哪个组。 这可以通过选择一个点来表示 组1 和一个代表 组2. 在测量从所有其他点到每个组的距离时,这些点将用作参考。

以这种方式,说点 (5, 3) 最终属于第 1 组,并指出 (79, 60) 到第 2 组。尝试分配新点时 (6, 3) 对于组,我们需要测量它到这两个点的距离。 在要点的情况下 (6, 3) is 接近(5, 3),因此它属于那个点所代表的组—— 组1. 这样,我们可以轻松地将所有点分组到相应的组中。

在此示例中,除了确定组数(集群) – 我们也选择了一些点作为 参考 每组新点的距离。

这是了解我们商店之间的相似之处的总体思路。 让我们把它付诸实践——我们可以先选择两个参考点 随机. 的参考点 组1(5, 3) 和参考点 组2(10, 15). 我们可以选择我们的两个点 numpy 数组由 [0][1] 索引并将它们存储在 g1 (第 1 组)和 g2 (第 2 组)变量:

g1 = points[0]
g2 = points[1]

完成此操作后,我们需要计算所有其他点到这些参考点的距离。 这就提出了一个重要的问题——如何测量那个距离。 我们基本上可以使用任何距离度量,但是,为了本指南的目的,让我们使用欧几里得距离_。

知道欧几里得距离测量基于毕达哥拉斯定理可能很有用:

$$
c^2 = a^2 + b^2
$$

当适应平面中的点时—— (a1, b1)(a2, b2),前面的公式变为:

$$
c^2 = (a2-a1)^2 + (b2-b1)^2
$$

距离将是平方根 c,所以我们也可以将公式写成:

$$
euclidean_{dist} = sqrt[2][(a2 – a1)^2 + (b2 – b1) ^2)]
$$

请注意: 您还可以将欧几里得距离公式推广到多维点。 例如,在三维空间中,点具有三个坐标——我们的公式通过以下方式反映了这一点:
$$
euclidean_{dist} = sqrt[2][(a2 – a1)^2 + (b2 – b1) ^2 + (c2 – c1) ^2)]
$$
无论我们操作的空间有多少维,都遵循同样的原则。

到目前为止,我们已经选择了代表组的点,并且我们知道如何计算距离。 现在,让我们通过将收集到的每个存储点分配给一个组来将距离和组放在一起。

为了更好地形象化,我们将声明三个列表。 第一个存储第一组积分的—— points_in_g1. 第二个存储第 2 组的点数 – points_in_g2,最后一个—— group, 至 标签 点作为要么 1 (属于第 1 组)或 2 (属于第 2 组):

points_in_g1 = []
points_in_g2 = []
group = []

我们现在可以遍历我们的点并计算它们与每个组引用之间的欧几里得距离。 每个点将是 接近 到两个组之一——根据哪个组最接近,我们将每个点分配给相应的列表,同时添加 1 or 2group 列表:

for p in points:
    x1, y1 = p[0], p[1]
    euclidean_distance_g1 = np.sqrt((g1[0] - x1)**2 + (g1[1] - y1)**2)
    euclidean_distance_g2 = np.sqrt((g2[0] - x1)**2 + (g2[1] - y1)**2)
    if euclidean_distance_g1 < euclidean_distance_g2:
        points_in_g1.append(p)
        group.append('1')
    else:
        points_in_g2.append(p)
        group.append('2')

让我们看看这个迭代的结果,看看发生了什么:

print(f'points_in_g1:{points_in_g1}n 
npoints_in_g2:{points_in_g2}n 
ngroup:{group}')

结果是:

points_in_g1:[array([5, 3])]
 
points_in_g2:[array([10, 15]), array([15, 12]), 
              array([24, 10]), array([30, 45]), 
              array([85, 70]), array([71, 80]),
              array([60, 78]), array([55, 52]), 
              array([80, 91])]
 
group:[1, 2, 2, 2, 2, 2, 2, 2, 2, 2] 

我们还可以绘制聚类结果,根据分配的组使用不同的颜色,使用 Seaborn 的 scatterplot()group 作为一个 hue 参数:

import seaborn as sns

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

很明显,只有我们的第一个点被分配到第 1 组,而所有其他点都被分配到第 2 组。这个结果与我们一开始的设想不同。 考虑到我们的结果和我们最初的期望之间的差异——我们有没有办法改变它? 好像有!

一种方法是重复该过程并选择不同的点作为组的参考。 这将改变我们的结果,希望更符合我们一开始的设想。 这第二次,我们不能像以前那样随机选择它们,而是通过获得一个 意味着 我们所有已经分组的点。 这样,这些新点可以位于相应组的中间。

例如,如果第二组只有点 (10, 15), (30, 45)。 新 中央 重点是 (10 + 30)/2(15+45)/2 – 等于 (20, 30).

由于我们已将结果放入列表中,因此我们可以先将它们转换为 numpy 数组,选择它们的xs,ys,然后得到 意味着:

g1_center = [np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()]
g2_center = [np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()]
g1_center, g2_center

建议: 尝试使用 numpy 和 NumPy 数组尽可能多。 它们经过优化以获得更好的性能并简化了许多线性代数运算。 每当你试图解决一些线性代数问题时,你一定要看看 numpy 检查是否有任何文件 numpy 旨在解决您的问题的方法。 机会是有的!

为了帮助使用我们的新中心点重复该过程,让我们将之前的代码转换为一个函数,执行它并查看点的分组方式是否有任何变化:

def assigns_points_to_two_groups(g1_center, g2_center):
    points_in_g1 = []
    points_in_g2 = []
    group = []

    for p in points:
        x1, y1 = p[0], p[1]
        euclidean_distance_g1 = np.sqrt((g1_center[0] - x1)**2 + (g1_center[1] - y1)**2)
        euclidean_distance_g2 = np.sqrt((g2_center[0] - x1)**2 + (g2_center[1] - y1)**2)
        if euclidean_distance_g1 < euclidean_distance_g2:
            points_in_g1.append(p)
            group.append(1)
        else:
            points_in_g2.append(p)
            group.append(2)
    return points_in_g1, points_in_g2, group

请注意: 如果你注意到你一遍又一遍地重复相同的代码,你应该将该代码包装到一个单独的函数中。 将代码组织成函数被认为是一种最佳实践,特别是因为它们有助于测试。 测试和隔离一段代码比没有任何功能的完整代码更容易。

让我们调用函数并将其结果存储在 points_in_g1, points_in_g2group 变量:

points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
points_in_g1, points_in_g2, group

并绘制带有彩色点的散点图以可视化组划分:

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

看来我们点的聚类是 越来越好. 但是,当考虑到它们与两组的接近程度时,图表中间仍有两个点可以分配给任一组。 到目前为止,我们开发的算法将这两个点都分配给了第二组。

这意味着我们可以通过采用 X 和 Y 的方法再次重复该过程,创建两个新的中心点 (质心) 到我们的组并根据距离重新分配它们。

让我们还创建一个函数来更新质心。 现在整个过程可以简化为对该函数的多次调用:

def updates_centroids(points_in_g1, points_in_g2):
    g1_center = np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()
    g2_center = np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()
    return g1_center, g2_center

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

请注意,在第三次迭代之后,每个点现在都属于不同的集群。 结果似乎越来越好——让我们再做一次。 现在去 第四次迭代 我们的方法:

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

这是我们第四次得到 同样的结果 和上一个一样。 所以看起来我们的点不会再改变组了,我们的结果已经达到了某种稳定性——它已经进入了一个不可改变的状态,或者 融合. 除此之外,我们得到的结果与我们对两组的设想完全相同。 我们还可以看看这种达成的划分是否有意义。

让我们快速回顾一下到目前为止我们所做的事情。 我们将我们的 10 家门店在地理上分为两个部分——一个位于西南地区,另一个位于东北部。 除了我们已经拥有的数据之外,收集更多数据可能会很有趣——收入、每日客户数量等等。 这样我们就可以进行更丰富的分析,并可能产生更有趣的结果。

当一个已经建立的品牌想要选择一个区域开设新店时,可以进行这样的聚类研究。 在这种情况下,除了位置之外,还需要考虑更多变量。

这一切与 K-Means 算法有什么关系?

在执行这些步骤时,您可能想知道它们与 K-Means 算法有什么关系。 到目前为止,我们进行的过程是 K-Means 算法. 简而言之,我们已经确定了组/集群的数量,随机选择了初始点,并在每次迭代中更新了质心,直到集群收敛。 我们基本上是手动执行了整个算法——仔细执行每一步。

K 在 K-Means 中来自 簇数 需要在开始迭代过程之前设置。 在我们的例子中 K = 2. 这种特性有时被视为 考虑到还有其他聚类方法,例如层次聚类,不需要事先有固定数量的聚类。

由于使用了均值,K-means 也变成了 对异常值和极值敏感 – 它们增强了可变性,使我们的质心更难发挥作用。 所以,要意识到执行的必要性 极值和异常值分析 在使用 K-Means 算法进行聚类之前。

另外,请注意我们的点被分割成直线部分,创建集群时没有曲线。 这也可能是 K-Means 算法的一个缺点。

请注意: 当您需要它更灵活并适应椭圆和其他形状时,请尝试使用 广义 K 均值高斯混合模型. 该模型可以适应椭圆分割簇。

K-Means 也有很多 优点! 它在 大型数据集 如果您使用某些类型的层次聚类算法,这可能会变得难以处理。 它也是 保证收敛,并且可以很容易地 概括适应. 除此之外,它可能是最常用的聚类算法。

现在我们已经了解了 K-Means 算法中执行的所有步骤,并了解了它的所有优缺点,我们终于可以使用 Scikit-Learn 库来实现 K-Means。

如何使用实现 K-Means 算法 Scikit学习

为了仔细检查我们的结果,让我们再次执行此过程,但现在使用 3 行代码 sklearn:

from sklearn.cluster import KMeans


kmeans = KMeans(n_clusters=2, random_state=42) 
kmeans.fit(points)
kmeans.labels_

在这里,标签与我们之前的组相同。 让我们快速绘制结果:

sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

结果图与上一节中的图相同。

查看我们的 Git 学习实践指南,其中包含最佳实践、行业认可的标准以及随附的备忘单。 停止谷歌搜索 Git 命令,实际上 学习 它!

请注意: 看看我们是如何使用 Scikit-Learn 执行 K-Means 算法的,您可能会觉得这是不费吹灰之力,而且您不必太担心它。 当我们逐步了解 K-Means 算法时,只需 3 行代码即可执行我们在上一节中讨论的所有步骤。 但, 细节决定成败 在这种情况下! 如果您不了解该算法的所有步骤和限制,您很可能会遇到 K-Means 算法给您带来出乎意料的结果的情况。

使用 Scikit-Learn,您还可以通过设置 init='k-means++' 争论。 在更广泛的意义上, K-均值++ 仍然选择 k 初始聚类中心在均匀分布后随机分布。 然后,不是通过仅计算距离度量,而是通过使用概率,从剩余的数据点中选择每个后续的聚类中心。 使用概率可以加快算法速度,并且在处理非常大的数据集时很有帮助。

肘部方法 - 选择最佳组数

到目前为止,一切都很好! 我们根据点和质心之间的欧几里得距离对 10 个商店进行了聚类。 但是图表中间那两个更难聚类的点呢? 他们不能也组成一个单独的小组吗? 我们真的选择错了吗 K = 2 团体? 也许我们实际上有 K = 3 团体? 我们甚至可以拥有三个以上的组而没有意识到这一点。

这里要问的问题是 如何确定 K-Means 中的组数 (K). 为了回答这个问题,我们需要了解对于不同的 K 值是否会有一个“更好”的集群。

发现这一点的简单方法是对具有不同值的点进行聚类 K, 因此对于 K=2、K=3、K=4,以此类推:

for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 

但是,不同的聚类点 Ks将是不够的 了解我们是否选择了理想值 K. 我们需要一种方法来评估每个聚类的质量 K 我们选择了。

手动计算 在聚类平方和 (WCSS) 内

这里是引入衡量我们的聚类点彼此接近程度的理想场所。 它基本上描述了多少 方差 我们有一个单一的集群。 这种措施称为 平方和簇内世界CSS 简而言之。 WCSS 越小,我们的点越接近,因此我们有一个结构更良好的集群。 WCSS 公式可用于任意数量的集群:

$$
WCSS = sum(Pi_1 – Centroid_1)^2 + cdots + sum(Pi_n – Centroid_n)^2
$$

请注意: 在本指南中,我们使用 欧氏距离 来获得质心,但也可以使用其他距离度量,例如曼哈顿。

现在我们可以假设我们选择了两个集群并尝试实现 WCSS 以更好地理解 WCSS 是什么以及如何使用它。 正如公式所述,我们需要总结所有聚类点和质心之间的平方差。 所以,如果我们第一组的第一点是 (5, 3) 我们第一组的最后一个质心(收敛后)是 (16.8, 17.0),WCSS 将是:

$$
WCSS = 总和((5,3) – (16.8, 17.0))^2
$$

$$
WCSS = 总和((5-16.8) + (3-17.0))^2
$$

$$
WCSS = 总和((-11.8) + (-14.0))^2
$$

$$
WCSS = 总和((-25.8))^2
$$

$$
WCSS = 335.24
$$

这个例子说明了我们如何为集群中的一个点计算 WCSS。 但是集群通常包含不止一个点,我们在计算 WCSS 时需要将它们全部考虑在内。 我们将通过定义一个接收点和质心簇并返回平方和的函数来做到这一点:

def sum_of_squares(cluster, centroid):
    squares = []
    for p in cluster:
        squares.append((p - centroid)**2)
        ss = np.array(squares).sum()
    return ss

现在我们可以得到每个集群的平方和:

g1 = sum_of_squares(points_in_g1, g1_center)
g2 = sum_of_squares(points_in_g2, g2_center)

并将结果相加得到总数 世界CSS:

g1 + g2

结果是:

2964.3999999999996

所以,在我们的例子中,当 K 等于 2,总 WCSS 为 2964.39. 现在,我们可以切换 Ks 并计算所有它们的 WCSS。 这样,我们就可以深入了解什么 K 我们应该选择使我们的聚类表现最好。

计算 世界CSS 运用 Scikit学习

幸运的是,我们不需要手动计算每个 WCSS K. 在对给定的簇数进行 K-Means 聚类后,我们可以通过使用 inertia_ 属性。 现在,我们可以回到我们的 K-Means for 循环,用它来切换簇的数量,并列出相应的 WCSS 值:

wcss = [] 
for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 
    wcss.append(kmeans.inertia_)
wcss

请注意,列表中的第二个值与我们之前计算的完全相同 K = 2:

[18272.9, # For k=1 
 2964.3999999999996, # For k=2
 1198.75, # For k=3
 861.75,
 570.5,
 337.5,
 175.83333333333334,
 79.5,
 17.0,
 0.0]

为了可视化这些结果,让我们绘制我们的 Ks 连同 WCSS 值:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

当情节中断时 x = 2,线中的一个低点,当 x = 3. 请注意,它提醒我们 肘部的形状. 通过将 Ks 与 WCSS 一起绘制,我们使用 肘法 选择 Ks 的数量。 和 选择的 K 正好是最低肘点,所以,这将是 3 而不是 2,在我们的例子中:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss);
plt.axvline(3, linestyle='--', color='r')

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

我们可以再次运行 K-Means 聚类算法,看看我们的数据会是什么样子 三个集群:

kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(points)
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

我们已经对两个集群感到满意,但是根据肘部方法,三个集群将更适合我们的数据。 在这种情况下,我们将拥有三种商店而不是两种。 在使用肘法之前,我们想到了西南和东北的商店集群,现在我们在中心也有商店。 也许这可能是开另一家商店的好地方,因为附近的竞争会更少。

替代集群质量措施

在评估集群质量时,还可以使用其他措施:

  • 剪影分数 – 不仅分析集群内点之间的距离,还分析集群本身之间的距离
  • 簇之间的平方和 (BCSS) – 与 WCSS 互补的指标
  • 平方和误差 (上交所)
  • 最大半径 – 测量点到其质心的最大距离
  • 平均半径 – 从一个点到其质心的最大距离之和除以聚类数。

建议尝试并了解它们中的每一个,因为根据问题,一些替代方案可能比最广泛使用的指标更适用 (WCSS 和剪影分数).

最后,与许多数据科学算法一样,我们希望减少每个集群内部的方差并最大化不同集群之间的方差。 所以我们有更多定义和可分离的集群。

在另一个数据集上应用 K-Means

让我们使用我们在另一个数据集上学到的知识。 这一次,我们将尝试寻找相似的葡萄酒组。

请注意: 您可以下载数据集 相关信息.

我们从导入开始 pandas 读取 wine-clustering CSV (逗号分隔值) 文件成一个 Dataframe 结构体:

import pandas as pd

df = pd.read_csv('wine-clustering.csv')

加载后,我们来看看前五条数据记录 head() 方法:

df.head()

结果是:

	Alcohol 	Malic_Acid 	Ash 	Ash_Alcanity 	Magnesium 	Total_Phenols 	Flavanoids 	Nonflavanoid_Phenols 	Proanthocyanins 	Color_Intensity 	Hue 	OD280 	Proline
0 	14.23 		1.71 		2.43 	15.6 			127 		2.80 			3.06 		0.28 					2.29 				5.64 				1.04 	3.92 	1065
1 	13.20 		1.78 		2.14 	11.2 			100 		2.65 			2.76 		0.26 					1.28 				4.38 				1.05 	3.40 	1050
2 	13.16 		2.36 		2.67 	18.6 			101 		2.80 			3.24 		0.30 					2.81 				5.68 				1.03 	3.17 	1185
3 	14.37 		1.95 		2.50 	16.8 			113 		3.85 			3.49 		0.24 					2.18 				7.80 				0.86 	3.45 	1480
4 	13.24 		2.59 		2.87 	21.0 			118 		2.80 			2.69 		0.39 					1.82 				4.32 				1.04 	2.93 	735

我们对葡萄酒中存在的物质进行了许多测量。 在这里,我们也不需要转换分类列,因为它们都是数字的。 现在,让我们看一下描述性统计数据 describe() 方法:

df.describe().T 

描述表:

 						count 	mean 		std 		min 	25% 	50% 	75% 		max
Alcohol 				178.0 	13.000618 	0.811827 	11.03 	12.3625 13.050 	13.6775 	14.83
Malic_Acid 				178.0 	2.336348 	1.117146 	0.74 	1.6025 	1.865 	3.0825 		5.80
Ash 					178.0 	2.366517 	0.274344 	1.36 	2.2100 	2.360 	2.5575 		3.23
Ash_Alcanity 			178.0 	19.494944 	3.339564 	10.60 	17.2000 19.500 	21.5000 	30.00
Magnesium 				178.0 	99.741573 	14.282484 	70.00 	88.0000 98.000 	107.0000 	162.00
Total_Phenols 			178.0 	2.295112 	0.625851 	0.98 	1.7425 	2.355 	2.8000 		3.88
Flavanoids 				178.0 	2.029270 	0.998859 	0.34 	1.2050 	2.135 	2.8750 		5.08
Nonflavanoid_Phenols 	178.0 	0.361854 	0.124453 	0.13 	0.2700 	0.340 	0.4375 		0.66
Proanthocyanins 		178.0 	1.590899 	0.572359 	0.41 	1.2500 	1.555 	1.9500 		3.58
Color_Intensity 		178.0 	5.058090 	2.318286 	1.28 	3.2200 	4.690 	6.2000 		13.00
Hue 					178.0 	0.957449 	0.228572 	0.48 	0.7825 	0.965 	1.1200 		1.71
OD280 					178.0 	2.611685 	0.709990 	1.27 	1.9375 	2.780 	3.1700 		4.00
Proline 				178.0 	746.893258 	314.907474 	278.00 	500.500 673.500 985.0000 	1680.00

通过查看表格,很明显有一些 数据的可变性 – 对于某些列,例如 Alchool 还有更多,对于其他人,例如 Malic_Acid, 较少的。 现在我们可以检查是否有 nullNaN 我们数据集中的值:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 13 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Alcohol               178 non-null    float64
 1   Malic_Acid            178 non-null    float64
 2   Ash                   178 non-null    float64
 3   Ash_Alcanity          178 non-null    float64
 4   Magnesium             178 non-null    int64  
 5   Total_Phenols         178 non-null    float64
 6   Flavanoids            178 non-null    float64
 7   Nonflavanoid_Phenols  178 non-null    float64
 8   Proanthocyanins       178 non-null    float64
 9   Color_Intensity       178 non-null    float64
 10  Hue                   178 non-null    float64
 11  OD280                 178 non-null    float64
 12  Proline               178 non-null    int64  
dtypes: float64(11), int64(2)
memory usage: 18.2 KB

考虑到数据集中没有空值,无需删除或输入数据。 我们可以使用 Seaborn pairplot() 查看数据分布并检查数据集是否形成对聚类感兴趣的列对:

sns.pairplot(df)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

通过查看配对图,两列似乎很有希望用于聚类目的—— AlcoholOD280 (这是一种确定葡萄酒中蛋白质浓度的方法)。 似乎在将其中两个组合在一起的地块上有 3 个不同的集群。

还有其他列似乎也相关。 最为显着地 AlcoholTotal_PhenolsAlcoholFlavanoids. 它们具有很好的线性关系,可以在配对图中观察到。

由于我们的重点是使用 K-Means 进行聚类,所以让我们选择一对列,比如说 AlcoholOD280,并测试此数据集的肘部方法。

请注意: 当使用数据集的更多列时,将需要绘制 3 维或将数据减少到 主要成分(使用 PCA). 这是一种有效且更常见的方法,只需确保根据它们解释的程度来选择主成分,并记住,在减少数据维度时,会丢失一些信息——因此该图是 近似 真实数据,而不是真实数据。

让我们绘制散点图,将这两列设置为其轴,以仔细查看我们想要分组的点:

sns.scatterplot(data=df, x='OD280', y='Alcohol')

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

现在我们可以定义我们的列并使用肘法来确定集群的数量。 我们还将启动算法 kmeans++ 只是为了确保它更快地收敛:

values = df[['OD280', 'Alcohol']]

wcss_wine = [] 
for i in range(1, 11): 
    kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
    kmeans.fit(values) 
    wcss_wine.append(kmeans.inertia_)

我们已经计算了 WCSS,因此我们可以绘制结果:

clusters_wine = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(clusters_wine, wcss_wine)
plt.axvline(3, linestyle='--', color='r')

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

根据肘部方法,我们这里应该有 3 个集群。 对于最后一步,让我们将我们的点分成 3 个集群并绘制用颜色标识的那些集群:

kmeans_wine = KMeans(n_clusters=3, random_state=42)
kmeans_wine.fit(values)
sns.scatterplot(x = values['OD280'], y = values['Alcohol'], hue=kmeans_wine.labels_)

使用 Scikit-Learn PlatoBlockchain 数据智能进行 K-Means 聚类的权威指南。 垂直搜索。 哎。

我们可以看到集群 0, 12 在图中。 根据我们的分析, 组0 拥有蛋白质含量更高、酒精度更低的葡萄酒, 组1 拥有酒精含量较高且蛋白质含量较低的葡萄酒,以及 组2 它的葡萄酒中同时含有高蛋白和高酒精。

这是一个非常有趣的数据集,我鼓励您通过在归一化和 PCA 之后对数据进行聚类来进一步进行分析——也可以通过解释结果并找到新的联系。

结论

K均值 聚类是一种简单但非常有效的无监督机器学习算法,用于数据聚类。 它根据数据点之间的欧几里得距离对数据进行聚类。 K-Means 聚类算法在对文本文档、图像、视频等进行分组方面有很多用途。

时间戳记:

更多来自 堆栈滥用