本文将展示数据聚类方法的重要用例,如何使用这些方法,并展示如何将这些方法作为降维技术使用。
首先,让我们讨论使这些方法如此受欢迎的用例。
客户分割
在线商店使用这种方法根据客户的购买模式、购买日期、年龄、收入等因素对客户进行聚类。这有助于商店更好地了解其客户,并帮助做出确保高盈利能力的决策。
为了更清楚地理解这一点,让我们举个例子。假设在根据购买日期和年龄对客户进行聚类后,我们发现年龄小于22岁的人在月底的消费较少。很可能大多数年龄小于22岁的人属于学生,而由于月底对大多数学生来说在经济上比较困难,他们可能不愿意去商店。因此,为了利用这一点,商店可以在月底推出折扣销售活动,这可能会比以前更频繁地吸引学生群体到商店,即使在月底也是如此。
如果商店没有使用聚类技术,可能就不会找到这个解决方案。
您可以在这个Tableau仪表盘中找到另一个聚类的例子。
用于数据分析
有时候,当我们单独分析数据的每个聚类时,我们会发现一些有趣的结果,而不是将整个数据一起分析。
作为降维技术
聚类方法也可以用作降维方法。我们将在文章末尾看到如何做到这一点。
半监督学习
我们可以通过首先对数据进行聚类,然后为每个聚类训练一个单独的模型来提高机器学习模型的准确性。
有时,当我们对分类问题使用半监督学习方法时,我们可能会在一个聚类中得到具有相同标签的实例。为了应对这种情况,我们可以创建一个模型,对每个输入的实例返回相同的标签。
您可以在我的一个项目中找到使用这种方法的例子。您可以在我的Github账户上查看该项目的源代码。
其他用例
除了上述提到的用例,聚类在图像分割等方面也非常有帮助。
现在让我们看一些最著名的聚类方法。
KMeans聚类
KMeans是目前最著名的聚类方法之一。该方法将尝试找出聚类的中心,然后将每个实例分配到其中一个中心。
让我们看看这个方法是如何工作的。
首先随机放置质心,然后为每个聚类分配标签。然后为每个实例分配一个标签。该实例将获得最接近它的聚类的标签。然后我们再次更新质心。完成后,我们将重复这个过程,直到质心没有任何变化。
尽管这个算法保证会收敛,但可能不会收敛到最优解。收敛到正确的解取决于质心的初始化,即算法开始时使用的质心的坐标。
解决这个问题的一个解决方案是多次使用不同的随机质心初始化运行算法,然后保留最佳解决方案。通过性能度量指标“惯性”来找到最佳解决方案。它基本上是每个实例与其最近质心之间的均方距离。
还有一个更受欢迎的解决方案。实现了这个解决方案的新算法称为KMeans++。
它引入了一种新的初始化步骤,倾向于选择彼此距离较远的质心,这一改进使得kMeans算法更不可能收敛到次优解。
有一些KMeans算法的变体,如加速的KMeans或小批量的KMeans等。
我们可以使用Scikit-Learn库的内置类轻松实现此算法。但是,真正的挑战是找到能够完美分离数据的最佳聚类数。
寻找最佳聚类数
有两种方法可以用来找到最佳聚类数:
- 使用肘部法和轮廓系数
- 使用kneed Python库
使用肘部法和轮廓系数
肘部法基本上是找到惯性和聚类数之间的曲线的肘部。我们希望惯性值既不太高也不太低。通常,这样的值位于惯性与聚类数曲线的肘部位置。
我们可以使用Scikit-learn库找到轮廓系数。轮廓系数的值介于-1和1之间。
轮廓系数接近1表示实例在自己的聚类内部,并且远离其他聚类。轮廓系数接近0表示它接近聚类边界。轮廓系数接近-1表示该实例可能被分配到错误的聚类。
因此,我们找到的最佳聚类数应使惯性既不太高也不太低,并且轮廓系数也应该是合理的。
让我们看看如何做到这一点。
## 必要的导入import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as sns## 读取数据"""为了演示,我们将使用一个简单的数据集,该数据集显示了服务员收到的小费金额,基于诸如星期几、用餐时间、总账单等因素。"""df = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/tips.csv')df.head()
## 绘制总账单 vs 小费plt.figure(figsize=(12,8))sns.set_style('darkgrid')plt.plot(df['total_bill'], df['tip'], 'bo')plt.xlabel('总账单')plt.ylabel('小费')plt.title('总账单与小费')
## 使用总账单、小费和人数列对数据进行聚类## 使用肘部法找到最佳聚类数"""为了绘制惯性和聚类数之间的关系,我们将对不同聚类数进行多次训练。对于这些模型中的每一个,我们将记录惯性。最后,我们将使用所有记录的惯性创建一个图表。"""from sklearn.cluster import KMeansinertia_list = [KMeans(n_clusters=i).fit(df[['total_bill','tip']]).inertia_ for i in range(2,10)]plt.figure(figsize=(12,8))sns.set_style('darkgrid')plt.plot(list(range(2,10)),inertia_list, 'rx', ls='solid')plt.xlabel('聚类数')plt.ylabel('惯性')plt.title('使用肘部法找到最佳聚类数')
根据图表,最佳聚类数应为4或5。这两个值的惯性既不太高也不太低。
## 使用轮廓系数找到最佳聚类数from sklearn.metrics import silhouette_score"""我们将使用类似的过程创建轮廓系数与聚类数之间的图表,就像我们在创建惯性与聚类数之间的图表时所做的那样。"""sil_score_list = []for i in range(2,10): kmeans = KMeans(n_clusters=i) kmeans.fit(df[['total_bill','tip']]) sil_score_list.append(silhouette_score(df[['total_bill','tip']],kmeans.labels_))plt.figure(figsize=(12,8))sns.set_style('darkgrid')plt.plot(list(range(2,10)),sil_score_list, 'mx', ls='solid')plt.xlabel('聚类数')plt.ylabel('轮廓系数')plt.title('使用轮廓系数找到最佳聚类数')
根据上面的两个图,当聚类数等于4时,我们将得到足够好的轮廓系数和较好的惯性值。因此,我们可以使用4个聚类来找出聚类的良好性能。
使用 Python 的 kneed 库
## 使用 kneed 库找到 kmeans 模型的最佳聚类数from kneed import KneeLocatorkn = KneeLocator(range(2,10), inertia_list, curve='convex',direction='decreasing')print(f"kmeans 模型的最佳聚类数:{kn.knee}")
kneed 库给出的聚类数与第一种方法给出的结果相同。现在让我们使用4个聚类来分离数据,然后可视化聚类。
## 使用聚类数等于4对数据进行聚类kmeans_final = KMeans(n_clusters=4)kmeans_final.fit(df[['total_bill','tip']])pred = kmeans_final.predict(df[['total_bill','tip']])## 为聚类标签创建一个新的列df['cluster'] = pred## 可视化聚类 ## 绘制聚类后的数据sns.set_style('whitegrid')sns.jointplot(x='total_bill', y='tip', data=df, hue='cluster',palette='coolwarm');
DBSCAN 聚类
该算法将高密度区域之间的低密度区域定义为连续的聚类。由于这一点,DBSCAN 聚类可以采用任何形状,而 KMeans 聚类只能产生凸形聚类。
DBSCAN 算法最重要的组成部分是核心样本的概念。核心样本是位于高密度区域的实例。因此,DBSCAN 算法中的聚类是靠近彼此的核心样本的集合以及靠近核心样本的非核心样本的集合。我们可以使用 Scikit-Learn 的 DBSCAN 类轻松实现 DBSCAN 算法。该类具有两个重要参数,min_samples 和 eps,它们定义了密集的含义。
对于每个实例,算法计算距离 eps 内有多少个实例。该区域被称为实例的 eps-邻域。
如果一个实例的 eps-邻域中至少有 min_samples 个实例(包括自身),则它被认为是一个核心实例。邻域中的所有实例都属于同一个聚类。该邻域可能包括其他核心实例,因此来自单个聚类的核心实例之间会形成一长串相邻的核心实例。
让我们看看如何使用 Scikit-Learn 类对与 KMeans 聚类相同的数据执行聚类。
from sklearn.cluster import DBSCAN## 进行聚类dbscan_pred = DBSCAN(eps=2, min_samples=5).fit_predict(df[['total_bill','tip']])df['DBSCAN_Pred'] = dbscan_pred## 绘制聚类后的数据sns.set_style('whitegrid')sns.jointplot(x='total_bill', y='tip', data=df, hue='DBSCAN_Pred',palette='coolwarm');
请注意,噪音数据样本被赋予标签 -1。
还有许多其他的聚类算法,如凝聚聚类、均值漂移聚类、亲和传播聚类、谱聚类等。
现在我们已经学会了如何实现聚类算法,让我们看看如何将这些方法用于降维问题。
使用聚类作为降维方法
一旦完成数据聚类,我们可以找出每个实例与每个聚类的关联度。
亲和度是衡量每个实例适应不同聚类的程度。
一旦我们有了每个实例的亲和度向量,我们就可以用其亲和度向量替换原始实例。如果亲和度向量是k维的,则数据的新维度将只有k个。
无论原始数据有多少维,经过聚类后,数据的维度将等于将数据划分为的聚类数。
让我们使用一个鸢尾花数据集进行演示。
## 必要的导入import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.model_selection import train_test_splitfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.metrics import confusion_matrix## 读取数据集df1 = pd.read_csv('数据路径')## 删除不必要的特征df1.drop('Id',axis=1,inplace=True)## 将数据划分为自变量和因变量X = df1.drop('Species',axis=1)y = df1['Species']## 将数据划分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y,random_state=238, test_size=0.33)## 首先直接训练模型,不使用任何降维技术## 在这里,我们使用随机森林分类器进行训练rfc = RandomForestClassifier(n_estimators=250,n_jobs=-1,max_depth=3)rfc.fit(X_train, y_train)rfc_predictions = rfc.predict(X_test)## 检查预测的混淆矩阵from sklearn.metrics import confusion_matrixmatrix = confusion_matrix(y_test, rfc_predictions)print("在应用任何降维方法之前创建的模型的混淆矩阵:\n")confusion_matrix(y_test,rfc_predictions, labels = df1['Species'].unique())
## 必要的导入from sklearn.cluster import KMeans## 创建3个聚类k = 3kmeans = KMeans(n_clusters=k)kmeans.fit(X_train)X_train_new = kmeans.transform(X_train)## 现在使用这些值作为新的训练集rfc_new = RandomForestClassifier(max_depth=3,n_jobs=-1,n_estimators=250)rfc_new.fit(X_train_new,y_train)rfc_new_predictions = rfc_new.predict(kmeans.transform(X_test))## 检查替换特征向量为亲和度向量后的预测混淆矩阵print("在替换特征向量为亲和度向量后创建的模型的混淆矩阵:\n")confusion_matrix(y_test,rfc_new_predictions, labels = df1['Species'].unique())
我们可以看到,与之前相比,有2个更多的不准确预测。这是因为降维方法会丢失一些信息。然而,只有2个不准确的预测仍然表明高水平的准确性。
希望你喜欢这篇文章。如果对文章有任何想法,请告诉我。非常感谢任何建设性的反馈。请在LinkedIn上联系我。祝你有美好的一天!