如何量化时间序列之间的相似性

逝者如斯夫,不舍昼夜。时间不会停止,世界上的一切都在不断运动。抛开物理学或哲学的概念不提,几乎所有东西都可以被描述为一系列的事件。对数据更感兴趣的人来说,它们又可以被看做是一系列的测量,这就是我们所说的时间序列。一个时间序列可以包含关于生活中许多不同方面的各种信息,如每天的温度曲线、货币汇率和股票评级、飞机的速度和位置、海洋潮汐水平高度······

本篇博文中,我们将看看我们是如何决定哪些时间序列是相似的,哪些是不相似的——这是一个在开始解决总体问题之前,需要考虑的重要问题。在下图中,可以看到一组不同的时间序列,我们将使用不同的(不)相似度量来相互比较。这些序列都是对同一消费曲线(一个电表冬季一周的平均消费)的描述。然而,下面介绍的方法具有高度概括性,适用于多个行业的不同问题。

在原始数据的基础上,通过多种方法来判别几个不同情况下时间序列的相似性。

1.Euclidean and MAPE

欧氏距离指标(Euclidean distance metric)和平均绝对百分比误差(Mean Absolute Percentage Error,MAPE)。两者都是逐点计算两个时间序列的差异,这使得它们的计算速度非常快,但也限制了它们的适用性。


用Python实现如下。

import numpy as npdef calc_euclidean(actual, predic):return np.sqrt(np.sum((actual - predic) ** 2))def calc_mape(actual, predic):return np.mean(np.abs((actual - predic) / actual))

欧氏距离指标本质上是两个时间序列(向量)之间的向量规范,因此要求两个序列的长度相等。它的值可以从0(相同的时间序列)到无穷大,实际的输出值不仅取决于两个时间序列之间的相似性,还取决于它们的长度,即比较的点数量。

MAPE也要求两个序列的长度相等,它通过逐点取距离的平均值除以实际或预测值来进行归一化。值得注意的是,这个定义不是对称的,输出是不同的,取决于哪个时间序列被认为是实际值,哪个是预测值。这可以通过用每个逐点距离除以两个时间序列的平均值来解决。

那么,它们的效果如何呢?通过观察两个时间序列之间所围成的区域(在下图中以红色标出),两种方法在具有噪音的时间序列之间表现较好,这个区域相当小,但它们在其他情况下表现相对较差。绝对值的逐点比较根本无法确定偏移或缩放的曲线是相似的,因为没有考虑到邻近点。

2.Pearson correlation coefficient

皮尔逊相关系数在Python中的实现方法如下。

import numpy as npdef calc_correlation(actual, predic):a_diff = actual - np.mean(actual)p_diff = predic - np.mean(predic)numerator = np.sum(a_diff * p_diff)denominator = np.sqrt(np.sum(a_diff ** 2)) * np.sqrt(np.sum(p_diff ** 2))return numerator / denominator

它测量两个数据集之间的线性相关性,在我们的例子中是时间序列。同样,要比较的时间序列需要有相同的长度。结果在散点图中得到较好的体现:

  • 如果所有的点都形成一条上升直线,那么相关性很强,估值为1;
  • 如果它们形成一条下降直线,那么这两个序列被认为是完全反相关的(行为相反),估值为-1。
  • 较差的相关性表现为更分散的点云,其数值接近于0。

正如预期的那样,只要我们比较的仅是在数值维度上移动或缩放的曲线,相关性较强。添加噪音仍然会导致一个不错的相关性,但任何沿时间轴的移动都会迅速降低相关系数,因为这里和之前考虑的指标一样,只进行了逐点比较。总的来说,皮尔逊相关系数表现不错,能清楚地显示出比之前的方法更灵活。

3.Dynamic Time Warping

我们已经谈了很多关于不同时间序列之间的逐点比较是相当不灵活的,在两个稍有时间偏移的序列之间看不到很多相似之处。动态时间规整(Dynamic Time Warping,DTW)是一个解决此类问题的方法。

鲁汶大学DTAI研究小组提供了相关的开源方法(https://github.com/wannesm/dtaidistance)。DTW本质上是一种优化的方式,简单地尝试两个时间序列之间所有合理的时间映射(一个子集),并选择最佳匹配。

每个小方块表示两个时间序列的两个点之间的映射,深色表示映射的时间序列值之间的差异。

红线表示最佳匹配:该线的倾斜度和弯曲度越大,两个时间序列之间的扭曲度就越大。

绘制最佳映射图,我们可以看到两个序列之间的映射情况。

较大的数值表示较小的距离。显然,DTW能够识别类似序列的时间偏移和时间扭曲版本,但如果在数值维度上有任何偏移,它就会失效并返回较大的距离——毕竟理想扭曲路径的确定完全取决于绝对时间序列值。

4.Compression-based dissimilarity

前面提到的几种方法有一个缺点:计算量大。DTW在一定程度上降低了复杂性,但在长时间序列上执行仍然非常慢。接下来介绍的方法将具有一定的优势:基于压缩的异质性(Compression-based dissimilarity,CBD)。典型的压缩算法非常善于在任何数据中识别重复的模式,类似的时间序列同样应该包含很多类似的模式。

举个例子,假设我们要压缩的字符串是the gorilla is the king of the utility jungle, because the gorilla is data-driven。显然,the gorilla is的字符模式是一个反复出现的主题,将其存入字典,并将其出现的所有地方用一个键替换。令the gorilla is = 1,则原句变为1 the king of the utility jungle, because 1 data-driven

这样,字符串的长度从81个字符降至72个字符,压缩率为11%。现在,如果我们有第二个完全不同的字符串,它的压缩将有一个不同的字典,将这两个字符串连接起来,然后一起压缩,与单独压缩相比,不会有任何进一步的节省。然而,如果这两个字符串是相似的,那么把它们放在一起而不是分开压缩,就可以让我们共享我们用于压缩的字典,从而进一步节省消耗。

这正是CBD的意义所在:只需比较两个时间序列单独压缩的大小和它们串联的压缩大小。这使得处理大数据变得轻而易举!

首先,我们需要对我们想要压缩的数据进行编码。如果我们直接使用时间序列值本身,几乎不会有任何共享的模式,因为即使是非常相似的时间序列也会有稍微不同的值。

尽管两个序列描述的是类似的趋势,但它们的绝对值和值差是不同的,因此大多数压缩算法不会发现任何共享模式。我们可以通过对数值进行分档并给每个分档分配一个字母来解决这个问题——这就是著名的符号聚合估计算法(Symbolic Aggregate approXimation,SAX)。

我们可以根据我们的目的选择字母表的大小(这里是7)。一个SAX和CBD的基本实现如下所示。

import bz2
import numpy as npclass CompressionBasedDissimilarity(object):def __init__(self, n_letters=7):self.bins = Noneself.n_letters = n_lettersdef set_bins(self, bins):self.bins = binsdef sax_bins(self, all_values):bins = np.percentile(all_values[all_values > 0], np.linspace(0, 100, self.n_letters + 1))bins[0] = 0bins[-1] = 1e1000return bins@staticmethoddef sax_transform(all_values, bins):indices = np.digitize(all_values, bins) - 1alphabet = np.array([*("abcdefghijklmnopqrstuvwxyz"[:len(bins) - 1])])text = "".join(alphabet[indices])return str.encode(text)def calculate(self, m, n):if self.bins is None:m_bins = self.sax_bins(m)n_bins = self.sax_bins(n)else:m_bins = n_bins = self.binsm = self.sax_transform(m, m_bins)n = self.sax_transform(n, n_bins)len_m = len(bz2.compress(m))len_n = len(bz2.compress(n))len_combined = len(bz2.compress(m + n))return len_combined / (len_m + len_n)

在这段代码中,我们使用sax_bins()确定一个基于所有数值的分档,并将其设置为全局分档,以便与set_bins()一起使用,或者我们可以直接不设置分档,让它在我们调用calculate()时为每个时间序列单独计算。这两个选项之间的区别,最好的解释说明是简单地看一些示例结果(如下图所示)。同样,较大的值表示两个时间序列之间的相似性较小。

全局分档(CBD All)考虑到了绝对值。单独分档(CBD Sep)只考虑到了时间序列的形状,这样,scaled和value_offset时间序列被认为与原时间序列是非常相似的,time_offset也被确定为一个接近的时间序列。

5.Conclusion

到此,已经介绍了几种不同的判断时间序列相似度的指标,究竟哪一个效果最好呢?值得注意的是,不应该把不同的度量相互比较,因为它们赋予时间序列对的距离的绝对值只是相对于用相同度量计算的其他对的距离有意义。

每种方法在某些特定场景下都有着不错的效果,但没有哪种方法可以做到在所有场合下是通用的。没有一个单一的衡量标准可以确定所有的这些配对都是相似的。对于一个特定的问题,哪一个是最好的,取决于在给定的背景下“相似”的定义。

在预测用电的场景下,如果它们在同一时间有高峰和低谷的话,并且这些高峰和低谷的绝对振幅对我们来说并不重要,那么我们最好选择相关系数作为相似性指标。如果振幅对两个时间序列来说都非常重要,那么最好选择欧氏或MAPE指标。这三个指标也都能比较好地处理噪声。

DTW对于寻找时间偏移或规整的曲线之间的相似性非常有针对性,但是一旦两个要比较的时间序列的绝对值有任何偏移就会失效。鉴于它在计算复杂性方面有很大的缺陷,它可能只会在明确需要处理时间规整的情况下使用。例如鸟叫声的声音分析,不同的样本可能有不同的速度,直接逐点比较并不能识别相似性或识别模式。

CBD的好处是可以轻松处理不同长度的大型时间序列。通过为所有时间序列设置SAX分档,或者为每个时间序列单独设置,我们可以选择是否考虑绝对振幅。无论哪种情况,这个指标对于量化相似性是最有用的。噪声序列和所有其他序列之间的相似性总是被判断为非常低,正如人眼所见,噪声看起来和其他地方有很大的区别。

【数据分析】如何量化时间序列之间的相似性?相关推荐

  1. 【数据分析】利用时间序列聚类细分客户(以电力行业为背景)

    利用时间序列聚类细分客户(以电力行业为背景) 在上一篇博文--<如何量化时间序列之间的相似性>中,我们讨论了量化不同时间序列之间的相似性的各种方法.这篇博文,我将利用之前的知识--时间序列 ...

  2. 【python量化】如何分析两段时间序列之间的相关性

    作者:Andrew Chung 公众号:WealthQuant 链接: https://www.zhihu.com/question/23525783/answer/956912446 已获得作者授权 ...

  3. python数据分析与量化交易

    第一章-学习之前的认知 影响股价的因素 1.公司自身因素 2.心理因素 3.行业因素 4.经济因素 5.市场因素 6.政治因素 金融量化投资 量化投资的优势 1.避免主观情绪,人性弱点和认知偏差,选择 ...

  4. 大数据分析培训课程python时间序列ARIMAX模型

    什么是ARIMAX模型? 如果您已经阅读了有关用于估计时间序列数据的模型的系列大数据分析培训课程python时间序列ARIMAX模型教程,则您已经熟悉3种主要方法- 自回归,移动平均值和积分. 所有这 ...

  5. RDKit | 比较分子之间的相似性

    比较分子之间的相似性 获取结构和数据,将SMILES转换为RDKit分子对象,然后比较相似性. 1.导入python模块 import numpy as np import pandas as pd ...

  6. Python使用matplotlib可视化两个时间序列的交叉相关性图、交叉相关图显示了两个时间序列之间的滞后性(Cross Correlation plot)

    Python使用matplotlib可视化两个时间序列的交叉相关性图.交叉相关图显示了两个时间序列之间的滞后性(Cross Correlation plot) 目录

  7. python 计算时间重叠_Python基于时间信息(即时、间隔)计算项目之间的相似性...

    我想根据时间信息计算项目(0,1,2,3-.)之间的相似性.时间信息可以是时间即时(startdate).时间间隔(startdate.enddate)或null(NaT):请参阅下面的datafra ...

  8. 两个时间序列之间的DTW(Dynamic Time Warping)距离度量

    两个时间序列之间的DTW(Dynamic Time Warping)距离度量 flyfish 源码地址 https://github.com/wannesm/dtaidistance from dta ...

  9. python量化分析数据_Python数据分析_量化分析.pdf

    法律声明  本课件包括:演示文稿,示例,代码,题库,视频和声 音等,小象学院拥有完全知识产权的权利:只限于善意 学习者在本课程使用,不得在课程范围外向任何第三方 散播.任何其他人或机构不得盗版.复制 ...

最新文章

  1. Python:数据提取之JSON与JsonPATH
  2. linux文件传输常用方法
  3. data URI scheme及其应用
  4. php iso 8859 1 解码,关于php:Apache的默认编码是ISO-8859-1,但网站是UTF-8?
  5. Spring.NET学习笔记13——AOP的概念(基础篇) Level 200
  6. knn算法的最佳k值_KNN(k-NearestNeighbor)算法笔记
  7. Linux学习记录--ACL权限控制
  8. hql懒加载后判断对象是否存在_JPA数据懒加载LAZY和实时加载EAGER(二) - Mr.Simm - 博客园...
  9. ascii码01100001_ASCII 码对照表详解 - 文章
  10. C++控制台五子棋(带背景音乐)
  11. WCF学习(2)- 契约
  12. 怎么样在应用中实现自助报表功能
  13. Golang 字符串拼接
  14. Activity生命周期的三种状态
  15. Deep C (and C++) by Olve Maudal and Jon Jagger— 很不错的国外技术文章
  16. python里面bif是啥意思_什么是BIF?
  17. ★Sql Server 2012 数据库修复一般性错误修复
  18. NIST加密标准是什么意思?
  19. java 接口 练习题_JAVA 接口练习题
  20. (Google)谷歌笔试算法题:要求相邻的两个数都不小于或者不大于其本身的排序

热门文章

  1. 前端笔记87——clearTimeout
  2. 信息系统监理师题库_2018年下半年上午-信息系统监理师-软考(考试真题及答案-完整版)...
  3. 高速公路桥梁路段安全形势及管理对策研究
  4. 学习C语言第八天——switch语句
  5. asp.net core MVC程序通过AJAX上传文件报“400 Bad Request”
  6. Zookeeper开发者手册
  7. WebGL入门基本概念
  8. 在 IDEA 里斗个地主不过分吧!
  9. 如何用OleDbDataAdapter来对数据库进行操作?
  10. bbz10 android,苹果安卓审美疲劳重 淘回黑莓Z10体验