Chrome 上的 GitHub 面向专业人士的 Git 设置!
Github 的 5 个 Chrome 扩展可以提高您的工作效率!
图片通过 Pixabay
对于那些尚未探索 Chrome 扩展(根据 Chrome 网上商店)的人来说,如今有大量的扩展可以添加——每一个都旨在增强界面、进步的潜力(即生产力),以及各种意图的可用功能。最近,我正在建立一个系统,作为我研究的一部分——应用机器学习,通常以图像作为输入/输出信号。因此,让我分享一下我觉得有用的 Chrome 专用设置。换句话说,让我分享一下我在准备 SW 开发和使用 Git、Github 和 Google 的 Chrome 的版本控制源代码时设置浏览器的方式。
不管您的具体关注点是什么,以下扩展都与任何使用 Github 的人相关。现在,除了本地设置之外,对于 mac 用户来说,可以通过关注我以前的媒体博客像专业人士一样进行 git 设置,我们可以通过添加基于 Github 的扩展来扩展我们的功能。
其余部分的组织如下。前面的五个子部分涵盖了五个扩展(即每个部分一个)。注意,顺序是不明确的(即前者不一定比后者评级高,反之亦然)。接下来,我们得出结论,其中包括一个列表,列出了所有相关项目的荣誉提名和参考文献。这里列出了包括的扩展:
- 增强型 Github
- Github 代码折叠
- Github 黑暗主题
- 精制 Github
- 八叉树
每个扩展的呈现是相同的:子部分以 Chrome 网络商店中列出的扩展的名称、URL、视图(即,预告图像)开始。此外,还显示了描述每个扩展在使用时的截图——通常快照跨越了前的和后的视图。
当然,首先必须安装基于 Chromium 的浏览器。几个选项是谷歌的 Chrome 、 Mozilla Firefox 和微软 Edge (2020 年或更晚)——这些,以及其他几个基于 Chrome 的浏览器,允许安装 Chrome 扩展。
注意,对于谷歌以外的浏览器,允许安装 Chrome 扩展的选项必须是设置中上的*(例如,这里是 Edge [ link ]的步骤)。*
增强型 Github
chrome://extensions/?id = anlikcnbgdeidpacdbdljnabclhahhmd
**图 1。预告图像。**增强版 Github,如 Chrome 网上商店所见。
如预告图(图 1)中所述,列出了每个文件的文件大小,并允许从文件查看器下载单个文件(即,通常必须打开单个文件才能下载专有内容)。尽管可能很简单,但这个扩展经常会派上用场。图 2 和图 3 分别示出了前视图和后视图。
图二。在增强 Github 之前。 注意视图是默认的 Github 界面。
图 3。激活后增强 Github。 红色边界框显示差异(即图 2)。注意文件大小,以及下载单个文件的图标(绿色边框)。
Github 代码折叠
chrome://extensions/?id = lefcpjbffalgdcdgidjnmabfenecjdf
图 4。预告图像。 Github 代码折叠,在 Chrome 网上商店看到的。
顾名思义(图 4),这个扩展支持直接在浏览器中进行代码折叠!图 5 中描绘的是与 Python 源代码一起激活和使用的扩展。然而,该工具是复杂的,因为它根据软件语言自动适应(即,自动设置),用于通用样式指南和文档语法(例如, docstring , Pep 8 , Doxygen )。
**图 5。通过 Chrome 扩展进行代码折叠。**注意代码折叠设置为 on(顶部)的函数定义的放大视图。此外,靠近底部折叠的代码显示了条件体也可以是可折叠的。切换按钮是箭头形状的,可以在左边看到(即,通过行号)。
Github 黑暗主题
chrome://extensions/?id = odkdlljoangmamjilkamahebpkpgpeacp
图 8。预告图像。 Github 黑暗主题,如 Chrome 网上商店所见。
简而言之,通过使背景颜色变暗来减轻视图——将 Github 的主题设置为暗色(图 8 和图 9)。
图 9。Github 黑暗主题扩展。 Github 的外观和感觉现在是黑暗模式——一种许多人更喜欢的模式。
精制 GitHub
chrome://extensions/?id = hlepfoohegkhhmjioechaddaejaokhf
**图 8。预告图像。**精制的 GitHub,如 Chrome 网上商店所见。
这个扩展带来了一系列功能增强(图 8)!项目报告(链接)中包含的自述文件中有一个详尽的列表,该列表列出了功能的目标级别(即,存储库、文件管理、基于代码、评论(管理和审阅)、对话、PR 和提交(查看和编辑)、配置文件、新闻订阅等)。此外,还允许定制(例如,基于 Javascript 的定制 CSS)。图 9 是示出所包括的几个特征的多个视图的 GIF 图像。尽管如此,还是有将近一百个特性。此外,该扩展集成的简单性使其成为一个重要的工具(即,没有学习曲线,如果不喜欢某个特性,就不要使用它,因为该扩展对界面的整体外观影响很小)。
图 9。插图显示了作为改进的 Github 扩展的一部分的特性。Github 的外观和感觉现在是黑暗模式——一种许多人更喜欢的模式。(图片来自项目的 Github,https://github.com/sindresorhus/refined-github)。)
八叉树
chrome://extensions/?id = bkhaagjahfmjljalopjnoealnfndnagc
图 10。预告图像。 Octotree,见于 Chrome 网上商店。
Octotree(图 10)是通过 GitHub 浏览项目时增强文件可访问性的一种简单方法。正如许多人可能同意的那样,传统的文件查看器对于观察项目的整体结构或快速打开嵌套在本地目录中的文件是最佳的(图 11)。
**图 11。八棵树的景色。**该扩展允许快速浏览文件。
图 12 示出了增强型观察器的剪辑。
**图 12。八叉树的增强视图。**可以快速查看和打开文件。
结论
因此,它总结了五个对 GitHub 有用的 Chrome 扩展。新的扩展会定期出现;仅 GitHub 就有几十个扩展可以通过 Chrome 网上商店下载。除此之外,还有许多扩展 to 和 themes 来增强最流行的网站(例如 Medium Code Highlighter ,这对于我过去的许多帖子来说是必不可少的)。如果你还没有去过的话,肯定值得去逛逛这家商店!
最后,这里是荣誉提名和相关参考。
荣誉提名
以下是其他基于 Github 的扩展,可能会有用。
- Git 历史浏览器扩展
- GitHub 的头像
- Git Cheatsheet
- GitHub 等距投稿
- GitHub Hovercard
- GitHub 强大的自动完成功能
- GitHub 存储库大小
- ZenHub for GitHub
- 还有更多
如果你有最喜欢的扩展,不管是不是这个博客的一部分,请在下面评论中分享。
相关参考文献
像现在的大多数话题一样,网上有大量的资源,大体上涵盖了 Chrome 扩展。这里有一些精选的。
- Alexander Isora 为极客设计的 14 款热铬扩展🦄
- 25 个扩展、应用程序、&让您的工作效率提高两倍,作者 Brian Tan
- 杰克·普林斯在 20 分钟内创建并发布 Chrome 扩展
- 想要 GitHub 通知。所以我做了一个 Chrome 扩展,作者是 Stacy Goh
- 同样,还有更多!
评论是其他读者和我最喜欢的资源!
这篇文章是我的非正式博客系列Git Like Pro、*、*的第二篇。另一篇涵盖了在 Mac 计算机上正确设置 Git 的步骤!检查一下, Git 像专业人士一样设置!
现在,我不知道你,但我准备写一些代码!😃 😃 😃
k-意味着比 Scikit-learn 的 25 行代码快 8 倍,错误低 27 倍
脸书·费斯图书馆又罢工了
k-均值迭代(来源)
介绍
在我上一篇关于 faiss 库的文章中,我用 20 行代码展示了如何使用脸书的 faiss 库让 kNN 比 Scikit-learn 快 300 倍。但是我们可以用它做更多的事情,包括更快更准确的 K-Means 聚类,只用了 25 行代码!
K-Means 是一种迭代算法,它将数据点聚类成 k 个聚类,每个聚类用一个均值/中心点(质心)表示。训练从一些最初的猜测开始,然后在两个步骤之间交替:分配和更新。
在分配阶段,我们将每个点分配给最近的聚类(使用点和质心之间的欧几里德距离),在更新步骤中,我们重新计算每个质心,从当前步骤中分配给该聚类的所有点计算平均点。
聚类的最终质量被计算为聚类内距离的总和,其中对于每个聚类,我们计算该聚类中的点与其质心之间的欧几里德距离的总和。这也叫惯性。
对于预测,我们在新点和质心之间执行 1 最近邻搜索(k=1 的 kNN)。
Scikit-learn vs faiss
在这两个库中,我们必须指定算法超参数:聚类数、重启次数(每次都从其他初始猜测开始)和最大迭代次数。
正如我们从例子中看到的,算法的核心是搜索最近的邻居,特别是最近的质心,用于训练和预测。这就是 faiss 比 Scikit 快几个数量级的地方——学习!它利用了优秀的 C++实现、尽可能的并发性,甚至 GPU,如果你愿意的话。
用 faiss 实现 K-Means 聚类
下面的 Github 要点也可以在我的定期 Github(链接)上找到。
faiss 的一个很大的特点是它既有安装和构建说明(安装文档),又有一个优秀的文档和示例(入门文档)。安装完成后,我们可以编写实际的集群。代码非常简单,因为我们只是模仿了 Scikit-learn API。
重要元素:
- faiss 专门为这个任务内置了
Kmeans
类,但是它的参数名称与 Scikit-learn 中的不同(参见文档 - 我们必须确保使用
np.float32
类型,因为 faiss 只使用这种类型 kmeans.obj
通过训练返回错误列表,为了得到像 Scikit-learn 中那样的最终错误,我们使用[-1]
索引- 使用
Index
数据结构进行预测,这是 faiss 的基本构建块,用于所有最近邻搜索 - 在预测中,我们使用 k = 1 执行 kNN 搜索,从
self.cluster_centers_
返回最近质心的索引(索引[1]
,因为index.search()
返回距离和索引)
时间和准确度比较
我选择了 Scikit-learn 中的一些流行数据集进行比较。比较列车时刻和预测时刻。为了便于阅读,我明确地写了基于 faiss 的集群比 Scikit-learn 的集群快多少倍。为了进行误差比较,我刚刚写了基于 faiss 的聚类实现了多少倍的低误差(因为数字很大并且不太能提供信息)。
所有这些时间都是用time.process_time()
函数测量的,该函数测量进程时间而不是挂钟时间,以获得更准确的结果。结果是 100 次运行的平均值,除了 MNIST,在那里 Scikit-learn 花费了太长时间,我不得不运行 5 次。
火车时间(图片由作者提供)
预测时间(图片由作者提供)
训练错误(图片由作者提供)
正如我们所看到的,对于小数据集(前 4 个数据集)的 K-Means 聚类,基于 faiss 的版本对于训练来说更慢,并且具有更大的误差。对于预测来说,它的工作速度普遍更快。
对于更大的 MNIST 数据集,faiss 显然是赢家。训练速度提高 20.5 倍是巨大的,特别是因为它将时间从几乎 3 分钟减少到不到 8 秒钟!1.5 倍的预测速度也不错。然而,真正的成就是误差降低了惊人的 27.5 倍。这意味着对于更大的真实世界数据集,基于 faiss 的版本要精确得多。而这只需要 25 行代码!
因此,基于这一点:如果你有大型(至少几千个样本)真实世界数据集,基于 faiss 的版本显然更好。对于小型玩具数据集,Scikit-learn 是更好的选择;然而,如果你有一个 GPU,GPU 加速的 faiss 版本可能会更快(我没有检查它以进行公平的 CPU 比较)。
摘要
通过 25 行代码,我们可以利用 faiss 库为合理规模的数据集进行 K-Means 聚类,从而获得巨大的速度和准确性提升。如果你需要,你可以通过 GPU、多个 GPU 等获得更好的性能,这在 faiss 文档中有很好的解释。
K-means 和 PCA 在图像聚类中的可视化分析
我们可以使用 K-means 和主成分分析(PCA)对时尚 MNIST 数据集上的图像进行聚类。我们还将使用 matplotlib 和 plotly 对结果进行可视化分析。
时尚 MNIST 数据集。图片来自 researchgate.net
我们在这里要做的是在 f-MNIST 数据上训练一个 K-means 聚类模型,以便它能够相对准确地对数据集的图像进行聚类,并且这些聚类具有一些我们可以理解和解释的逻辑。然后,我们将参考实际标签(y)使用 matplotlib 和 plotly 直观地分析聚类的结果,并得出关于 k-means 聚类如何在图像数据集上执行的粗略结论。最后的代码可以在最后的链接中找到。
在本文中,功能和组件可互换使用。
介绍
聚类是一种无监督的机器学习算法,它识别没有特定标签的模式,并根据特征对数据进行聚类。在我们的例子中,我们将看到一个聚类算法(k-means)是否可以在没有标签(y)的情况下在 f-MNIST 中找到不同服装图像之间的模式。
说明 K-means 如何工作的 gif。每个红点是一个质心,每种不同的颜色代表一个不同的集群。每一帧都是质心被重新定位的迭代。(来源: gyfcat )
K-means 聚类的工作原理是根据给定的聚类数分配多个质心。每个数据点被分配给质心最接近它的聚类。该算法旨在最小化观测值与其所属聚类质心之间的平方欧氏距离。
主成分分析或 PCA 是一种减少给定数据集的维度,同时仍然保留其大部分方差的方法。维基百科将其定义为,“ PCA 被定义为一种正交线性变换,它将数据变换到一个新的坐标系,使得数据的一些标量投影的最大方差位于第一个坐标上(称为第一主分量),第二个最大方差位于第二个坐标上,以此类推。”
PCA 可视化。最好的 PC(黑色移动线)是那些红线的总长度最小的时候。它将被用来代替水平和垂直分量(来源: giphy
基本上,PCA 降低了数据集的维度,同时保留了大部分信息。例如,如果一个数据集有 500 个特征,根据保留的特定方差量,它会减少到 200 个特征。保留的方差越大,保存的信息就越多,但是得到的维数也就越多。
维度越少,训练和测试模型的时间就越少。在某些情况下,使用数据集和 PCA 的模型比原始数据集表现更好。PCA 的概念以及它通过改变保留方差而在图像上引起的变化在这里处得到了很好的展示。
这个计划
因此,计划是在数据集上执行 k-means,但只是在对其应用 PCA 之后。
- 从 keras 加载数据集
- 预处理数据,展平数据(从 60000 x 28 x 28 数组到 60000 x 784 数组)
- 对其应用 PCA 以减少维度(使用 0.98 方差从 784 到 420)
- 在 PC 数据集上应用 K 均值聚类(10 个聚类)
- 使用 matplotlib 和 plotly 观察和分析结果
数据集
与 MNIST 数字数据集相比,f-MNIST 数据集是一个稍微高级的数据集,它由不同种类服装的 28 x 28 像素图像组成,数字代表以下服装类型。
#Loading required libraries **import keras
from keras.datasets import fashion_mnist
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans** **#Loading the dataset
(X_train,y_train), (X_test,y_test) = fashion_mnist.load_data()**
时尚 MNIST 数据集
每张图片都是 28×28 像素,上面有各种各样的衣服、鞋子和包包
数据预处理
我们通过将特征展平成一维来将数据从 3D 阵列重新成形为 2D 阵列。28×28 阵列的每个图像现在是 784 个特征的单个阵列。所以我们的数据集从之前的 60000,28,28 变成了 60000,784 数组。
#Reshaping X to a 2D array for PCA and then k-means
**X = X_train.reshape(-1,X_train.shape[1]*X_train.shape[2])** #We will only be using X for clustering. No need of y.**print ("The shape of X is " + str(X.shape))
print ("The shape of y is " + str(y.shape))** #We will be using y only to check our clustering **Output:**
The shape of X is (60000, 784)
The shape of y is (60000,)
主成分分析
我们现在将在数据集上使用 PCA 来降低维数。我们将选择保留方差 0.98(通过反复试验选择的值),并将其用于我们的数据集。
**from sklearn.decomposition import PCA**
# Make an instance of the Model**variance = 0.98** #The higher the explained variance the more accurate the model will remain, but more dimensions will be present**pca = PCA(variance)**
**pca.fit(Clus_dataSet)** #fit the data according to our PCA instance**print("Number of components before PCA = " + str(X.shape[1]))
print("Number of components after PCA 0.98 = " + str(pca.n_components_))**
#dimension reduced from 784**Output:**
Number of components before PCA = 784
Number of components after PCA 0.98 = 420
我们现在根据 PCA 实例转换数据
**Clus_dataSet = pca.transform(Clus_dataSet)****print(“Dimension of our data after PCA = “ + str(Clus_dataSet.shape))****Output:**
Dimension of our data after PCA = (60000, 420)
我们还可以对数据进行逆变换,以查看数据因 PCA 而发生的变化。
**approximation = pca.inverse_transform(Clus_dataSet)**#image reconstruction using the less dimensioned data
**plt.figure(figsize=(8,4));**n = 500 #index value, change to view different data# Original Image
**plt.subplot(1, 2, 1);
plt.imshow(X[n].reshape(X_train.shape[1], X_train.shape[2]),
cmap = plt.cm.gray,);
plt.xlabel(str(X.shape[1])+’ components’, fontsize = 14)
plt.title(‘Original Image’, fontsize = 20);**# 196 principal components
**plt.subplot(1, 2, 2);
plt.imshow(approximation[n].reshape(X_train.shape[1], X_train.shape[2]),
cmap = plt.cm.gray,);
plt.xlabel(str(Clus_dataSet.shape[1]) +’ components’, fontsize = 14)
plt.title(str(variance * 100) + ‘% of Variance Retained’, fontsize = 20);**
左边的数据是原始数据(784 个分量),右边的数据是从 PCA 逆变换而来的(420 个分量)。两者都有 28 x 28 的尺寸。
k 均值聚类
构建 k 均值模型时,我们需要以下参数的值。
init :质心的初始化方法。值将为:“k-means++”。k-means++以一种智能的方式为 k-mean 聚类选择初始聚类中心,以加速收敛。
n_clusters :要形成的簇的数量以及要生成的质心的数量。值将是:10(根据索引,我们有 10 个类,可能不是最好的,但对我们的上下文足够好)
n_init :使用不同质心种子运行 k-means 算法的次数。就惯性而言,最终结果将是 n_init 次连续运行的最佳输出。基于我们的惯性结果,值将是:35(可能不是最好的,但对我们的环境来说足够好了)
现在我们有了自己的模型,并使它适合我们的数据集。首先尝试使用提到的参数来检查本文的结果。您可以稍后更改它们,并看到不同的结果。
**k_means = KMeans(init = “k-means++”, n_clusters = 10, n_init = 35)
k_means.fit(Clus_dataSet)**
现在,该模型已经适合我们的图像数据集,我们已经执行了主成分分析。数据现在被分成 10 个簇。现在,我们必须检查哪种类型的图像出现在每个集群中,并查看是否有任何模式。请记住,分布是相似的,但是在执行此操作时,集群的数量(标签)可能会有所不同。
可视化和分析
拟合之后,我们使用下面的代码来可视化我们的集群。
**G = len(np.unique(k_means_labels))** #Number of labels#2D matrix for an array of indexes of the given label
**cluster_index= [[] for i in range(G)]
for i, label in enumerate(k_means_labels,0):
for n in range(G):
if label == n:
cluster_index[n].append(i)
else:
continue**#Visualisation for clusters = clust**plt.figure(figsize=(20,20));
clust = 3 #**enter label number to visualise **num = 100** #num of data to visualize from the cluster **for i in range(1,num):
plt.subplot(10, 10, i);** #(Number of rows, Number of column per row, item number) **plt.imshow(X[cluster_index[clust][i+500]].reshape(X_train.shape[1], X_train.shape[2]), cmap = plt.cm.binary);
plt.show()**
正如你在下面看到的,这个特殊的集群(在我的例子中是 3 个)在集群踝靴方面做得很好。
第三组似乎有短靴(略短)、运动鞋和一些凉鞋
下面的条形图可视化代码可以在最后的链接中找到。这使用来自数据集的 y_train 的类别标签,并检查给定聚类中某个类别的数量。该图将是相同的(如果您使用相同的参数),而当您执行它时,集群的数量(标签)可能会有所不同。例如,在我的示例中,标记为 0 的聚类似乎是凉鞋聚类,而在你的示例中,该聚类可能标记为 4。
注:簇名为条形图上方***。***
簇 0~ 3 的条形图
集群 0 好像以凉鞋居多。
集群 1 看似随机但大多只有上身衣服。 (T 恤、套头衫、连衣裙、外套和衬衫)
集群 2 也有上身衣服但是种类较少。(套头衫、衬衫和外套)**
集群 3 似乎大多是短靴,很少有运动鞋和凉鞋。基本上都是鞋子。
簇 4 ~ 7 的条形图。集群 6 和 7 似乎都有包。
同样,我们可以观察到星团 4 ~7。在群集 6 和 7(在我的情况下)中,似乎有大多数的包。但是在使用上述集群的可视化(如下所示)时,我们看到了一个合理的模式。一个集群的提手被提起(以及其他),另一个没有。
第六组似乎有提手的袋子。
第 7 组似乎有把手朝下的包。
看起来有鞋子的分类 8 和分类 9 的条形图。
下面显示的群集 8 和 9 似乎是鞋。聚类 8 有一些凉鞋,大部分是运动鞋,聚类 9 似乎有一些凉鞋,大部分是短靴。
第八组好像有运动鞋和凉鞋。两个都是鞋。
集群 9 似乎主要是踝靴和几双凉鞋。两个都是鞋。
集群的 3D 可视化
我们将使用 plotly 在 3D 中可视化星团。 Plotly 是 python 的高级可视化库。使用以下代码获得聚类数据的 3D 散点图。我们将仅使用数据集中 420 个要素中的 3 个要素。这种可视化有助于了解集群的形成情况,以及单个集群扩散到其他集群的程度。
#install these if you haven’t
**!pip install chart_studio
!pip install plotly****import plotly as py
import plotly.graph_objs as go
import plotly.express as px**#3D Plotly Visualization of Clusters using go**layout = go.Layout(
title='<b>Cluster Visualisation</b>',
yaxis=dict(
title='<i>Y</i>'
),
xaxis=dict(
title='<i>X</i>'
)
)****colors = ['red','green' ,'blue','purple','magenta','yellow','cyan','maroon','teal','black']
trace = [ go.Scatter3d() for _ in range(11)]
for i in range(0,10):
my_members = (k_means_labels == i)
index = [h for h, g in enumerate(my_members) if g]
trace[i] = go.Scatter3d(
x=Clus_dataSet[my_members, 0],**# 0 is a component among the 420 components. Feel free to change it **y=Clus_dataSet[my_members, 1],**# 1 is a component among the 420 components. Feel free to change it **z=Clus_dataSet[my_members, 2],**# 2 is a component among the 420 components. Feel free to change it **mode='markers',
marker = dict(size = 2,color = colors[i]),
hovertext=index,
name='Cluster'+str(i),
)****fig = go.Figure(data=[trace[0],trace[1],trace[2],trace[3],trace[4],trace[5],trace[6],trace[7],trace[8],trace[9]], layout=layout)
py.offline.iplot(fig)**
输出:
使用 PCA 对 k 均值聚类的 f-MNIST 数据集进行 3D plotly 散点图可视化。每种颜色代表一个不同的集群。
由于数据集(具有 PCA)实际上具有 420 个维度,因此该可视化仅在散点图中显示了这些特征中的 3 个。要绘制的组件可以在代码中更改,以了解不同组件的情况。
(可进行进一步的主成分分析,将所有 784 个分量减少到 3 个分量,以在 3D 图中完全表示,但这样做会丢失大量信息)
结论
**聚类似乎将相似的项目分组在一起。一个集群或者包含上身衣服 (T 恤/上衣、套衫、连衣裙、外套、衬衫)或者鞋子(凉鞋/运动鞋/短靴)或者包。然而,该聚类在裤子上表现不佳,并且似乎将其与连衣裙归为一组。
一群穿着裤子和裙子的人
前述集群中的服装和裤子的数据可视化
但它很好地区分了这两种包。这种模式可以由我们来解释。一组是提手凸起的包,另一组是提手未凸起的包。
两个集群都有包。但是该算法能够区分手柄被提起和未被提起
类似地,在下面显示的两个集群中,两个集群都以短靴为主。但是短靴看起来大小不一,小一点的看起来和同一组的运动鞋很相似。
两个集群都有最大的踝靴。左边的比右边的短
观察上面的结果,我们可以看到 k -means 算法基于一个合理的模式来区分它的聚类。因此,我们可以得出一个粗略的结论,K-means 聚类方法在进行主成分分析后可以得到一个不错的分类结果。
参考文献
[1] A. Ng,斯坦福大学的机器学习。(未注明)。从 https://www.coursera.org/learn/machine-learning取回
[2] S Joel Franklin , K-Means 聚类用于图像分类 (2020),中
[3] 迈克尔·加拉内克, PCA + Logistic 回归(MNIST)(2018)github
k-均值聚类算法
在 k-means 的引擎盖下,以便一个 7 年级学生能够理解
我选择为这个项目实现的算法是 K 均值聚类。生成的数据试图根据每个点离拟定水井的距离来模拟配水场景。本质上,该算法对于客户细分场景是理想的,这种场景基于客户的位置和井的数量将客户聚集在特定的水井周围。
在这个假想的场景中,几个地方自治市多年来一直在与老化的水利基础设施作斗争。水的供应、储存和从一个地方到另一个地方的运输是一个挑战。一位数据科学家被请来建立一些关于客户将如何受到影响的模型,并为改善供水提供一些启示。
目标是理解算法;然而,当变量有真正的意义时,它有助于我们深入了解它是如何工作的,以及背后的数学原理。
例题: 客户将如何根据他们的位置进行聚类?创建一个放置 3 口和 7 口水井的可视化模型,每口井作为质心。
客户的位置是固定的等距点,使用内置的范围函数生成。一共 1392 分。
作者图片
在绘制了每个客户的固定位置后,我找到了我认为是数据集地理中心的地方。我认为这是第一口水井的理想地点。
作者图片
对于以每口井为质心的 3 口水井的布局,客户将被分为以下几类。用于预测新井位置的特征是每个点距质心的距离。
作者图片
对于 7 个水井的位置,每个水井都有一个质心,客户将按以下方式聚集。
作者图片
假设所有单个点的距离彼此等距,则在这种情况下应用 k-means 聚类算法是有意义的。应用距离公式计算每个点和所选质心之间的欧几里德距离。
接下来,我决定给这个问题添加一些上下文,并包含一些特征工程,以查看当应用 k-means 算法时,客户将如何聚类。
我添加了一些随机点,每个点代表一个特定的负责分配水的供水公司。显然,在这个假想的数据集上做了一些假设,但总体目标是看到 k-means 聚类算法在运行。
假设每个自来水公司都有一个单独的定价结构,根据水从每口井流出的距离来生产和向客户分配水,我想看看在考虑其他特征时,k-means 聚类算法将如何运行。
在这个场景中,根据一家供水公司的定价结构和水到达每个客户的距离创建了四个分类。
作者图片
k-means 聚类算法用于计算如何根据利润率(生产价格和销售价格之间的差额)对客户进行细分。
作者图片
我对这个虚拟数据集应用的 k-means 聚类算法的最后一个应用程序将客户分为 3 个部分。它使用了一种称为线附加费的功能,这是一种基于距离应用于数据集的功能。
作者图片
我花了大约两周的时间尝试了解 k-means 聚类算法。当应用于现实生活的概念场景时,理解算法如何工作是最好的证明。
虽然这目前超出了 k-means 聚类算法的范围,但逻辑上的下一步将包括探索每个自来水公司的一些分类算法模型以及对该场景的更多假设,例如:
想象一下,在公共供水公司突然被私有化为七家公司后,每个客户被随机分配到一口井,而不考虑距离。每个公司根据水的运输距离有不同的线路附加费,根据客户的选择有不同的送货时间表和用水量。创建一个应用程序,准确地将各自的资金分配给每个自来水公司,并创建一个模型,以便有效和高效地将水分配给所有客户。
k-均值聚类和间隙统计
用差距统计弥合知识差距
照片由suser ll just me在 Freeimages 上拍摄并由我编辑
在引擎盖下有许多代码在运行。这就是为什么我在这篇文章的最后提供了我的 Github 库,并且我只展示了 K-Means 的一小段代码。
介绍
聚类是模式分析中识别数据中不同组的一种重要技术。由于数据大多是三维以上的,所以在应用聚类技术之前,我们执行像 PCA 或拉普拉斯特征映射这样的降维方法。然后,这些数据可以在 2D 或 3D 中使用,这使得我们可以很好地将发现的星团可视化。
尽管这是一个基本的工作流程,但情况并非总是如此。
数据通常也是无标签的。这意味着你没有明确的定义你想在这些数据中找到什么。这就是为什么聚类也是一种很好的数据探索技术,而不需要事先降维。
常见的聚类算法是 K-Means 和 Meanshift 算法。在这篇文章中,我将重点介绍 K-Means 算法,因为这是最简单和最直接的聚类技术。此外,我们将假设数据要么直接提供有两个特征(因此 2D),要么有人对数据执行 2D 降维,然后将其提供给我们。因此,我们直接深入应用 K-Means。
K-Means 算法需要一个超参数,即你想要寻找的聚类数 K 。但是,如果我们想找到集群,我们怎么知道我们需要多少集群?
示例:如果我们想要在数据中为我们的营销团队找到人物角色,我们可以假设我们想要找到三到四类人。
在这种情况下,K 的数量是固定的。但是如果不是呢?
超参数的选择称为模型选择。在
K-Means 的情况下,这只是我已经说过的 **K、**的数量。在这篇博文中,我将重点讲述我们如何通过对 K-Means 执行 Tibshirani 的 Gap-Statistics,从统计上找出 K 的最佳值。
Gap-Statistics 是由 Robert Tibshirani 于 2000 年在斯坦福引入的。
目标
我想用这个帖子来回答这三个问题:
- 1)如何在 K-Means 中找到 K 的最佳值?
- 2)我们如何衡量差距统计的性能?
- 3)在什么条件下差距统计可能会失败?
K-Means——非常简短的介绍
K-Means 执行三个步骤。但是首先你需要预先定义 k 的数量。这些聚类点通常被称为质心。
- 1)通过计算所有点到所有质心之间的欧几里德距离,将每个数据点(重新)分配到其最近的质心。
- 2)基于所有相应的数据点计算每个质心的平均值,并将质心移动到所有指定数据点的中间。
- 3)转到 1)直到满足收敛标准。在我的例子中,我计算所有点到重新分配的质心平均值之间的类内距离。在新的迭代之后,如果所有的质心一起移动小于 0.01,那么基本上不再发生什么,执行收敛标准。
代码 1)K-表示由我从头开始编写
在上面的代码 1 中可以看到,第 9 行使用列表理解为每个数据点计算到每个中心点的欧几里德距离(第 3 行中 K = 3)。Numpy.argmin 然后为每个点选择最近的距离,并将其分配给该质心。第 13 行计算第三步,并对总的簇内距离求和。如果小于 0.01,则 while 循环中断。
图 1) K=3 gif |我做的
我们可以看到在循环中每个点的分配是如何变化的。总共需要五次循环直到收敛。
通知:质心的初始化对 K-Means 的执行有很大的影响。想象两个质心从最左边和最低的位置开始。每个数据点将被分配给质心一号,聚类是无用的。
注意 : K-Means 只是局部最优,并不能保证全局最小
进一步的调查
图 1 显示了 300 个数据点的 3 个质心。我还没有展示数据的代码,它只是从带有 make_blobs 的 sklearn 中生成的。
当然,在有三个全局最优质心的情况下,这种簇内距离不会进一步减小。但是当我们给 K 加上越来越多的值时会发生什么呢?簇内距离将几乎单调地缩小。想象一下,如果我们用一个额外的质心将图 1 的三个集群中的一个分成两个。簇内距离会缩小,因为所有点现在都更靠近另一个质心,即使这显然是一个错误的簇分裂。
图 2) K=300 |我做的
当我们选择 K 的数量等于质心的数量时,总的簇内距离将是 0。从最小化问题的角度来看,这是理想的,但对我们来说不是。
图 3) K=11 |我做的
当我们选择 K 的数目等于 11 时,我们可以看到,我们将永远不会达到小于 3 的总簇内距离。
由于图 2 和图 3 中的起点为 1,所以图 2 的实际簇内距离为零,而图 3 的实际簇内距离为二。
那么我们如何防止 K 被选择为等于数据点的数量呢?
我们如何通过初始化来强制我们的集群拥有 K 个非空组件?
- 1)在样本点的位置初始化每个聚类中心
- 2)针对局部最小值制定对策
1)如何在 K-Means 中找到 K 的最优值?
答案当然是缺口统计,但它是什么呢?
它是由罗伯特·提布拉尼在 20 年前发明的。基本的最小化问题如下所示:
公式 1)估计 K*的形式规则由 HTF 统计学习的要素第 519 页 | 14.3.11 实际问题
看起来怪怪的?没问题!K*是我们想要找到的 K 的最优值。我们需要定义不同的数据矩阵 W_data 和 W_uniform。其中 W_data 是上图 1 中的 300 个数据点,W_uniform 基本上是群集内距离的模拟平均分布,如进一步调查部分所述。W_uniform 基本看起来像图 3。
公式 2)缩减差距统计公式
我们在 中可以看到,其中 上面的*,*表示 S’(S 素数)等于前面的 S 乘以一个小值(1.024695)。这意味着它在每个时间步长不断变大。
第一个时间步长的初始 S 等于所有均匀绘制的数据点的标准偏差,例如 20 次运行。可能更多,但是 Tibshirani 写道 20 次模拟已经足够了。
这是什么意思呢?
好吧。正如我们已经指出的,我们需要一种方法,使得 K 的最佳数目不被选为数据点的数目。为此,引入模拟平均值W _ uniform from和标准差 S’(K+1)。
通过检查公式 1 中每个时间步长的图中的最小化问题,我们取 K 的数目,这通过引入新的质心而使最大跳跃进入减少的总簇内距离。
如果你仔细观察图 3,你会发现距离减少的跳跃对于前几个质心来说特别大。这具有直观的意义,因为如果你回头看一下图 1,很明显你引入的质心越多,簇内距离的变化就越小。
因此,差距统计的基本思想是根据均匀抽取的样本的总体行为,选择 K 的数量,即类内距离发生最大跳跃的地方。可能的情况是簇内距离仅发生非常轻微的减小。出于这个原因,S’(K+1)充当阈值,以挑选出太微小的变化,并从数据中去除采样噪声。只有当变化大到阈值 S′(K+1)不再起作用时,才会选择 K 的最佳值。
让我为你想象一下:
图 4)差距统计|我做的
注意:类内距离曲线的值已经被最大类间距离归一化。
我故意选择了图 4 左上角的数据,下面的两个簇非常接近。K-means 几乎不可能分辨出这些是不同的聚类。
在左下方的图像中,我们可以看到差距统计数据。选择 K=3 的最佳值,因为我们在值再次收缩之前选择第一个峰值点。红线的计算方法是从右下图的 W_data(蓝色)中减去 W_uniform(绿色)。
退一步:右下图像显示 W_data(蓝色)和 W_uniform(绿色)分布。通过查看 G(K)上的公式 2,我们看到需要用 W_data to 的对数减去 W_uniform 的对数。
对于 W_data 和模拟的 W_uniform,总的簇内距离如预期的那样收缩。但是在 K=4 时,间隙统计检测到 W_data 的总距离的变化不像模拟的那样。这意味着它没有像预期的那样减少。
即使当从 W_uniform 中减去标准偏差 S’(K+1)时,间隙统计也将选择 K 的最佳值作为 3 。
注意:如果我们假设 K=4 处的间隙不存在,则低于其前一个点的下一个点在 K=6 处。但由于我将标准偏差标记为垂直的粗红线,我们看到,减去标准偏差后,距离的变化太小,因此 K 将被选择为 K=6。将被选择的下一个 K 是 K=7,因为在 K=8 时出现下一个大间隙。
2)我们如何衡量差距统计的性能?
正如我已经提到的,质心的初始化高度影响 K 均值的优化。我们需要考虑不同的数据分布。在计算 K-Means 算法的第二步时,我们需要记住两种基本情况:
- 1)总体聚类距离大 - >我们取平均值
- 2)总体聚类距离小 - >我们取最小值
如果我们在计算差距统计之前考虑这两种差异,那么差距统计将更加稳健。
对于我的例子,总的聚类距离很小,所以我计算了平均值,如代码 1 的第 12 行所示,这里我使用 Numpy.mean。
3)在什么条件下差距统计可能会失败?
可能会出现三种情况:
- 低估集群
- 高估集群
- 通常
低估
如果两个或三个集群非常接近,而其他集群相距甚远,它往往会低估。这正是我之前向您展示的示例中所发生的情况。其中两个星系团靠得太近,所以间隙统计低估了 K*。
高估
如果所有的星团都很接近,那就高估了而不是低估了。我真的不能解释为什么,但这是我计算了几次后发生的事情。
图 5)差距统计高估|我做的
通常
低估和高估都主要取决于随机初始化的质心。当它们中的一些由于随机的不顺利而被忽略时,类内距离的中断迫使间隙统计更早地产生最佳的类。
结论
即使间隙统计是找到合适的 K 的好方法,它仍然不是完美的。例如,我们需要引入一个新的超参数,即模拟 W_uniform 的 K 的个数。我们不能确定这个的理想值是多少。此外,质心的随机初始化会导致高估或低估 K*。
但是通过了解差距统计的所有方面,最好的方法是应用它,然后运行几次差距统计图。取差距统计的平均值可以是一个增加的评估标准。
希望你喜欢这篇文章,它给了你一些差距统计的见解。
密码
你可以在我的 Github 页面 这里 找到这个项目的完整代码。如果您对代码有任何疑问,可以给我发电子邮件。你可以在我的网站上找到我的邮箱地址。
参考
[1] Trevor Hastie,Robert Tibshirani 和 Jerome Friedman,统计学习的要素:数据挖掘、推理和预测 (2009),Springer
[2] Trevor Hastie,Robert Tibshirani 和 Guenther Walther,通过差距统计估计数据集中的聚类数 (2000)
这篇博文基于从弗里德里希·亚历山大大学埃尔兰根-纽伦堡的课程模式分析中获得的知识。我使用了 Christian Riess 博士演讲的部分内容来说明这篇文章的例子。所以所有权利归克里斯汀·里斯博士所有。
k-均值聚类—已解释
详细的理论解释和 scikit-learn 实现
假设我们开始做生意,向人们出售一些服务。业务进展顺利,几个月内我们的数据库中就有了大约一万名客户。我们希望留住我们的客户,同时增加每位客户的收入。所以我们计划向数据库中的客户提供一笔交易。我们有两个选择:
- 向所有客户提供相同的交易
- 准备客户特定的交易
第一种选择很简单。“所有服务打九折”的交易就可以了。然而,与针对客户的交易相比,这种方式效率较低,利润也较低。此外,针对客户的交易可能对客户更有吸引力。一些顾客喜欢某一件商品打折,而另一些顾客喜欢买一送一的交易。一些客户在周末购买服务 A,而另一些客户在周一上午购买。根据企业规模和客户数量,我们可以列出更多不同的选项。
我们决定准备客户特定的交易。下一步是决定提供什么样的交易。我们不能只为每个客户创建不同的交易。这根本无法管理。一个明智的选择可能是发现具有相似兴趣或购买行为的客户,并将他们分组。分组的标准可以是客户偏好、品味、兴趣、客户服务组合等等。假设客户数据库中有每个客户的以下信息:
- 客户年龄、地址
- 平均采购金额
- 平均购买数量
- 购买频率
- 购买的时间和类型
这个列表很容易扩展。手动对客户进行分组极其困难。然后我们向机器学习寻求帮助。将相似客户分组的任务称为聚类。维基百科上更正式的定义:
聚类分析或聚类是对一组对象进行分组的任务,使同一组中的对象(称为聚类)比其他组(聚类)中的对象彼此更相似(在某种意义上)。
在我们的例子中,对象是客户。
聚类是无监督的,这意味着没有样本(或数据点)的标签。聚类在很多行业都有应用。以下是集群的一些示例:
- 客户细分
- 图象分割法
- 图像/颜色压缩
- 检测异常或异常值
有许多不同的聚类算法。在这篇文章中,我将介绍一种最常见的聚类算法: K-Means 聚类。
聚类 vs 分类
在开始讨论 k-means 聚类之前,我想指出聚类和分类之间的区别。
- 分类任务中的样本有标签。每个数据点根据一些测量结果进行分类。分类算法试图对样本的测量值(特征)和它们的指定类别之间的关系进行建模。然后模型预测新样本的类别。
- 聚类分析中的样本没有标签。我们希望该模型能够在数据集中找到结构,以便相似的样本能够被分组到聚类中。我们基本上是让模特给样品贴标签。
K-均值聚类
k-均值聚类旨在将数据划分为 k 个聚类,使得同一聚类中的数据点相似,而不同聚类中的数据点相距较远。
两点的相似性由它们之间的距离决定。
测量距离的方法有很多。欧氏距离(p = 2 的闵可夫斯基距离)是最常用的距离度量之一。下图显示了如何计算二维空间中两点之间的欧几里德距离。它是使用点的 x 和 y 坐标之差的平方来计算的。
在上面的例子中,欧几里德距离是(16 + 9)的平方根,也就是 5。二维中的欧几里得距离让我们想起了著名的勾股定理。
还有其他方法来衡量距离如余弦相似度,平均距离等等。相似性度量是 k-means 聚类的核心。最佳方法取决于问题的类型。因此,为了选择最佳的测量类型,拥有良好的领域知识是很重要的。
K-means 聚类试图最小化一个类内的距离,最大化不同类之间的距离。
让我们从一个简单的例子开始理解这个概念。像往常一样,我们首先导入依赖项:
# Importing necessary libraries
import numpy as np
import pandas as pdimport matplotlib.pyplot as pltfrom sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
Scikit-learn 提供了许多有用的功能来创建合成数据集,这对练习机器学习算法非常有帮助。我将使用 make_blobs 函数。
X, y = make_blobs(n_samples = 200, centers=4, cluster_std = 0.5, random_state = 0)plt.scatter(X[:, 0], X[:, 1], s=50)
然后我们创建一个 KMeans 对象并拟合数据:
kmeans = KMeans(n_clusters = 4)
kmeans.fit(X)
现在,我们可以将数据集划分为多个集群:
y_pred = kmeans.predict(X)
plt.scatter(X[:, 0], X[:, 1], c = y_pred, s=50)
现实生活中的数据集要复杂得多,其中的聚类没有明显的区分。但是,算法的工作方式是一样的。
K-means 算法不能确定聚类数。我们需要在创建 KMeans 对象时定义它,这可能是一项具有挑战性的任务。
K-means 是一个迭代过程。它基于期望最大化算法。确定集群数量后,它通过执行以下步骤来工作:
- 为每个簇随机选择质心(簇的中心)。
- 计算所有数据点到质心的距离。
- 将数据点分配给最近的聚类。
- 通过取聚类中所有数据点的平均值,找到每个聚类的新质心。
- 重复步骤 2、3 和 4,直到所有点收敛并且聚类中心停止移动。
注意:初始质心是随机选择的,这可能会导致最终的聚类有些不同。为了克服这个问题,scikit learn 提供了 n_init 参数。k-means 算法以不同的初始质心运行“n_init”次,并且最终结果将根据 n_init 次连续运行来确定。
你可以使用 Naftali Harris 在他的博客上准备的这个工具来可视化每个步骤。我从这个互动工具中截取了截图,这样上面的步骤就更容易理解了。我强烈建议花点时间使用这个工具。
随机选择质心
计算所有数据点到质心的距离,并将数据点分配给最近的聚类
通过取平均值来计算每个聚类的新质心
将数据点重新分配到最近的聚类中心
当聚类中心(质心)不再移动时,模型收敛
利弊
优点:
- 容易理解
- 相对较快
- 可扩展用于大型数据集
- 能够以一种聪明的方式选择初始质心的位置,从而加速收敛
- 保证收敛
缺点:
- 集群的数量必须预先确定。K-means 算法无法猜测数据中存在多少个聚类。确定集群的数量可能是一项具有挑战性的任务。
- 只能画线性边界。如果数据中存在非线性结构来分隔组,k-means 将不是一个好的选择。
- 随着样本数量的增加而变慢,因为在每一步,k-means 算法都会访问所有数据点并计算距离。另一种方法是使用数据点的子集来更新质心的位置(即 sk learn . cluster . minibatchkmeans)
- 对异常值敏感
感谢您的阅读。如果您有任何反馈,请告诉我。
我关于机器学习算法的其他帖子
K-Means 聚类讲解:算法和 Sklearn 实现
聚类和 k-means 聚类简介。详细概述和 sklearn 实现。
K-Means 聚类是数据科学和机器学习领域中最强大的聚类算法之一。它非常简单,但却能产生非常好的效果。因为聚类是理解数据集的一个非常重要的步骤,所以在本文中,我们将讨论什么是聚类,我们为什么需要它,以及 k-means 聚类在数据科学中对我们有什么帮助。
文章概述:
- 什么是集群
- 什么是无监督机器学习
- 集群应用
- k-均值聚类解释
- k-均值聚类算法
- 使用 Scikit-Learn 和 Python 实现 K-Means 聚类
什么是集群
聚类的任务是根据数据的属性,更确切地说是根据数据中或多或少明显的某些模式,将数据分组为两个或多个组。我们的目标是找到数据中的那些模式,帮助我们确定,给定数据集中的某个项目,我们将能够正确地将该项目放在正确的组中,以便它与该组中的其他项目相似,但与其他组中的项目不同。
这意味着聚类实际上由两部分组成:一部分是识别组,另一部分是尽可能将每个项目放在正确的组中。
聚类分析算法的理想结果是同一组中的两个项目尽可能相似,而不同组中的两个项目尽可能不同。
聚类示例—来源:维基百科
一个真实的例子是客户细分。作为一家销售各种产品/服务的企业,很难为每个客户找到完美的商业策略。但我们可以明智地将我们的客户分成几个小组,了解这些客户的共同点,并针对每个小组调整我们的业务策略。向客户提出错误的商业策略可能意味着失去该客户,因此我们实现了良好的市场聚类非常重要。
什么是无监督机器学习
无监督机器学习是一种机器学习算法,它试图在没有任何先验知识的情况下推断数据中的模式。与之相反的是监督机器学习,我们有一个训练集,算法将通过将输入与预定义的输出进行匹配来试图找到数据中的模式。
我写这个的原因是因为聚类一个无监督的机器学习任务。当应用聚类算法时,我们事先不知道类别(尽管我们可以设置想要被识别的类别的数量)。
分类将从分析数据的算法中产生。正因为如此,我们可以称聚类为探索性的机器学习任务,因为我们只知道类别的数量,而不知道它们的属性。然后,我们可以尝试使用不同数量的类别,看看我们的数据是否有更好的聚类。
然后,我们必须了解我们的集群,这实际上可能是最不同的任务。让我们重新使用客户细分的例子。假设我们运行了一个聚类算法,将我们的客户分为 3 组。但是那些群体是什么呢?为什么算法决定这些客户适合这个组,而那些客户适合那个组?这是你需要非常熟练的数据科学家以及非常了解你的业务的人的部分。他们会查看数据,尝试分析每个类别中的一些项目,并尝试猜测一些标准。一旦他们找到一个有效的模式,他们就会从那里进行推断。
当我们得到一个新客户时会发生什么?我们必须将该客户放入我们已经拥有的一个聚类中,这样我们就可以通过我们的算法运行关于该客户的数据,并且该算法将使我们的客户适合我们的一个聚类。此外,在未来,在我们获得大量新客户后,我们可能需要重建我们的集群——可能新的集群会出现,也可能旧的集群会消失。
集群应用
**有哪些常见的集群应用?**在我们爱上聚类算法之前,我们需要了解什么时候可以使用它们,什么时候不可以。
最常见的用例是我们已经讨论过的:客户/市场细分。公司无时无刻不在进行这种类型的分析,以便了解他们的客户和市场,并调整他们的商业策略、服务和产品,使之更适合他们。
另一个常见的用例由信息提取任务表示。在信息抽取任务中,我们经常需要发现实体、单词、文档等之间的关系。现在,如果你的直觉告诉你,我们有更大的机会找到彼此更相似的项目之间的关系,那么你是对的,因为对我们的数据点进行聚类可能会帮助我们找出在哪里寻找关系。(注:如果想了解更多关于信息抽取的内容,也可以试试这篇文章: Python NLP 教程:信息抽取和知识图)。
另一个非常流行的用例是使用聚类进行图像分割。图像分割是观察图像并试图识别图像中不同项目的任务。我们可以使用聚类来分析图像的像素,并识别图像中的哪个项目包含哪个像素。
k-均值聚类解释
K-Means 聚类算法是一种迭代聚类算法,它试图将数据点准确地分配到我们预定义的 K 个聚类中的一个聚类。
与任何其他聚类算法一样,它试图使一个聚类中的项目尽可能相似,同时也使这些聚类尽可能互不相同。这是通过确保一个聚类中的数据点与该聚类的质心之间的平方距离之和最小来实现的。聚类的质心是聚类中所有值的平均值**。你也可以从这一段了解到K-的意思是的来源。**
用更专业的术语来说,我们试图将数据放入一个尽可能同质的集群,同时尽可能异质的集群。K 数是我们试图获得的集群数。我们可以摆弄 K,直到我们对结果满意为止。
k-均值聚类算法
K-Means 聚类算法只需要几个简单的步骤。
- 分配 K 组数
- 混洗数据并将每个数据点随机分配到 K 个簇中的一个,并分配初始随机质心。
- 计算每个数据点和所有质心之间的平方和。
- 根据步骤 3 的计算,将每个数据点重新分配到最近的质心。
- 通过计算每个聚类的平均值来重新分配质心
- 重复步骤 3、4、5,直到我们不再需要更改集群中的任何内容
运行 K 均值聚类算法所需的时间取决于数据集的大小、我们定义的 K 数以及数据中的模式。
使用 Scikit-Learn 和 Python 实现 K-Means 聚类
我们将使用 Sckikit-Learn Python 库在一个小数据集上运行 K-Means 聚类算法。
K 均值聚类算法的数据集
该数据由关于伦敦、巴黎和柏林的 3 个文本组成。我们将提取维基百科中关于这三个城市的文章的摘要部分,并通过我们的聚类算法来运行它们。
然后,我们将提供 3 个我们自己的新句子,并检查它们是否被正确地分配到各个组。如果发生这种情况,我们就知道我们的聚类算法起作用了。
k-均值聚类实现
首先让我们安装我们的依赖项。
# Sklearn library for our cluster
pip3 install scikit-learn
# We will use nltk(Natural Language Toolkit) to remove stopwords from the text
pip3 install nltk
# We will use the wikipedia library to download our texts from the Wikipedia pages
pip3 install wikipedia
现在让我们定义一个小类来帮助我们从维基百科页面收集文本。我们将文本存储到本地的 3 个文件中,这样我们就不会在每次运行算法时再次下载文本。第一次运行算法时使用 class,第二次运行时可以注释第 8-12 行,取消第 13-15 行的注释。
import wikipedia
class TextFetcher:
def __init__(self, title):
self.title = title
page = wikipedia.page(title) # 8
f = open(title + ".txt", "w") # 9
f.write(page.summary) # 10
f.close() # 11
self.text = page.summary # 12
#f = open(title + ".txt", "r")
#self.text = f.read()
#f.close()
def getText(self):
return self.text
现在让我们构建数据集。我们将获取关于每个城市的文本,并删除停用词**。停用词是我们通常在每次文本处理任务之前过滤掉的词。它们是英语中非常常见的单词,不会给文本带来任何价值和意义。因为它们中的大多数在任何地方都被使用,它们将阻止我们正确地对我们的文本进行聚类。**
from text_fetcher import TextFetcher
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import nltk
def preprocessor(text):
nltk.download('stopwords')
tokens = word_tokenize(text)
return (" ").join([word for word in tokens if word not in stopwords.words()])
if __name__ == "__main__":
textFetcher = TextFetcher("London")
text1 = preprocessor(textFetcher.getText())
textFetcher = TextFetcher("Paris")
text2 = preprocessor(textFetcher.getText())
textFetcher = TextFetcher("Berlin")
text3 = preprocessor(textFetcher.getText())
docs = [text1, text2, text3]
单词矢量化技术
众所周知,计算机非常不擅长理解文本,但它们在处理数字方面表现得更好。因为我们的数据集是由单词组成的,所以我们需要将单词转换成数字。
****单词嵌入或单词矢量化代表一组用于将单词分配给实数向量的技术,这些技术可由机器学习用于某些目的,其中之一是文本聚类。
Scikit-Learn 库包含一些单词矢量器,但是对于本文,我们将选择tfidfvector。
tfidf_vectorizer = TfidfVectorizer()
tfidf = tfidf_vectorizer.fit_transform(docs)
现在是时候应用我们的 K 均值聚类算法了。幸运的是,Scikit-Learn 有一个非常好的 K-Means 算法实现,我们将使用它。因为我们知道要将文本分为 3 类(每个城市一类),所以我们将定义 K 值为 3。
kmeans = KMeans(n_clusters=3).fit(tfidf)
print (kmeans)
# Output: [0 1 2]
我知道,就这么简单!现在我们的产量意味着什么?简单地说,这 3 个值就是我们的 3 个集群。
为了测试它们,我们现在可以提供 3 个文本,我们确定它们应该在不同的簇中,看看它们是否被正确分配。我们必须确保不要忘记对这 3 个文本进行矢量化,以便我们的算法能够理解它们。
test = ["This is one is about London.", "London is a beautiful city", "I love London"]
results = kmeans.predict(tfidf_vectorizer.transform(test))
print (results)
# Prints [0, 0, 0]
test = ["This is one is about Paris.", "Paris is a beautiful city", "I love Paris"]
results = kmeans.predict(tfidf_vectorizer.transform(test))
print (results)
# Prints [2, 2, 2]
test = ["This is one is about Berlin.", "Berlin is a beautiful city", "I love Berlin"]
results = kmeans.predict(tfidf_vectorizer.transform(test))
print(results)
# Prints [1, 1, 1]
test = ["This is about London", "This is about Paris", "This is about Vienna"]
results = kmeans.predict(tfidf_vectorizer.transform(test))
print (results)
# Prints [0, 2, 1]
看起来我们的集群成功了!现在让我们假设我们会得到另一个我们一无所知的文本。我们可以将该文本通过我们的分类器,看看它属于哪个类别。我认为这是一个非常好和有效的文本分类器。
结论
今天我们讨论了 K 均值聚类算法。我们首先对聚类算法和无监督机器学习技术进行了概述,然后讨论了 K-Means 算法,并使用 Scikit-Learn Python 库实现了它。
本文原载于 程序员背包博客 。如果你想阅读更多这类的故事,一定要访问这个博客。
非常感谢你阅读这篇文章!对更多这样的故事感兴趣?在 Twitter 上关注我,在@ b _ dmarius我会在那里发布每一篇新文章。
k 均值聚类
概述
今天机器学习的大多数应用都是基于监督学习的。然而,大部分数据是没有标签的:我们有输入 X ,但没有标签y计算机科学家扬·勒库恩的名言
如果智能是一块蛋糕,无监督学习就是蛋糕,有监督学习就是糖衣,强化学习就是上面的樱桃。
换句话说,无监督学习有巨大的潜力。
无监督学习的一种形式是将相似的实例分组到*簇中。*聚类是数据分析、客户细分、推荐系统、搜索引擎、半监督学习、降维等等的一个很好的工具。
如果你每天在一个公园里散步,你可能会无意中发现一棵你从未见过的树。如果你环顾四周,注意到更多的一些,它们并不完全相同,但看起来非常相似,你知道它们属于同一个属。你可能需要一个树木学家来告诉你这是哪一个物种,但是你不需要专家来给你的树分类。这就是集群的本质:识别相似实例,并将它们分配到集群或相似实例组中的任务。
k 均值
最常用的聚类技术之一是 K-means。K-means 算法是由 Stuart Lloyd 和 Bell Labs 在 1957 年作为一种脉冲编码调制技术提出的,但直到 1982 年才在公司外部发表。Edward Forgy 在 1965 年发表了几乎相同的算法,因此它被称为 Lloyd-Forgy。以下内容生成了我们将进行聚类的数据:
from sklearn.datasets import make_blobsblob_centers = np.array([[ 0.2, 2.3],[-1.5 , 2.3],[-2.8, 1.8],[-2.8, 2.8],[-2.8, 1.3]])blob_std = np.array([0.4, 0.3, 0.1, 0.1, 0.1])X, y = make_blobs(n_samples=2000, centers=blob_centers,
cluster_std=blob_std, random_state=7)plt.figure(figsize=(8, 4))
plot_clusters(X)
save_fig("blobs_plot")
plt.show()
未标记的数据集
K-Means 在聚类上面的数据时非常有效,通常只需要很少的迭代。它将试图找到每个集群的中心,并将每个实例分配给最近的集群。让我们训练一个 K 均值聚类器:
from sklearn.cluster import KMeans
k = 5
kmeans = KMeans(n_clusters = k)
y_pred = kmeans.fit_predict(X)
每个实例被分配到五个集群中的一个。它接收一个标签作为它被分配到的集群的索引。
我们可以看到这些标签:
y_pred
array([4, 0, 1, ..., 2, 1, 0], dtype=int32)y_pred is kmeans.labels_
True
我们还可以看到算法找到的五个质心(聚类中心):
kmeans.cluster_centers_
array([[ 0.20876306, 2.25551336],
[-2.80580621, 1.80056812],
[-1.46046922, 2.30278886],
[-2.79290307, 2.79641063],
[-1.99213367, 1.3131094 ]])
对于新数据,我们也可以很容易地做到这一点,通过查看任何新数据点最接近哪个质心。我们也可以可视化决策边界,每个质心用 x 表示。
k 意味着判定边界和质心
最初,随机放置质心,标记实例,并更新质心。这个过程反复进行,直到质心停止移动,并且已经定义了聚类。
加速 K-均值算法
加速 K-Means 是 Sklearn 的默认设置。它通过跟踪实例和质心之间的距离的下限和上限,大大加速了该算法。你可以强迫 Sklearn 使用原来的算法,尽管不太可能需要。
小批量 K 均值
代替在每次迭代中使用完整的数据集,该算法能够使用小批量,在每次迭代中稍微移动质心。这通常会将算法速度提高 3 到 4 倍。尤其重要的是,它使得对不适合内存的大型数据集进行聚类成为可能。一个限制是它的惯性通常稍差,尤其是当集群增加时,但是对于许多集群,使用小批量的速度要快得多。
寻找最佳的聚类数
在这个数据集中,我们可以清楚地看到有 5 个我们想要彼此分割的聚类。然而,情况并不总是如此,我们的数据通常没有像这样明显地分段。如果我们不采取预防措施来计算最佳集群数量,我们的结果可能会很差:
K 值过低
第一个想法是选择最小化惯性的 k,但是我们不能这样做,因为惯性总是随着 k 的增大而减小。事实上,集群越多,每个实例越接近其最近的质心,因此惯性越低。正如我们在 k=8 的情况下所看到的,我们正在毫无理由地分割集群。
惯性作为 k 的函数
惯性很快下降到 5,但之后下降很慢。任何低于 5 的 k 值,增益都是巨大的,任何高于 5 的 k 值,我们都不会得到更多的信息。这是一种相当粗糙的,主观的分配 k 的方法,但是它通常工作得很好。这样做时,我们也可以考虑业务问题的特定需求。
然而,在这种情况下,我们可以看到有 5 个集群我们想要细分。4 个集群可能足够了,但是我们应该研究 k=4 和 k=5 之间的差异
剪影分数
另一种更精确的方法是对每个实例使用轮廓分数,并对不同数量的聚类绘制它们,然而这种方法计算量更大,它将给出更清晰的最佳 k:
from sklearn.metrics import silhouette_scoresilhouette_score(X, kmeans.labels_)silhouette_scores = [silhouette_score(X, model.labels_) for model in kmeans_per_k[1:]]
聚类数和轮廓分数
正如我们所看到的,使用 k 的每个级别的轮廓分数,哪一个 k 是最优的就更加明显了。
更有用的是绘制每个实例的轮廓系数,按它们所在的聚类和系数的值排序。这是一张剪影图。形状的高度表示聚类包含的实例数量,其宽度表示聚类中实例的排序轮廓系数(越宽越好)。虚线表示平均轮廓系数。
分析各种 K 的轮廓图
垂直虚线表示每个聚类数的轮廓分数。如果许多实例在虚线的短边(左边)停止,那么这个集群就相当糟糕,因为这意味着这些实例彼此靠得太近。在 k=3 和 k=6 时,我们得到的是坏簇,但在 k=4 和 k=5 时,它们相当好。大多数情况下会超出虚线。然而,当 k=4 时,橙色集群相当大,而在 k=5 时,它们都是相似的大小,所以看起来应该使用 5 来获得相似大小的集群。
执行这一过程显示了肘方法的明显局限性,定期执行它可以增强您选择 k 的稳健性。
K-意味着限制
作为一名优秀的数据科学家,了解你所使用的方法背后的假设是很重要的,这样你才能对它们的优缺点有所了解。这将帮助您决定何时以及在什么情况下使用每种方法:
- 我们经常会得到次优解和局部极小值(由于质心的随机初始化),因此需要多次运行算法来避免这种情况。
- 除此之外,我们还需要指定 k,这可能是主观的,有时相当麻烦,取决于数据集。
- 最大的问题是,当聚类具有不同的大小、密度或非球形形状时,K-Means 的性能不是特别好。根据数据的不同,另一种聚类算法可能会更好。(通常,在执行 K-Means 之前缩放输入要素会有所帮助,但这并不能保证所有聚类都是完美的球形)
- K-Means 也给予较大的聚类比较小的聚类更多的权重。换句话说,较小聚类中的数据点可以远离质心,以便更多地集中在较大的聚类上。这可能仅仅因为不平衡的数据而导致较小的集群分配不当。
- 最后,因为 K-Means 将每个实例分配到一个非重叠的聚类中,所以对于位于边界线附近的点没有不确定性的度量
在本文中,我讨论了最著名的聚类算法之一——K-Means。我们研究了在使用 K-Means 时可能面临的挑战。
我们实现了 k-means 并查看了肘形曲线,这有助于在 K-Means 算法中找到最佳的聚类数,同时也展示了它的局限性。
如果你有任何疑问或反馈,欢迎在下面的评论区分享
参考文献
Aurelien Geron (2019) 用 Scikit-Learn、Keras 和 TensorFlow 进行动手机器学习:构建智能系统的概念、工具和技术图书,第 2 版。,:奥赖利。
所有可视化的代码都可以在我的 GitHub 这里找到
适用于初学者的 k-均值聚类
一个学生用 Python 对这个有趣而有用的机器学习算法进行了深入的解释和逐步的指导
Python K-Means 聚类(所有照片按作者分类)
介绍
K-意思是聚类是我在进入机器学习时学习的第一批算法之一,就在线性和多项式回归之后。
但是 K-Means 从根本上背离了后两者。回归分析是一种监督的 ML 算法,而 K-Means 是非监督的。
这是什么意思?
监督学习和非监督学习是机器学习算法的两大类别:
监督学习
你输入标有数据的程序。换句话说,你在提供正确答案的数据上训练算法,然后将学习到的规则应用于新数据,以预测它们的答案。
这对回归和分类很有用。
无监督学习
您不需要为数据提供标签,而是由程序来发现它们。
这对于聚类和发现数据中的隐藏模式非常有用。
重要提示:
如果你是初学者,我建议你先阅读这些关于线性和多项式回归的文章,我在下面链接了这些文章。在其中,我涵盖了一些基本的机器学习知识和术语,我将在整篇文章中以此为基础。
一位同学用 Python 对这个简单的机器学习算法进行了全面、深入的解释
towardsdatascience.com](/linear-regression-the-actually-complete-introduction-67152323fcf2) [## 多项式回归:你需要的唯一介绍
一名学生对 Python 中机器学习算法背后的理论和应用的深入探究
towardsdatascience.com](/polynomial-regression-the-only-introduction-youll-need-49a6fb2b86de)
该算法
我想象一个有大量数据点的数据集。我们的目标是将每个点分配给一个集群或组。要做到这一点,我们需要找出集群在哪里,以及哪些点应该属于每一个。在我们的例子中,我们将有两个变量:不同国家的出生率和预期寿命。我们可以创建这个数据的散点图来可视化我们的组。
K-均值聚类的一个例子
为什么我们要对这些数据执行 K-Means 聚类?
这里有一个实际的例子:假设联合国希望根据这两个指标将国家分为三类,这样它们就可以根据各自的需求提供相应的援助。
除了目测,我们可以使用 K-Means 来自动化这个过程(其中 K 表示我们想要创建的集群的数量,而 Mean 表示平均值)。
K 均值背后有两个关键假设:
- 每个聚类的中心是属于该聚类的所有数据点的平均值。
- 每个数据点属于具有最近中心点的聚类。
这两个简单的假设描述了整个算法。我们的程序所做的就是迭代几个步骤,每个步骤都试图满足上述条件。
距离
在继续之前,我们必须讨论距离的概念。我们可以在 ML 中使用许多距离度量,例如曼哈顿和切比雪夫,但今天我们将坚持使用更熟悉的欧几里德、,你可能会记得高中数学中的这些。
在二维空间中,两点之间的欧几里德距离是
*√((xⱼ — xᵢ)² + (yⱼ — yᵢ)²)*
步伐
这是算法的概要:
- 通过从数据集中随机选取点并使用这些点作为平均值的初始值,初始化每个聚类的平均值。
- 将每个点分配给最近的聚类。
- 计算每个聚类的平均值,作为属于它的所有点的平均值。
- 重复 2 和 3 预定的次数,或者直到收敛。
这个例子
像往常一样,我们从进口开始:
- matplotlib(py plot & RC params)——创建我们的数据可视化
- sci kit-Learn(pairwise _ distances _ arg min)-执行机器学习
- NumPy——做科学计算
- csv —读取 csv 文件
- 集合(计数器和默认值)—用于计数
import matplotlib.pyplot as plt
import numpy as np
import csv
from sklearn.metrics import pairwise_distances_argmin
from collections import Counter, defaultdict
我有一个 csv 文件,其中包含如下所示的数据:
Countries,BirthRate(Per1000 - 2008),LifeExpectancy(2008)
Afghanistan,46.613,47.532
Albania,14.69,76.492
Algeria,20.804,72.44
...
为了处理这些数据,我们需要一些变量来保存我们的 x 值、y 值、标签和国家名称,在这个 csv 文件中是。我们可以用一个函数从文件中提取所有这些信息:
x, y, x_label, y_label, countries = read_csv()
我对 read_csv() 函数的定义如下。当然,您应该调整它以适合您的 csv 文件。
def read_csv():
x = []
y = []
countries = []
x_label = ""
y_label = ""
with open('dataBoth.csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
lines = 0
for row in reader:
if lines >= 1:
print(', '.join(row))
x.append(float(row[1]))
y.append(float(row[2]))
countries.append(row[0])
lines += 1
else:
x_label = row[1]
y_label = row[2]
print(', '.join(row))
lines += 1
return x, y, x_label, y_label, countries
现在我们已经处理了数据,我们需要将 x 和 y 组合成(x,y)对的 2D 列表,我们可以这样做:
X = np.vstack((x, y)).T
现在我们有了一个 2D 列表(实际上是一个 numpy 数组),如下所示:
[[46.613, 47.532]
[14.69, 76.492]
[20.804, 72.44]
...]
让我们绘制这些数据点的散点图,看看我们在这里处理的是什么:
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.scatter(x, y, color='#76c2b4')
plt.show()
(出生率、预期寿命)对列表的散点图
正如你所看到的,出生率和预期寿命之间的负相关是显而易见的。然而,3 个不同的组不会立即出现。这就是 K-Means 的用武之地。
接下来,我们将编写迭代创建集群的函数。该函数的逐行解释作为注释包含在下面的代码片段中,但是我也将在这里提供一些说明。
我们可以使用NP . random . random state(rseed)选择随机中心,调用。在那上面排列找到一个 i ,然后选择 X 的第个元素*,这就是我们的 (x,y) 对的 2D 列表,记住。我们有一个循环,其中我们使用pairwise _ distance _ arg min来计算点和中心之间的距离,然后从这些点的平均值中找到新的中心,然后检查聚类是否已经收敛(如果不能选择新的中心,则平均值变小)。当群集收敛时,此循环终止:*
def find_clusters(X, n_clusters, rseed=2):
# 1\. Randomly choose clusters
rng = np.random.RandomState(rseed)
i = rng.permutation(X.shape[0])[:n_clusters]
centers = X[i]
# The main loop
# This loop continues until convergence.
# You could make it run a set number of times by changing
# it to say while x > 5, for example, and removing the break
print("\nConverging centres:")
while True:
# 2a. Assign labels based on closest center
# I am using the pairwise_distances_argmin method to
# calculate distances between points to centres
labels = pairwise_distances_argmin(X, centers)
# 2b. Find new centers from means of points
new_centers = np.array([X[labels == i].mean(0) for i in
range(n_clusters)])
# 2c. Check for convergence
if np.all(centers == new_centers):
break
centers = new_centers
# Print converging centres
print(centers)
print()
return centers, labels
让我们将集群的数量设置为 3:
clust_num = 3
剩下要做的就是将我们的 K-Means 算法应用于数据的结果可视化:
centers, labels = find_clusters(X, clust_num)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis')
plt.title('K-Means clustering of countries by birth rate vs life expectancy')
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.show()
数据被分成 3 组
那就是成功实现的算法!
但是如果我们想要更多的信息呢?
毕竟,联合国希望看到每个集群中的国家名称。
我们可以提取所有这些信息,并将其打印到终端:
print("\nNumber of countries in each cluster:")
print(Counter(labels))
# Get cluster indices
clusters_indices = defaultdict(list)
for index, c in enumerate(labels):
clusters_indices[c].append(index)
# Print countries in each cluster and means
x = 0
while x < clust_num:
print("\nCluster " + str(x + 1))
print("----------")
for i in clusters_indices[x]:
print(countries[i])
print("----------")
print("Mean birth rate:")
print(centers[x][0])
print("Mean life expectancy:")
print(centers[x][1])
x+=1
这将打印每个集群中的国家以及该集群的平均出生率和预期寿命。
结论
至少应该清楚,K-Means 聚类是一种非常有用的算法,有许多实际应用。希望您已经学到了足够的知识,可以对一些有趣的数据执行自己的实现,并发现一些隐藏的聚类。
内容概述:
- 监督与非监督机器学习的简单比较。
- 该技术应用的一个例子。
- 算法的概要。
- 实现的例子。
如果您觉得这篇文章有帮助,我很乐意与您合作!在 Instagram 上关注我,了解更多机器学习和软件工程内容。
编码快乐!
订阅 📚为了不错过我的一篇新文章,如果你还不是中等会员,请加入🚀去读我所有的,还有成千上万的其他故事!
资源
ski kit Learnsk Learn . cluster . k meanshttps://sci kit-Learn . org/stable/modules/generated/sk Learn . cluster . k means . html**
Python 文档 收藏https://docs.python.org/2/library/collections.html
SciPynumpy . random . random statehttps://docs . SciPy . org/doc/numpy-1 . 15 . 0/reference/generated/numpy . random . random state . html**
sci kit Learnsk Learn . metrics . pairwise _ distance _ arg minhttps://sci kit-Learn . org/stable/modules/generated/sk Learn . metrics . pairwise _ distance _ arg min . html**
****Numpy.orgnumpy . v stackhttps://numpy . org/doc/stable/reference/generated/numpy . v stack . html
k-均值聚类从零开始
梅尔·普尔在 Unsplash 上的照片
我们学习 K-Means 聚类是如何工作的,并一点一点地对它进行编码
K -means 聚类(本文简称 k-means)是一种流行的无监督机器学习算法(无监督是指不需要目标变量,也就是 Y 变量来训练算法)。当我们面对数据时,尤其是具有大量特征的数据,将它们分类是很有帮助的。通过将相似的观察结果分类到一个桶中(也称为集群),我们可以比较和对比这些桶。理解驱动跨存储桶差异的特征为我们提供了关键的线索,让我们知道在创建分析或构建模型时应该关注什么特征(我们甚至可能希望将我们的分类直接用作模型特征)。
简而言之,这就是集群。现在让我们看看 k-means 是如何将我们的观察结果分成有意义的聚类的。
入门指南
如果你想看完整的代码,你可以从 GitHub 这里下载。
我已经为之前的帖子下载了它,所以我们今天将再次使用泰坦尼克号数据集:
import numpy as np
import pandas as pd
import numpy.matlib
import matplotlib.pyplot as plt
import seaborn as snstitanic = pd.read_csv('train.csv')
由于我们的主要重点是构建 k-means 并探索它是如何工作的,所以我们将只处理数据集中的两列:票价(为机票支付的价格)和乘客的年龄。我们也将删除空值。我先按票价然后按年龄对数据进行分类,因为我最终会选择前 k 个观察值作为聚类中心(质心)。排序确保了我将挑选 k 个彼此非常相似的观测值作为我的初始质心。这样,起始质心将是次优的,我们可以更清楚地看到算法如何能够收敛到更好的质心(和聚类)。
cluster_data = titanic[['Fare','Age']].copy(deep=True)
cluster_data.dropna(axis=0, inplace=True)
cluster_data.sort_values(by=['Fare','Age'], inplace=True)
cluster_array = np.array(cluster_data)
我们将要聚类的数据存储在数组 cluster_array 中。它看起来如下(第一列是票价,第二列是年龄):
# Fare Age
[[ 0\. 19\. ]
[ 0\. 25\. ]
[ 0\. 36\. ]
[ 0\. 38\. ]
[ 0\. 39\. ]
[ 0\. 40\. ]
[ 0\. 49\. ]
[ 4.0125 20\. ]
[ 5\. 33\. ]
[ 6.2375 61\. ]]
罗斯·斯奈登在 Unsplash 上的照片
K-均值算法
在我们编写代码之前,让我们先从概念上理解 k-means 算法是如何工作的。K-means 把每个星团想象成一个太阳系。星团中的一切(所有观测)围绕的恒星被称为星团的质心。
簇及其质心
所以给定一组质心和它们的坐标(其中 X 坐标是 fare,Y 坐标是 age),我们可以通过计算每个观察值最接近哪个质心(根据欧几里德距离)来轻松地计算出每个观察值属于哪个簇。
但是我们如何决定质心在哪里呢?这就是 k 均值算法的用武之地。首先,我们选择一个 k 值,即质心的数量(这是一个我们必须调整的超参数)。假设我们选择 k 为 4。然后我们可以随机选择 4 个点,并将它们指定为我们的起始质心。使用我们随机选择的起始质心,我们可以创建 4 个集群。听起来有点傻,对吧?选择随机质心并创建随机簇有什么意义?
这里有一个窍门:我们聚类的平均值成为我们新的质心(对于每个聚类,我们计算平均费用和平均年龄,这是我们新质心的坐标)。只要我们开始随机挑选的质心彼此稍有不同,新的质心(聚类平均值)将比我们最初的聚类更优;其中最优性被定义为最大化集群内的相似性和集群间的差异。
一旦我们有了新的质心,我们就可以根据它最接近的新质心来重新分配每个观测值的聚类。由于质心变得更加优化,我们的聚类也应该改进(在聚类内的同质性和跨聚类的方差方面)。现在,我们可以根据重新分配的簇的坐标的平均值,再次计算新的质心。这些质心将再次改进它们的前身,我们可以不断清洗和重复这个过程,直到算法收敛。收敛被定义为当我们不再能够减少所有聚类的偏离质心的平方和(也称为聚类平均值)时。与平均值的方差之和是一种衡量聚类成员之间相似程度的方法,该值越低,越相似越好。
一个例子可能会帮助你更好地理解这个算法的工作原理。想象一个房间里挤满了不同身高的人(下图)。我们想根据唯一可观察的参数,高度,将它们分成两类。所以我们随机选择两个人(穿灰色衣服的),并告诉其他人站在他们身高最接近的人旁边(抛硬币以打破平局)。一旦他们这样做了,这个组的平均值(或者身高等于平均值的人)就成为新的质心(绿色)。注意这是如何将质心推开的——绿色质心比灰色质心离得更远。这种推开所有质心(实际上我们会有不止 1 个特征和 2 个质心)是我们重复取平均值和重新聚类(假设我们没有取最大值和彼此相反的极值点作为初始质心)时往往会发生的情况。
新聚类的均值如何变得更优的示例
编码 K-均值-辅助函数
在我们开始编写代码之前,让我们回顾一下步骤:
- 随机分配质心来启动事物。
- 基于这些质心(以及一个观测到质心的距离),将每个观测分配给一个簇。
- 计算每个簇的平均坐标;这些是我们新的质心。
- 基于新的质心重新分配簇。
- 不断重复步骤 3 和 4,直到收敛。
为了让生活更简单,让我们定义几个助手函数。首先让我们写一个来计算两点之间的欧几里德距离(又名两点之间的直线距离):
def calc_distance(X1, X2):
return (sum((X1 - X2)**2))**0.5
接下来,我们需要一个给定一组质心的函数,它可以告诉我们每个观察值属于哪个簇。下面的函数使用嵌套的 for 循环(我知道效率不高)来计算每个观察值和每个质心之间的距离(使用我们的 calc_distance 函数)。然后,它根据最接近的质心将观察值分配给一个聚类。输出是每个观察的分类标签的列表。
# Assign cluster clusters based on closest centroid
def assign_clusters(centroids, cluster_array):
clusters = []
for i in range(cluster_array.shape[0]):
distances = []
for centroid in centroids:
distances.append(calc_distance(centroid,
cluster_array[i]))
cluster = [z for z, val in enumerate(distances) if val==min(distances)]
clusters.append(cluster[0])
return clusters
现在我们需要一个更新步骤的函数,在这里我们分配新的质心。以下函数将数据(每次观察的费用和年龄)、 cluster_array 及其所属的当前聚类、 clusters 连接在一起,形成一个数据帧、 cluster_df 。然后,我们可以按簇过滤 cluster_df ,以获得属于特定簇的观察值,并计算这些观察值的平均值。这些计算的平均值就是我们新的质心。
# Calculate new centroids based on each cluster's mean
def calc_centroids(clusters, cluster_array):
new_centroids = []
cluster_df = pd.concat([pd.DataFrame(cluster_array),
pd.DataFrame(clusters,
columns=['cluster'])],
axis=1)
for c in set(cluster_df['cluster']):
current_cluster = cluster_df[cluster_df['cluster']\
==c][cluster_df.columns[:-1]]
cluster_mean = current_cluster.mean(axis=0)
new_centroids.append(cluster_mean)
return new_centroids
calc_centroids 的返回值是一个数组,其中第一列是每个分类的平均费用,第二列是每个分类的平均年龄:
# Example Output of calc_centroids # Mean Mean
# Fare Age
0 1
0 34.835711 18.394295
1 13.119311 32.090217
2 285.381483 31.166667
3 96.662211 36.114023
我们需要的最后一个助手函数更多的是用于报告目的。我们想知道聚类内的方差是多少,或者换句话说,一个聚类内的观测值彼此之间有多相似或不相似。因此,让我们构建一个函数来计算每个聚类相对于质心的偏差平方和。该函数按聚类过滤 cluster_df ,计算平均值,然后从聚类内的每个观察值中减去聚类平均值。函数 repmat 获取一个给定的数组并复制它——在我们的例子中,我们希望复制我们观察到的所有次数的平均值,这样我们就可以直接减去这两个数组。
# Calculate variance within each cluster
def calc_centroid_variance(clusters, cluster_array):
sum_squares = []
cluster_df = pd.concat([pd.DataFrame(cluster_array),
pd.DataFrame(clusters,
columns=['cluster'])],
axis=1)
for c in set(cluster_df['cluster']):
current_cluster = cluster_df[cluster_df['cluster']\
==c][cluster_df.columns[:-1]]
cluster_mean = current_cluster.mean(axis=0)
mean_repmat = np.matlib.repmat(cluster_mean,
current_cluster.shape[0],1)
sum_squares.append(np.sum(np.sum((current_cluster - mean_repmat)**2)))
return sum_squares
酷,我们现在准备运行 k-means。
运行 K 均值
让我们仍然使用 4 个集群(k=4)。就像我之前所说的,我们将有目的地选择糟糕的起始质心,这样我们就可以看到算法所做的改进(我使用观察 2、3、4 和 5,因为它们产生了非常糟糕的起始簇)——实际上,我们不想这样做,因为它会减慢速度。然后,我们使用我们的助手函数 assign_clusters ,根据最接近的质心将每个观察值分配给一个集群。
接下来,我们运行 for 循环 20 次(在这种情况下,20 次就足够收敛了),其中我们重复计算新的质心(使用 calc_centroids )和新的聚类(使用 assign_clusters ),以便我们可以获得最佳的聚类。回想一下,通过重复计算聚类平均值(也称为新质心)和基于这些新质心分配新聚类的过程,该算法如何收敛到最终的聚类。
k = 4
cluster_vars = []centroids = [cluster_array[i+2] for i in range(k)]
clusters = assign_clusters(centroids, cluster_array)
initial_clusters = clusters
print(0, round(np.mean(calc_centroid_variance(clusters, cluster_array))))for i in range(20):
centroids = calc_centroids(clusters, cluster_array)
clusters = assign_clusters(centroids, cluster_array)
cluster_var = np.mean(calc_centroid_variance(clusters,
cluster_array))
cluster_vars.append(cluster_var)
print(i+1, round(cluster_var))
对于我的循环中的每一次迭代,我都在列表 cluster_vars 中存储了聚类与其质心的偏差平方和的平均值。此平均值是每个分类(对于所有分类)内方差水平的近似度量。因为我们希望集群成员尽可能相似,所以我们希望这个平均值尽可能低。让我们看看这个平均值是如何随着我们的迭代而演变的。开始时急剧下降,然后趋于平稳。到我们循环的第六次迭代时,它差不多收敛了。
所有聚类的平均方差和与循环迭代次数的关系
让我们看看我们的集群是否变得更好了。回想一下,我们从任意选择的质心开始。以下是基于这些初始质心的聚类(每种颜色都是一个聚类)。看起来我们很幸运有一些基于年龄的分离,但仅此而已。
初始聚类
这是聚合集群。这些集群的区分似乎更有意义:
- 有年纪较大的低价位乘客(绿色)。
- 年轻的低票价人群(深红色)。
- 买得起高价票的人(蓝色)。
- 还有那些买得起超贵门票的(讽刺的是黄金)。
聚合集群
另一种检验我们做得如何的方法是通过观察我们的集群的生存概率是否不同。记住 k-means 聚类是无监督的;因此,我们没有明确地训练模型来预测乘客是否幸存。相反,我们希望通过产生有意义的差异化集群,我们可以发现在我们关心的事情(在这种情况下是生存)方面也恰好表现不同的群体。相对于我们最初的集群,我们的聚合集群似乎在预测存活率方面做得更好。
该算法找到了具有更高生存概率的聚类
结论
显然,我们还可以做更多的事情,包括添加更多的功能(而不是只有 2 个),调整 k(集群的数量),并尝试更好地理解每个集群的身份和关键特征。但那是以后的事了。我希望通过阅读这篇文章,你对聚类是如何工作的,以及 k-means 是如何使用一个非常简单的算法来产生一些非常酷的结果有了一些了解。干杯,大家注意安全!
K-Means 聚类:工作原理&在数据中寻找最优的聚类数
数学公式,寻找最佳聚类数和 Python 中的工作示例
作者创造的形象
介绍
K-means 是应用最广泛的无监督聚类方法之一。
K-means 算法通过尝试将样本分成等方差的 K 组来对手头的数据进行聚类,从而最小化被称为 惯性 或组内平方和的标准。该算法要求指定聚类数。它适用于大量样品,并已在许多不同领域的大范围应用中使用。
k-means 算法将一组 N 个样本(存储在数据矩阵 X 中)分成 K 个不相交的聚类 C ,每个聚类由聚类中样本的均值 μj 来描述。这个星团通常被称为“T28 质心”。
K-means 算法属于无监督机器 学习算法/方法的家族。对于这一系列模型,研究需要手头有一个带有一些观察值的数据集**,而不需要观察值的标签 / 类别。无监督学习研究系统如何从未标记的数据中推断出描述隐藏结构的函数。**
现在让我们来发现算法的数学基础。
数学公式
给定一组观察值( x 1、 x 2、…、 x n ),其中每个观察值是一个d-维实向量,k-意味着聚类旨在将 n 个观察值划分为 k (≤ n )个集合形式上,目标定义如下:
作者创作的乳胶图像。
其中μI 是组/簇 Si 中的点的平均值。
如果你想在交互式路线图和活跃的学习社区的支持下自学数据科学,看看这个资源:https://aigents.co/learn
理解背后的算法
部分 Voronoi 图示例(来源:https://sci kit-learn . org/stable/auto _ examples/cluster/plot _ k means _ digits . html # sphx-glr-auto-examples-cluster-plot-k means-digits-py)。
该算法也可以通过 Voronoi 图的概念来理解。
首先,使用当前质心计算点的 Voronoi 图。最初,质心是随机选择的通常是,但这取决于底层使用的包/库/软件。
Voronoi 图中的每个线段成为一个单独的簇。
其次,质心被更新到每个线段的平均值。然后,该算法重复这一过程,直到满足停止标准。
当迭代之间目标 函数中的相对减少小于给定的容差 (ε)值或质心** 移动(在空间中)小于容差时算法停止。**
寻找最佳聚类数
如介绍中所述,K-Means 算法需要预先指定聚类的数量。如果没有关于数据中潜在聚类数的有效假设,这项任务可能很难完成。
幸运的是,有一些方法可以估计我们数据中的最佳聚类数,如轮廓系数或肘方法。如果地面真实标签未知,必须使用模型本身进行评估。在本文中,我们将只使用轮廓系数,而不是简单得多的肘法。简而言之,肘方法将方差百分比解释为聚类数的函数:应该选择多个聚类,以便添加另一个聚类不会提供更好的数据建模。
较高的轮廓系数分数与具有更好定义的聚类的模型相关。轮廓系数是为每个样本定义的,由两个分数组成:
- a :一个样本到同一类中所有其他点的平均距离。
- b :样本与下一个最近簇中所有其他点之间的平均距离。
单个样本的轮廓系数 s 定义为:
作者创作的乳胶图像。
最后,一组样本的总轮廓系数作为每个样本轮廓系数的平均值给出。
最好的值是 1,最差的值是-1。接近 0 的值表示重叠的簇。负值通常表示样本被分配到错误的聚类,因为不同的聚类更相似。
Python 工作示例
对于本例,我们将创建人工数据,即人工聚类。这样我们将提前知道地 到即我们数据集中簇的确切数目。
让我们从导入所需的 python 库开始:
from sklearn.datasets import [make_blobs](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_blobs.html#sklearn.datasets.make_blobs)
from sklearn.cluster import [KMeans](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans)
from sklearn.metrics import [silhouette_samples](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_samples.html#sklearn.metrics.silhouette_samples), [silhouette_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_score.html#sklearn.metrics.silhouette_score)
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
接下来,让我们创建一些包含 500 个样本、 2 个特征/变量和 K=4 个聚类的人工数据。
# Generating the data
# This particular setting has one distinct cluster and 3 clusters placed close together.
X, y = [make_blobs](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_blobs.html#sklearn.datasets.make_blobs)(n_samples=500,
n_features=2,
centers=4,
cluster_std=1,
center_box=(-10.0, 10.0),
shuffle=True,
random_state=1)
我们知道数据中有 K=4 个聚类,但是,为了了解剪影评分如何工作**,我们将使用一系列不同数量的聚类来拟合模型。**
每一次,我们将估计轮廓分数,并且也用最终(收敛 ) 质心绘制数据。所有这些都是由下面的代码完成的:
range_n_clusters = [3, 4, 5]for n_clusters in range_n_clusters:
# Create a subplot with 1 row and 2 columns
fig, (ax1, ax2) = [plt.subplots](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html#matplotlib.pyplot.subplots)(1, 2)
fig.set_size_inches(18, 7)
# The 1st subplot is the silhouette plot
# The silhouette coefficient can range from -1, 1 but in this example all
# lie within [-0.1, 1]
ax1.set_xlim([-0.1, 1])
# The (n_clusters+1)*10 is for inserting blank space between silhouette
# plots of individual clusters, to demarcate them clearly.
ax1.set_ylim([0, len(X) + (n_clusters + 1) * 10])
# Initialize the clusterer with n_clusters value and a random generator
# seed of 10 for reproducibility.
clusterer = [KMeans](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans)(n_clusters=n_clusters, random_state=10)
cluster_labels = clusterer.fit_predict(X)
# The silhouette_score gives the average value for all the samples.
# This gives a perspective into the density and separation of the formed
# clusters
silhouette_avg = [silhouette_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_score.html#sklearn.metrics.silhouette_score)(X, cluster_labels)
print("For n_clusters =", n_clusters,
"The average silhouette_score is :", silhouette_avg)
# Compute the silhouette scores for each sample
sample_silhouette_values = [silhouette_samples](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_samples.html#sklearn.metrics.silhouette_samples)(X, cluster_labels)
y_lower = 10
for i in range(n_clusters):
# Aggregate the silhouette scores for samples belonging to
# cluster i, and sort them
ith_cluster_silhouette_values = \
sample_silhouette_values[cluster_labels == i]
ith_cluster_silhouette_values.sort()
size_cluster_i = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i) / n_clusters)
ax1.fill_betweenx([np.arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html#numpy.arange)(y_lower, y_upper),
0, ith_cluster_silhouette_values,
facecolor=color, edgecolor=color, alpha=0.7)
# Label the silhouette plots with their cluster numbers at the middle
ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
# Compute the new y_lower for next plot
y_lower = y_upper + 10 # 10 for the 0 samples
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")
# The vertical line for average silhouette score of all the values
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
ax1.set_yticks([]) # Clear the yaxis labels / ticks
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
# 2nd Plot showing the actual clusters formed
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
ax2.scatter(X[:, 0], X[:, 1], marker='.', s=30, lw=0, alpha=0.7,
c=colors, edgecolor='k')
# Labeling the clusters
centers = clusterer.cluster_centers_
# Draw white circles at cluster centers
ax2.scatter(centers[:, 0], centers[:, 1], marker='o',
c="white", alpha=1, s=200, edgecolor='k')
for i, c in enumerate(centers):
ax2.scatter(c[0], c[1], marker='$%d$' % i, alpha=1,
s=50, edgecolor='k')
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")
[plt.suptitle](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.suptitle.html#matplotlib.pyplot.suptitle)(("Silhouette analysis for KMeans clustering on sample data "
"with n_clusters = %d" % n_clusters),
fontsize=14, fontweight='bold')
[plt.show](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.show.html#matplotlib.pyplot.show)()
控制台中的代码输出(图片由作者创建)
我们观察到,在 K=4 个聚类的情况下,平均/均值轮廓得分最高。
这验证了轮廓分数是 K-均值拟合优度的良好度量。
我们还制作了这些图:
剪影分数&最终(收敛 ) 质心的数据(图片由作者创建)
剪影分数&最终(收敛 ) 质心的数据(图片由作者创建)
剪影分数&最终(收敛 ) 质心的数据(图片由作者创建)
垂直线是所有值的平均轮廓得分。
同样,我们还可以直观地验证轮廓得分是特定示例的 K 均值拟合优度的良好度量。
结论
K-means 是应用最广泛的无监督聚类方法之一。该算法通过尝试将样本分成等方差的 K 组来对手头的数据进行聚类,从而最小化被称为惯性或类内平方和的标准。该算法要求指定聚类数。
但是,如果地面实况标签未知,则必须使用模型本身进行评估。
在本文中,我们使用了轮廓系数。从工作示例中,我们可以验证轮廓分数是 K-means 拟合优度的良好度量。
仅此而已!希望您喜欢这篇新文章——更多内容即将发布!
参考
[1]彼得·j·鲁瑟夫(1987 年)。“轮廓:聚类分析的解释和验证的图形辅助”。计算与应用数学 20:53–65。doi:10.1016/0377–0427(87)90125–7。
[2]https://en . Wikipedia . org/wiki/Silhouette _(集群)
您可能还喜欢:
[## LSTM 时间序列预测:使用 LSTM 模型预测股票价格
在这篇文章中,我将向你展示如何使用预测 LSTM 模型来预测股票价格
towardsdatascience.com](/lstm-time-series-forecasting-predicting-stock-prices-using-an-lstm-model-6223e9644a2f) [## 时间序列预测:使用 ARIMA 模型预测股票价格
在这篇文章中,我将向你展示如何使用预测 ARIMA 模型来预测特斯拉的股票价格
towardsdatascience.com](/time-series-forecasting-predicting-stock-prices-using-an-arima-model-2e3b3080bd70)
敬请关注并支持这一努力
如果你喜欢这篇文章并觉得它有用,请关注我,这样你就可以看到我所有的新帖子。
有问题吗?把它们作为评论贴出来,我会尽快回复。
最新帖子
最有用的免费书籍和在线课程,适合想了解更多数据科学知识的人。
medium.com](https://medium.com/@seralouk/the-best-free-data-science-resources-free-books-online-courses-9c4a2df194e5) [## 用新冠肺炎假设的例子解释 ROC 曲线:二分类和多分类…
在这篇文章中,我清楚地解释了什么是 ROC 曲线以及如何阅读它。我用一个新冠肺炎的例子来说明我的观点,我…
towardsdatascience.com](/roc-curve-explained-using-a-covid-19-hypothetical-example-binary-multi-class-classification-bab188ea869c) [## 支持向量机(SVM)解释清楚:分类问题的 python 教程…
在这篇文章中,我解释了支持向量机的核心,为什么以及如何使用它们。此外,我还展示了如何绘制支持…
towardsdatascience.com](/support-vector-machines-svm-clearly-explained-a-python-tutorial-for-classification-problems-29c539f3ad8) [## PCA 清楚地解释了——如何、何时、为什么使用它以及特性的重要性:Python 指南
在这篇文章中,我解释了什么是 PCA,何时以及为什么使用它,以及如何使用 scikit-learn 在 Python 中实现它。还有…
towardsdatascience.com](/pca-clearly-explained-how-when-why-to-use-it-and-feature-importance-a-guide-in-python-7c274582c37e) [## 关于 Python 中的最小-最大规范化,您需要知道的一切
在这篇文章中,我将解释什么是最小-最大缩放,什么时候使用它,以及如何使用 scikit 在 Python 中实现它
towardsdatascience.com](/everything-you-need-to-know-about-min-max-normalization-in-python-b79592732b79) [## Scikit-Learn 的标准定标器如何工作
在这篇文章中,我将解释为什么以及如何使用 scikit-learn 应用标准化
towardsdatascience.com](/how-and-why-to-standardize-your-data-996926c2c832)
和我联系
- LinkedIn:【https://www.linkedin.com/in/serafeim-loukas/
- https://www.researchgate.net/profile/Serafeim_Loukas研究之门:
k-均值聚类:识别有利可图的酒店客户
K-Means 聚类算法允许我们对接近平均值的观察值进行分组。这使我们能够更高效地将数据分类到特定的部分。
在本例中,K-Means 用于分析葡萄牙一家酒店的市场细分聚类。
该分析基于下面参考文献部分引用的由 Antonio、Almeida 和 Nunes 进行的原始研究。
来源:Jupyter 笔记本输出
给定提前期(从客户预订到他们实际入住酒店的时间),以及 ADR (每位客户的平均每日房价),k-means 聚类算法用于直观地识别哪些细分市场对酒店最有利可图。
具有高 ADR 和低交付周期的客户是理想的,因为这意味着 1)客户支付高每日价格,这意味着酒店的利润率更高,而低交付周期意味着客户更快支付预订费用,这增加了酒店的现金流。
数据操作
加载数据并随机选择 100 个样本:
df = pd.read_csv('H1full.csv')
df = df.sample(n = 100)
间隔(或连续随机变量)为提前期和 ADR 定义如下:
leadtime = df['LeadTime']
adr = df['ADR']
使用’'‘分类代码’ ’ '定义具有分类成分的变量,在本例中为细分市场。
marketsegmentcat=df.MarketSegment.astype("category").cat.codes
marketsegmentcat=pd.Series(marketsegmentcat)
这样做的目的是为每个细分市场分配分类代码。例如,以下是数据集中一些市场细分条目的片段:
10871 Online TA
7752 Online TA
35566 Offline TA/TO
1353 Online TA
17532 Online TA
...
1312 Online TA
10364 Groups
16113 Direct
23633 Online TA
23406 Direct
应用cat.codes
后,这里有相应的类别。
10871 4
7752 4
35566 3
1353 4
17532 4
..
1312 4
10364 2
16113 1
23633 4
23406 1
细分市场标签如下:
- 0 =公司
- 1 =直接
- 2 =组
- 3 =离线 TA/TO
- 4 =在线 TA
使用 sklearn 对提前期和 ADR 特性进行缩放:
from sklearn.preprocessing import scale
X = scale(x1)
下面是 X 的一个例子:
array([[ 1.07577693, -1.01441847],
[-0.75329711, 2.25432473],
[-0.60321924, -0.80994917],
[-0.20926483, 0.26328418],
[ 0.53174465, -0.40967609],
[-0.82833604, 0.40156369],
[-0.89399511, -1.01810593],
[ 0.59740372, 1.40823851],
[-0.89399511, -1.16560407],
k 均值聚类
当谈到选择集群数量时,一个可能的解决方案是使用所谓的肘方法。以下是肘部曲线的一个示例:
来源:Jupyter 笔记本输出
这是一种计算每个分类的分类内方差的技术,方差越低,分类越紧密。
在这方面,随着分数开始变平,这意味着随着我们增加聚类的数量,方差的减少越来越少,这允许我们确定 k 的理想值。
但是,这种技术不一定适合较小的集群。此外,我们已经知道我们想要定义的集群的数量(k=5 ),因为我们已经知道我们想要分析的细分市场的数量。
此外,虽然 k-means 聚类方法也可以使用 PCA(或主降维)来减少特征的数量,但这在这种情况下是不合适的,因为使用的唯一两个特征(除了细分市场)是 ADR 和提前期。
因此,k-means 算法定义如下:
>>> km = KMeans(n_clusters = 5, n_jobs = None, random_state = None)
>>> km.fit(X)KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
n_clusters=5, n_init=10, n_jobs=None, precompute_distances='auto',
random_state=None, tol=0.0001, verbose=0)
为每个细分市场标签定义颜色主题:
# Market Segment Labels: 0 (Complementary) = firebrick, 1 (Corporate) = dodgerblue, 2 (Direct) = forestgreen, 3 (Groups) = goldenrod, 4 (Offline TA/TO) = rebeccapurplecolor_theme = np.array(['firebrick', 'dodgerblue', 'forestgreen', 'goldenrod', 'rebeccapurple'])
以下是实际标签的图表:
来源:Jupyter 笔记本输出
下面是 k-means 算法生成的聚类图:
来源:Jupyter 笔记本输出
如前所述,具有最短交付时间和最高 ADR 的客户被视为利润最高。
但是,好像有问题!许多细分市场类别都被贴错了标签。
这是使用 k-means 聚类时的一个常见问题,并不一定表示应该抛弃该模型!相反,它只是建议我们需要以不同的方式思考我们的数据。
例如,我们已经知道哪些客户属于哪个细分市场。在这点上,生成 k-means 聚类算法来再次预测这一点并没有多大用处。相反,运行这种算法的目的是快速了解哪种类型的客户最有利可图。
此外,我们只考虑了提前期和 ADR 这两个特征。可能还有我们没有考虑到的其他特征,这些特征可以更好地表明客户可能属于哪个细分市场,并且从我们目前看到的情况来看,没有直观的证据表明某些细分市场比其他细分市场更有利可图。
对此,我们稍微简化一下分析。如果我们使用三个集群呢?
来源:Jupyter 笔记本输出
我们看到,蓝色类别具有最高的 ADR 和最低的提前期(利润最高),而绿色类别显示最低的 ADR 和最高的提前期(利润最低)。
从这个角度来看,k-means 聚类算法提供了一种快速对酒店最赚钱的客户进行分类的有效方法,并且可以进行进一步的分析,以分析每组客户共有的某些属性。
当谈到无监督学习时——重要的是要记住这在很大程度上是一种探索性分析方法——目标不一定是预测,而是揭示以前可能没有考虑过的关于数据的见解。例如,为什么某些客户的交付周期比其他客户短?来自某些国家的客户更有可能符合这一特征吗?不同的客户类型呢?
这些都是 k-means 聚类算法可能无法直接回答我们的问题——但是将数据减少到单独的聚类中为能够提出这样的问题提供了一个强大的基线。
结论
在本例中,我们看到:
- 如何使用 Python 进行 k-means 聚类
- k-均值聚类在按盈利能力细分酒店客户中的应用
- 有效使用 k 均值模型的数据配置
非常感谢您的参与,这个例子的相关 GitHub 库可以在这里找到。
免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。
参考
- Antonio、Almeida 和 Nunes:使用数据科学预测酒店预订取消
- OpenClassrooms:执行 K-Means 聚类
- 中:用 PYTHON 中的 K-MEANS 聚类预测鸢尾花的种类
- 走向数据科学:当集群没有意义的时候
- 方差解释:K 均值聚类不是免费的午餐
Python 中的 K-Means 聚类
用 K-Means 直观地介绍数据科学
意味着聚类是一种无监督的最大似然算法,我们可以用它来将我们的数据集分成逻辑分组——称为聚类。因为它是无监督的,所以我们不需要依赖已标记的数据来进行训练。
用 K-均值识别的五个聚类。
这些分类是通过将数据分成明显不同的组来创建的,其中组成每个组的值是相似的,而不同组之间的值是不同的。
K-means 中的 K 是指聚类的个数。聚类机制本身的工作方式是将数据集中的每个数据点标记为一个随机的聚类。然后,我们循环执行以下过程:
- 取每个聚类中所有数据点的平均值
- 将该平均值设置为新的聚类中心(质心)
- 将每个数据点重新标记到其最近的聚类质心。
我们继续这个过程,直到质心停止移动,这意味着我们已经成功地对数据集进行了聚类!
这种算法的应用范围很广,一些最常见也最有趣的应用包括:
- 文档聚类(例如,政策、法规、技术规范)
- 市场分割
- 欺诈检测[1]
- 识别犯罪热点[2]
在本文中,我们将使用一个简单的数据集。然而,K-Means 可以有效地用于极其丰富多样的数据集-有些数据集有几十个特征和数百万个样本。
实现算法
我们将使用 Sci-kit Learn 实现 K-means。但在此之前,我们需要数据。这里我们可以使用 Sci-kit Learn 的make_blobs
函数来生成给定数量的人工生成的集群:
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=500, n_features=3, centers=5,
cluster_std=2)
在这个玩具示例中,我们可以分辨出我们的聚类——然而,当处理数百万个数据点和数十个特征/维度时,就变得困难多了。
这样,在变量X
中,我们现在有了包含500
数据点的人工数据,每个数据点由3
特征/尺寸组成,并且每个数据点属于5
斑点中的一个。变量y
告诉我们每个数据点属于哪个集群——通常,我们不知道这一点。
k 均值
现在我们有了数据。我们可以运行 K-Means 对其进行聚类!我们再次使用 sci-kit learn:
from sklearn.cluster import KMeans
model = KMeans(n_clusters=5)
这里我们已经用5
聚类质心初始化了 K 均值模型。然后,我们可以使用fit
方法用我们的数据X
运行我们的模型:
model.fit(X)
现在我们可以分别使用labels_
和cluster_centers_
方法访问我们的数据分类和质心坐标。
我们分别用 model.cluster_centers_ 和 model.labels_ 访问 X 数据聚类中心和标签。
当绘制质心和标记的数据点时,我们可以看到该算法已经识别了五个聚类:
用肘法选择 K
我们对 K-Means 的理解中缺少的一部分是如何选择 K?
到目前为止,最流行的方法是肘法。幸运的是,这也非常简单。
首先,我们需要用 K 的某个值运行我们的算法—一旦完成,我们可以从intertia_
属性中提取 X 值的误差平方和(SSE ):
sse = model.inertia_
SSE 计算为每个数据点与其分配的聚类质心之间的平方距离之和。如果所有数据点都紧紧聚集在分配给它们的质心周围,那么 SSE 将会很低,否则就会很高。
重要的是,我们要有足够的聚类来匹配我们数据集中的聚类,但不要有太多的聚类,通过简单地为每个数据点分配它自己的聚类,SSE 就会最小化。
sse = []for K in range(1, 10):
model = KMeans(n_clusters=K)
model.fit(X)
sse.append(model.inertia_)
我们需要找到一个神奇的地方,在那里我们可以正确地确定最合理的集群数量。可以通过计算 K 值范围的 SSE 并识别上图中的“弯头”来识别该点。
这就是对 K-Means 算法聚类的介绍!我们涵盖了:
- K 的意思是
- 用在哪里
- 我们如何使用它
- 用肘法选择 K
我希望你喜欢这篇文章——如果你有任何问题或想法,请通过 Twitter 或在下面的评论中告诉我。
感谢阅读!
参考
[1] A. Ghorbani,S. Farzai,使用基于数据挖掘方法的汽车保险欺诈检测 (2018),IJMEC
[2] M. Zulfadhilah 等人,使用日志分析和 K-Means 聚类的网络分析 (2016),IJACSA
*除非另有说明,所有图片均出自作者之手
大学数据的 k-均值聚类
我们能仅仅根据大学的特点把它们分为公立和私立吗?
瓦迪姆·谢尔巴科夫在 Unsplash 拍摄的照片。
大家好!对于这个项目,我想介绍一下 K 均值聚类,这是机器学习中最常见的聚类算法之一。在此过程中,我们将进行一些探索性的数据分析,以了解更多关于大学的数据集。
背景
对于那些可能是机器学习新手的人来说,聚类是无监督学习模型的一个例子,当我们将未分类的训练数据输入模型,并让我们的模型尝试根据数据的特征以某种方式对数据进行分类。
另一种方法是监督学习模型,我们预先为我们的训练数据分配标签,指示每个数据点属于哪个类别,该模型试图预测新数据点属于哪个类别。
我在中国从事教育工作近 4 年,我的工作涉及使用数据分析来估计学生被他们学校名单上的大学录取的可能性。为了好玩,我将用 Python 创建一个模型,使用 K-means 聚类将大学分为两组:私立和公立。事实上,一个在大学网站上至少做了粗略研究的学生可以在不到一分钟的时间内找到一所学校是私立还是公立的,但我们将看看一个模型是否能够根据似乎非常相关的特征(州外学费、毕业率)和似乎完全不相关的特征(捐赠校友的百分比)正确地对学校进行分类。
注意:我们实际上有这个数据集的标签,但是我们不会将它们用于 K-means 聚类算法,因为这是一个无监督的学习算法。最后,我将比较 K-means 和监督学习算法,以比较这两种模型的性能。
数据
以下是该数据集中的特征—随意浏览它们,并思考它们预测一所学校是公立还是私立的好坏程度:
- 申请:收到的申请数量
- 受理:受理的申请数量
- 招生:招生人数
- 前 10%的学生:来自高中班级前 10%的新生的百分比
- 高中班级排名前 25%的新生比例
- F .本科生:全日制本科生人数
- P .本科生:非全日制本科生人数
- 州外:州外学费
- 房间。食宿:食宿费用
- 图书:预计图书成本
- 个人:预计个人支出
- 博士:拥有博士学位的教师比例
- 终端:拥有终端学位(博士/法学博士/医学博士/工商管理硕士等)的教师比例
- 学生/教师比率:学生/教师比率
- 校友百分比:捐赠的校友百分比
- expense:每个学生的教学支出
- 毕业生。比率:毕业率
探索性数据分析
开始任何分析的一个好方法是使用熊猫。DataFrame.describe()来获得关于数据的一些基本统计信息。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snscolleges = pd.read_csv(‘College_Data’,index_col=0)
colleges.describe()
DataFrame.describe()的输出,关于数据集特征的一些基本统计数据。图片作者。
仅通过查看这些列的最大值,就可以发现一些问题:
- 众所周知,顶级私立学校每年收费高达 6 万美元,但这里的州外学费最高只有 21,700 美元,所以我们可以假设这笔学费是按学期而不是按年列出的。
- 有一所学校 100%以上的教师都是博士!这似乎有些可疑,但这或许可以用一小撮成绩优异的教师来解释,他们可能有一个被重复计算的双博士学位。
- 同样,我们也有一所毕业率为 118%的学校!我们稍后会探讨这种异常现象…
请随意查看平均值、中间值和其他统计数据,看看有什么让你印象深刻!这就是探索性数据分析的原因。
让我们来看看哪所大学的申请人数最多。
colleges.loc[colleges[‘Apps’]==np.max(colleges[‘Apps’])]
输出。图片作者。
结果是罗格斯大学的申请人数和录取人数最多,但注册人数却不是最多的。高中和大学的另一个值得夸耀的地方是他们的师生比:越低越好。
colleges.loc[colleges[‘S.F.Ratio’]==np.min(colleges[‘S.F.Ratio’])]
输出。图片作者。
这里的赢家是查尔斯顿大学,其 非常低 的比率为 2.5,这实际上是一个与家庭学校或私人辅导一样亲密的教学环境。考虑到学生与教师比率的第 25 百分位是 11.5,C 的 U 是一个主要的异常值。
现在来说说钱:哪个大学的校友捐赠率最高?
colleges.loc[colleges[‘perc.alumni’]==np.max(colleges[‘perc.alumni’])]
输出。图片作者。
威廉姆斯获奖不足为奇,因为这是一所小型文理学院(总共约 2000 名学生),主要面向拥有强大人脉的富裕家庭。之前打电话告诉我们,捐款比例的中位数只有区区 21%,因此作为学生打电话者,校园里有大量的工作机会。
现在有趣的事情来了:让我们通过观察学校在每个学生身上的支出与州外学费的比率,来看看谁真正从大学教育中获得了他们的美元价值。
colleges[‘expense ratio’] = colleges[‘Expend’]/(colleges[‘Outstate’])colleges.describe()[‘expense ratio’]
输出。图片作者。
WOAH!平均值小于 1 的事实告诉我,当把学费作为唯一的收入来源时,普通学校在学生身上是赔钱的。事实上, ~69% 的大学在学生身上的投资超过了他们收取的费用,这对大多数大学的未来来说不是一个好兆头。比例最高的学校大概是一些常春藤盟校吧?
colleges.loc[colleges[‘expense ratio’]==np.max(colleges[‘expense ratio’])]
输出。图片作者。
不对!最佳“物有所值”奖授予…鼓乐…伯明翰阿拉巴马大学,费用比率为 3.68 !然而,一种更愤世嫉俗的观点是,如果 UAB 在每个学生身上的花费是州外学费的近 4 倍,那么它可能不会在商业上持续太久…所以如果你是 2021 年的 HS 班,在他们还在运营的时候就进去,但要握紧你的钱包,因为那些打电话的学生会加班加点地抢你的捐款!
对于任何想知道的人来说,最大的小偷(费用比率最低的大学)是林登伍德学院,比率为 0.378。哎呀!
形象化
是时候创建一些数据可视化了!
让我们调查一下学费是如何随着学生人数以及学校是公立还是私立而变化的。我怀疑私立学校的学费更高,因为它们不像公立学校那样接受政府资助。全日制学生的数量可能会对这两种情况产生不利影响,因为更多的学生意味着更多的员工和更多的建筑,但一所大学可能会从针对如此大量学生的建筑项目的规模经济中受益。
plt.figure(figsize=(8,6))
sns.scatterplot(data=colleges,x='Outstate',y='F.Undergrad',hue='Private')
全日制本科生与州外学费的数量,按私立/公立区分。图片作者。
嗯… 非常 有趣的是,这所学校的本科生人数几乎完全与学费无关,这就引出了一个问题:这些钱去了哪里?让我们放大一下州外学费,看看毕业率。
sns.set_style('darkgrid')
g = sns.FacetGrid(colleges,hue='Private',palette='coolwarm',height=6,aspect=1.5)
g = g.map(plt.hist,'Outstate',bins=20,alpha=0.7)
plt.legend(labels=['Private','Public'])
私立和公立学校的州外学费。图片作者。
grid = sns.FacetGrid(colleges,hue='Private',palette='coolwarm',height=6,aspect=1.5)
grid = grid.map(plt.hist,'Grad.Rate',bins=20,alpha=0.7)
plt.legend(labels=['Private','Public'])
私立和公立学校的毕业率。图片作者。
不出所料,私立学校的州外学费更高,毕业率也更高——也许是因为如果一个学生在教育上投入那么多钱,他们的父母会想,“你最好完成学业…否则!”
现在回到那个毕业率高于 100%的学校……原来罪魁祸首是卡泽诺维亚学院。也许这个学校作弊,把双专业算作两次毕业?现实中这是没有意义的,所以我准备把这个毕业率改成 100%。
现在到了你们期待已久的时刻:K-均值聚类!
k-均值聚类创建
首先,我们将从 Scikit-learn 导入 KMeans ,Scikit-learn 是 Python 中最流行的机器学习包。K-means 的工作方式如下:
- 选择集群的数量。选择 2、4 还是 10 取决于具体问题的领域。在本例中,我们对公立和私立学校进行分类,因此我们将选择聚类数为 2。如果你正在分析一个群体中的基因变异,并且事先知道有 7 个已知的变异,那么你会选择 7 个。
- 将每个数据点随机分配到一个类别。
- 取每个类别中数据点的质心。对于那些认为质心是某种听起来很酷的小行星的人来说,它是多变量微积分——代表“每个星团中所有数据的平均值”对于 1-D 数据,您已经直观地理解了这一点:食品杂货的平均价格得到一个像 52 美元这样的数字。如果您计算杂货项目的平均价格和平均数量(二维),您将得到两个数字,如$52 和 2 个项目。在该数据集中,我们有 18 个要素,因此每个质心对应一组 18 维坐标。不,我们不会尝试去想象这个。
- 将每个数据点重新分配到最近质心对应的类别。
- 重复第 3 步和第 4 步,直到类别不再发生变化。
这里有一个很好的图片来帮助说明:
逐步 K-均值聚类,大点代表每个彩色聚类的质心。资料来源:第 389 页,《统计学习简介,作者:James,Witten,Hastie 和 Tibshirani。
用 Python 编写 K-means 模型非常简单,如下所示,模型生成的聚类可以用km.labels_
引用(不要忘了末尾的下划线!).
from sklearn.cluster import KMeans
km = KMeans(n_clusters=2)
km.fit(colleges.drop(‘Private’,axis=1))
评估
如果没有标签,就没有评估聚类的完美方法。然而,在这种情况下,学院数据集告诉我们每个学校是公立还是私立,因此我们可以使用这些标签交叉验证我们的 K-means 模型,以比较监督和非监督模型的总体性能。
评估机器学习模型性能的两个快速方法是查看一个 混淆矩阵 和一个 分类报告 。
def convertToCluster(cluster):
if cluster=='Yes':
return 1
else:
return 0
colleges['Cluster'] = colleges['Private'].apply(convertToCluster)from sklearn.metrics import classification_report,confusion_matrixprint(confusion_matrix(colleges['Cluster'],km.labels_))
print(classification_report(colleges['Cluster'],km.labels_))
来自 Scikit-learn 的无监督 K-means 模型的混淆矩阵和分类报告。图片作者。
如果你习惯于监督学习算法,你可能会看着这些结果想,“ 22%的准确率?! 这款就是垃圾!无监督模型到底有什么用?”但是请记住无监督的定义:该模型旨在从我们给它的混乱的 18 个特征中找出意义,没有标签。这并不是一件容易的事情,所以让我们把功劳归于 K-means 该归功的地方。
奖金部分比较无监督和有监督学习算法
让我们实际上比较我们刚刚得到的结果和监督学习模型的结果,以评估它们的性能(或者至少,将我们的期望设置为无监督学习的适当低水平😉).让我们来做一个经典的逻辑回归。
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegressionunis = colleges
X = unis.drop('Cluster',axis=1)
y = unis['Cluster']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)logmodel = LogisticRegression()
logmodel.fit(X_train,y_train)preds = logmodel.predict(X_test)print("Using K means clustering (unsupervised):\n")
print(confusion_matrix(colleges['Cluster'],km.labels_))
print(classification_report(colleges['Cluster'],km.labels_))print("Using logistic regression (supervised):\n")
print(confusion_matrix(y_test,preds))
print(classification_report(y_test,preds))
比较无监督和有监督学习模型的性能(在这种情况下是逻辑回归)。作者图片。
伙计们,看看标签的力量。使用一个简单的逻辑回归,一个监督学习模型,准确率从 22%飙升到 91% ,这可能可以通过选择另一个模型来提高。
希望你能开始明白 K 的意思是如何从混乱的数据中理出头绪的!使用探索性数据分析随意探索其他领域,看看您会发现什么!