使用轮廓分数提升时间序列聚类的表现

news2024/11/18 16:48:48

我们将使用轮廓分数和一些距离指标来执行时间序列聚类实验,并且进行可视化

让我们看看下面的时间序列:

如果沿着y轴移动序列添加随机噪声,并随机化这些序列,那么它们几乎无法分辨,如下图所示-现在很难将时间序列列分组为簇:

上面的图表是使用以下脚本创建的:

 # Import necessary libraries
 import os
 import pandas as pd
 import numpy as np
 
 # Import random module with an alias 'rand'
 import random as rand
 from scipy import signal
 
 # Import the matplotlib library for plotting
 import matplotlib.pyplot as plt
 
 # Generate an array 'x' ranging from 0 to 5*pi with a step of 0.1
 x = np.arange(0, 5*np.pi, 0.1)
 
 # Generate square, sawtooth, sin, and cos waves based on 'x'
 y_square = signal.square(np.pi * x)
 y_sawtooth = signal.sawtooth(np.pi * x)
 y_sin = np.sin(x)
 y_cos = np.cos(x)
 
 # Create a DataFrame 'df_waves' to store the waveforms
 df_waves = pd.DataFrame([x, y_sawtooth, y_square, y_sin, y_cos]).transpose()
 
 # Rename the columns of the DataFrame for clarity
 df_waves = df_waves.rename(columns={0: 'time',
                                     1: 'sawtooth',
                                     2: 'square',
                                     3: 'sin',
                                     4: 'cos'})
 
 # Plot the original waveforms against time
 df_waves.plot(x='time', legend=False)
 plt.show()
 
 # Add noise to the waveforms and plot them again
 for col in df_waves.columns:
     if col != 'time':
         for i in range(1, 10):
             # Add noise to each waveform based on 'i' and a random value
             df_waves['{}_{}'.format(col, i)] = df_waves[col].apply(lambda x: x + i + rand.random() * 0.25 * i)
 
 # Plot the waveforms with added noise against time
 df_waves.plot(x='time', legend=False)
 plt.show()

现在我们需要确定聚类的基础。这里有两种方法:

把接近于一组的波形分组——较低欧几里得距离的波形将聚在一起。

把看起来相似的波形分组——它们有相似的形状,但欧几里得距离可能不低

距离度量

一般来说,我们希望根据形状对时间序列进行分组,对于这样的聚类-可能希望使用距离度量,如相关性,这些度量或多或少与波形的线性移位无关。

让我们看看上面定义的带有噪声的波形对之间的欧几里得距离和相关性的热图:

可以看到欧几里得距离对波形进行分组是很困难的,因为任何一组波形对的模式都是相似的。例如,除了对角线元素外,square & cos之间的相关形状与square和square之间的相关形状非常相似

所有的形状都可以很容易地使用相关热图组合在一起——因为类似的波形具有非常高的相关性(sin-sin对),而像sin和cos这样的波形几乎没有相关性。

轮廓分数

通过上面热图和分析,根据高相关性分配组看起来是一个好主意,但是我们如何定义相关阈值呢?看起来像一个迭代过程,容易出现不准确和大量的人工工作。

在这种情况下,我们可以使用轮廓分数(Silhouette score),它为执行的聚类分配一个分数。我们的目标是使轮廓分数最大化。

轮廓分数(Silhouette Score)是一种用于评估聚类质量的指标,它可以帮助你确定数据点是否被正确地分配到它们的簇中。较高的轮廓分数表示簇内数据点相互之间更加相似,而不同簇之间的数据点差异更大,这通常是良好的聚类结果。

轮廓分数的计算方法如下:

  1. 对于每个数据点 i,计算以下两个值:- a(i):数据点 i 到同一簇中所有其他点的平均距离(簇内平均距离)。- b(i):数据点 i 到与其不同簇中的所有簇的平均距离,取最小值(最近簇的平均距离)。
  2. 然后,计算每个数据点的轮廓系数 s(i),它定义为:s(i) = \frac{b(i) - a(i)}{\max{a(i), b(i)}}
  3. 最后,计算整个数据集的轮廓分数,它是所有数据点的轮廓系数的平均值:\text{轮廓分数} = \frac{1}{N} \sum_{i=1}^{N} s(i)

其中,N 是数据点的总数。

轮廓分数的取值范围在 -1 到 1 之间,具体含义如下:

  • 轮廓分数接近1:表示簇内数据点相似度高,不同簇之间的差异很大,是一个好的聚类结果。
  • 轮廓分数接近0:表示数据点在簇内的相似度与簇间的差异相当,可能是重叠的聚类或者不明显的聚类。
  • 轮廓分数接近-1:表示数据点更适合分配到其他簇,不同簇之间的差异相比簇内差异更小,通常是一个糟糕的聚类结果。

一些重要的知识点:

在所有点上的高平均轮廓分数(接近1)表明簇的定义良好且明显。

低或负的平均轮廓分数(接近-1)表明重叠或形成不良的集群。

0左右的分数表示该点位于两个簇的边界上。

聚类

现在让我们尝试对时间序列进行分组。我们已经知道存在四种不同的波形,因此理想情况下应该有四个簇。

欧氏距离

 pca = decomposition.PCA(n_components=2)
 pca.fit(df_man_dist_euc)
 df_fc_cleaned_reduced_euc = pd.DataFrame(pca.transform(df_man_dist_euc).transpose(), 
                                               index = ['PC_1','PC_2'],
                                               columns = df_man_dist_euc.transpose().columns)
 
 index = 0
 range_n_clusters = [2, 3, 4, 5, 6, 7, 8]
 
 # Iterate over different cluster numbers
 for n_clusters in range_n_clusters:
     # Create a subplot with silhouette plot and cluster visualization
     fig, (ax1, ax2) = plt.subplots(1, 2)
     fig.set_size_inches(15, 7)
 
     # Set the x and y axis limits for the silhouette plot
     ax1.set_xlim([-0.1, 1])
     ax1.set_ylim([0, len(df_man_dist_euc) + (n_clusters + 1) * 10])
 
     # Initialize the KMeans clusterer with n_clusters and random seed
     clusterer = KMeans(n_clusters=n_clusters, n_init="auto", random_state=10)
     cluster_labels = clusterer.fit_predict(df_man_dist_euc)
 
     # Calculate silhouette score for the current cluster configuration
     silhouette_avg = silhouette_score(df_man_dist_euc, cluster_labels)
     print("For n_clusters =", n_clusters, "The average silhouette_score is :", silhouette_avg)
     sil_score_results.loc[index, ['number_of_clusters', 'Euclidean']] = [n_clusters, silhouette_avg]
     index += 1
     
     # Calculate silhouette values for each sample
     sample_silhouette_values = silhouette_samples(df_man_dist_euc, cluster_labels)
     
     y_lower = 10
 
     # Plot the silhouette plot
     for i in range(n_clusters):
         # Aggregate silhouette scores for samples in the cluster and sort them
         ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
         ith_cluster_silhouette_values.sort()
 
         # Set the y_upper value for the silhouette plot
         size_cluster_i = ith_cluster_silhouette_values.shape[0]
         y_upper = y_lower + size_cluster_i
 
         color = cm.nipy_spectral(float(i) / n_clusters)
 
         # Fill silhouette plot for the current cluster
         ax1.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7)
 
         # Label the silhouette plot with cluster numbers
         ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
         y_lower = y_upper + 10  # Update y_lower for the next plot
 
     # Set labels and title for the silhouette plot
     ax1.set_title("The silhouette plot for the various clusters.")
     ax1.set_xlabel("The silhouette coefficient values")
     ax1.set_ylabel("Cluster label")
 
     # Add vertical line for the average silhouette score
     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])
 
     # Plot the actual clusters
     colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
     ax2.scatter(df_fc_cleaned_reduced_euc.transpose().iloc[:, 0], df_fc_cleaned_reduced_euc.transpose().iloc[:, 1],
                 marker=".", s=30, lw=0, alpha=0.7, c=colors, edgecolor="k")
 
     # Label the clusters and cluster centers
     centers = clusterer.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")
 
     # Set labels and title for the cluster visualization
     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")
 
     # Set the super title for the whole plot
     plt.suptitle("Silhouette analysis for KMeans clustering on sample data with n_clusters = %d" % n_clusters,
                  fontsize=14, fontweight="bold")
 
 plt.savefig('sil_score_eucl.png')
 plt.show()

可以看到无论分成多少簇,数据都是混合的,并不能为任何数量的簇提供良好的轮廓分数。这与我们基于欧几里得距离热图的初步评估的预期一致

相关性

 pca = decomposition.PCA(n_components=2)
 pca.fit(df_man_dist_corr)
 df_fc_cleaned_reduced_corr = pd.DataFrame(pca.transform(df_man_dist_corr).transpose(), 
                                               index = ['PC_1','PC_2'],
                                               columns = df_man_dist_corr.transpose().columns)
 
 index=0
 range_n_clusters = [2,3,4,5,6,7,8]
 for n_clusters in range_n_clusters:
     # Create a subplot with 1 row and 2 columns
     fig, (ax1, ax2) = plt.subplots(1, 2)
     fig.set_size_inches(15, 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(df_man_dist_corr) + (n_clusters + 1) * 10])
 
     # Initialize the clusterer with n_clusters value and a random generator
     # seed of 10 for reproducibility.
     clusterer = KMeans(n_clusters=n_clusters, n_init="auto", random_state=10)
     cluster_labels = clusterer.fit_predict(df_man_dist_corr)
 
     # 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(df_man_dist_corr, cluster_labels)
     print(
         "For n_clusters =",
         n_clusters,
         "The average silhouette_score is :",
         silhouette_avg,
     )
     sil_score_results.loc[index,['number_of_clusters','corrlidean']] = [n_clusters,silhouette_avg]
     index=index+1
     
     sample_silhouette_values = silhouette_samples(df_man_dist_corr, 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(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(
         df_fc_cleaned_reduced_corr.transpose().iloc[:, 0], 
         df_fc_cleaned_reduced_corr.transpose().iloc[:, 1], marker=".", s=30, lw=0, alpha=0.7, c=colors, edgecolor="k"
     )
     
 #     for i in range(len(df_fc_cleaned_cleaned_reduced.transpose().iloc[:, 0])):
 #                         ax2.annotate(list(df_fc_cleaned_cleaned_reduced.transpose().index)[i], 
 #                                      (df_fc_cleaned_cleaned_reduced.transpose().iloc[:, 0][i], 
 #                                       df_fc_cleaned_cleaned_reduced.transpose().iloc[:, 1][i] + 0.2))
         
     # 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(
         "Silhouette analysis for KMeans clustering on sample data with n_clusters = %d"
         % n_clusters,
         fontsize=14,
         fontweight="bold",
     )
 
 plt.show()

当选择的簇数为4时,我们可以清楚地看到分离的簇,其他结果通常比欧氏距离要好得多。

欧几里得距离与相关廓形评分的比较

轮廓分数表明基于相关性的距离矩阵在簇数为4时效果最好,而在欧氏距离的情况下效果就不那么明显了结论

总结

在本文中,我们研究了如何使用欧几里得距离和相关度量执行时间序列聚类,并观察了这两种情况下的结果如何变化。如果我们在评估聚类时结合Silhouette,我们可以使聚类步骤更加客观,因为它提供了一种很好的直观方式来查看聚类的分离情况。

https://avoid.overfit.cn/post/939876c1609140ac803b86209d8ee7ab

作者:Girish Dev Kumar Chaurasiya

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1099523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM - Springboot - MyBatis-Plus 全栈体系(三十)

第七章 MyBatis-Plus MyBatis-Plus 高级用法:最优化持久层开发 一、MyBatis-Plus 快速入门 1. 简介 版本:3.5.3.1MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在 MyBa…

vscode终端显示多个虚拟环境

问题:某次突然发现vscode前面出现多个虚拟环境,即(.conda)(base),其中(base)是默认自动激活的,但是(.conda)不是,而且我退…

上海亚商投顾:沪指震荡调整跌 减肥药、华为概念股持续活跃

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 市场情绪 沪指上个交易日低开后震荡调整,深成指、创业板指盘中跌超1%,宁德时代一度跌超3%&#xff…

新增Node.js运行环境、新增系统缓存清理功能,1Panel开源面板v1.7.0发布

2023年10月16日,现代化、开源的Linux服务器运维管理面板1Panel正式发布v1.7.0版本。 在这个版本中,1Panel新增Node.js运行环境;新增系统缓存清理功能;应用安装时支持选择远程数据库。此外,我们进行了40多项功能更新和…

GitHub验证的2FA

一、 起因: GitHub需要双重身份验证 (2FA) 是登录网站或应用时使用的额外保护层。启用 2FA 时,必须使用您的用户名和密码登录,并提供另一种只有您知道或可以访问的身份验证形式。 二、解决: 2.1 这里使用chrome的身份验证插件进…

[Tkinter 教程08] Canvas 图形绘制

python - [译][Tkinter 教程08] Canvas 图形绘制 - 个人文章 - SegmentFault 思否 一、简介 Canvas 为 Tkinter 提供了绘图功能. 其提供的图形组件包括 线形, 圆形, 图片, 甚至其他控件. Canvas 控件为绘制图形图表, 编辑图形, 自定义控件提供了可能. 在第一个例子里, …

基于深度优先搜索的图遍历

这里写目录标题 基于深度优先搜索的无向图遍历算法流程图Python实现Java实现 基于深度优先搜索的有向图遍历Python实现 基于深度优先搜索的无向图遍历 使用深度优先搜索遍历无向图,将无向图用邻接表存储: 算法流程图 初始化起点 source,当…

2023_Spark_实验十四:SparkSQL入门操作

1、将emp.csv、dept.csv文件上传到分布式环境,再用 hdfs dfs -put dept.csv /input/ hdfs dfs -put emp.csv /input/ 将本地文件put到hdfs文件系统的input目录下 2、或者调用本地文件也可以。区别:sc.textFile("file:///D:\\temp\\emp.csv&qu…

苹果10月24日推送iOS 17.1:修复iPhone 12辐射超标问题 信号会更差

前段时间在iPhone 15系列发布的当天,法国突然宣布iPhone 12不能在该国销售,理由是iPhone 12超过了当地无线电频率暴露的法定范围。 根据法国监管机构ANFR(国家频率管理局)发布的最新消息,苹果将会在10月24日推送iOS 17.1正式版,届…

Prometheus的Pushgateway快速部署及使用

prometheus-pushgateway安装 一. Pushgateway简介 Pushgateway为Prometheus整体监控方案的功能组件之一,并做于一个独立的工具存在。它主要用于Prometheus无法直接拿到监控指标的场景,如监控源位于防火墙之后,Prometheus无法穿透防火墙&…

自动驾驶:控制算法概述

自动驾驶:控制算法概述 常见控制算法PID算法LQR算法MPC算法 自动驾驶控制算法横向控制纵向控制 参考文献 常见控制算法 PID算法 PID(Proportional-Integral-Derivative)控制是一种经典的反馈控制算法,通常用于稳定性和响应速度要…

MATLAB-文件自动批量读取文件,并按文件名称或时间顺序进行数据处理

我在处理文件数据时,发现一个一个文件处理效率太低,因此学习了下MATLAB中自动读取特定路径下文件信息的程序,并根据读取信息使用循环进行数据处理,提高效率,在此分享给大家这段代码并给予一些说明,希望能为…

.Net Core 6 运行环境手动安装流程

安装.NET Core 6 概述 在开始之前,我们首先需要了解一下整个安装过程的流程。下面的表格将展示安装.NET Core 6的步骤以及每一步需要做的事情。 步骤 动作 说明 1 下载.NET Core 6 SDK 从官方网站下载.NET Core 6 SDK安装包 2 安装.NET Core 6 SDK …

AXURE RP EXTENSION For Chrome 安装

在浏览器上输入地址:chrome://extensions/ 打开图片中这个选项,至此你就能通过index.html访问

【设计模式-1】UML和设计原则

说明:设计模式(Design Pattern)对于软件开发,简单来说,就是软件开发的套路,固定模板。在学习设计模式之前,需要首先学习UML(Unified Modeling Language,统一建模语言&…

BAT026:删除当前目录及子目录下的空文件夹

引言:编写批处理程序,实现批量删除当前目录及子目录下的空文件夹。 一、新建Windows批处理文件 参考博客: CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132137544 二、写入批处理代码 1.右键新建的批处理文件,点击【编辑…

MinIO (一)安装并生成windows服务

最近公司要搞文件服务器,所以就研究了下MinIO,在这里做个笔记,研究的不深,记录一下基本使用功能,用到了哪些功能就研究哪些,里面的很多功能没用到。 MinIO 文件在线管理系统 更多详细介绍请参考 官网&am…

微信小程序仿苹果负一屏由弱到强的高斯模糊

进入下面小程序可以体验效果&#xff0c;然后进入更多。查看模糊效果 一、创建小程序组件 二、代码 wxml: <view class"topBar-15"></view> <view class"topBar-14"></view> <view class"topBar-13"></view&…

4-k8s-部署springboot项目简单实践

文章目录 一、部署原理图二、部署实践 一、部署原理图 部门一般都有一个属于自己的私服gitlab服务器&#xff0c;由开发者开发代码&#xff0c;然后上传到私服gitlab然后使用调度工具&#xff0c;如jenkins&#xff0c;去gitlab拉去代码&#xff0c;编译打包&#xff0c;最后得…

Web3D虚拟人制作简明指南

如何在线创建虚拟人? 虚拟人,也称为数字化身、虚拟助理或虚拟代理,是一种可以通过各种在线平台与用户进行逼真交互的人工智能人。 在线创建虚拟人变得越来越流行,因为它为个人和企业带来了许多好处。 通过虚拟助理或代理,您可以以更具吸引力和个性化的方式与客户或受众进…