Dai0v0
638 words
3 minutes
计算曲线趋势相似度的方法

要计算两条曲线之间趋势的相似程度,具体来说:

对于两个函数(输出是一维的,输入不一定),如果在各个区间上的单调性排列相同,则认为是趋势相似的,例如 y=x^2 和 y=3x^2 就是相似的,而 y=x^2 和 y=-x^2 是不相似的

这里要求能判断变化快慢不同和截距不同的函数是相似的,对相位不同不做要求

DTW#

Dynamic Time Warping,动态时间规整

DTW 可以计算两个时间序列的相似度,尤其适用于不同长度、不同节奏的时间序列(比如不同的人读同一个词的音频序列)。 DTW 将两个序列拉伸放缩,使得两个序列的形态尽可能的一致,得到最大可能的相似度。

实现上,DTW 是用动态规划计算一个「最短路径问题」:

有矩阵 Dnm(n 是序列 A 的长度,m 是序列 B 的长度),Dij 是 Ai 和 Bj 的距离,现在从左上角 D11 开始,要到达右下角 Dnm,每次只能往右/下/右下方向前进。求最短路径?

表现在图像,最后 DTW 会尽可能把相似的点联系起来,这是欧氏距离无法直接做到的。

欧氏距离和DTW

实现算法如下:

def dtw_similarity(s1, s2):

    def ed(m, n):
        return np.sqrt(np.sum((m - n) ** 2))

    a = s1 / np.linalg.norm(s1)
    b = s2 / np.linalg.norm(s2)
    D = np.zeros((len(a)+1, len(b)+1))
    D[1:, 1:] = ed(a, b)
    for i in range(1, len(a)+1):
        for j in range(1, len(b)+1):
            D[i][j] += min(D[i-1, j], D[i, j-1], D[i-1, j-1])
    return D[-1][-1]

这里的代码只实现了两个序列之间的比较,也就是默认输入是一维的。

样条插值法#

这种方法的思路就是先假定输入的函数符合某种分布,然后用分布去拟合得到特征系数,将「曲线趋势的相似度」转换为「特征系数的相似度」,后者是向量,可以用余弦相似度之类的方法实现。

多项式拟合#

from scipy.optimize import curve_fit

def curve_similarity(x, y1, y2):  
    # 定义模型函数
    def f(x, a, b, c, d, e):
        return a * x**4 + b * x**3 + c * x**2 + d * x + e

    def cosine_similarity(a,b):
        return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

    params1, cov1 = curve_fit(f, x, y1)
    params2, cov2 = curve_fit(f, x, y2)
    return cosine_similarity(params1, params2)

广义加性模型拟合#

import pygam

def gam_similarity(x, y1, y2):

    def cosine_similarity(a,b):
        return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

    model = pygam.LinearGAM(n_splines=10) #样条参数为 10
    
    model.fit(x, y1)
    params1 = []
    for i,term in enumerate(model.terms):  
        if term.isintercept:
            continue
        params1.extend(model.partial_dependence(term=i))
    
    model.fit(x, y2)
    params2 = []
    for i,term in enumerate(model.terms):
        if term.isintercept:
            continue
        params2.extend(model.partial_dependence(term=i))
    return cosine_similarity(params1, params2)

样条函数

样条函数 plt.plot(gam.partial_dependence(term=i))
计算曲线趋势相似度的方法
https://u1805.github.io/posts/curve-similarity/
Author
Dai0v0
Published at
2023-07-22