【问题标题】:Testing similarity of several datasets by producing a cross-correlation matrix通过生成互相关矩阵来测试多个数据集的相似性
【发布时间】:2017-08-08 10:32:51
【问题描述】:

我正在尝试比较几个数据集并基本上测试它们是否显示相同的特征,尽管此特征可能会被转移、反转或减弱。 下面是一个非常简单的例子:

A = np.array([0., 0, 0, 1., 2., 3., 4., 3, 2, 1, 0, 0, 0])
B = np.array([0., 0, 0, 0, 0, 1, 2., 3., 4, 3, 2, 1, 0])
C = np.array([0., 0, 0, 1, 1.5, 2, 1.5, 1, 0, 0, 0, 0, 0])
D = np.array([0., 0, 0, 0, 0, -2, -4, -2, 0, 0, 0, 0, 0])
x = np.arange(0,len(A),1)

我认为最好的方法是将这些信号归一化并获得绝对值(现阶段它们的衰减对我来说并不重要,我对位置感兴趣......但我可能错了,所以我也将欢迎有关此概念的想法)并计算它们重叠的区域。我正在跟进this answer - 该解决方案看起来非常优雅和简单,但我可能执行错误。

def normalize(sig):
    #ns = sig/max(np.abs(sig))
    ns = sig/sum(sig)
    return ns
a = normalize(A)
b = normalize(B)
c = normalize(C)
d = normalize(D)

然后看起来像这样:

但是,当我尝试从答案中实施解决方案时,我遇到了问题。

for c1,w1 in enumerate([a,b,c,d]):
    for c2,w2 in enumerate([a,b,c,d]):
        w1 = np.abs(w1)
        w2 = np.abs(w2)
        M[c1,c2] = integrate.trapz(min(np.abs(w2).any(),np.abs(w1).any()))
print M

产生TypeError: 'numpy.bool_' object is not iterableIndexError: list assignment index out of range。但我只包含了.any(),因为没有它们,我得到的是ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

编辑 - 新 (感谢@Kody King)

现在的新代码是:

M = np.zeros([4,4])
SH = np.zeros([4,4])
for c1,w1 in enumerate([a,b,c,d]):
    for c2,w2 in enumerate([a,b,c,d]):
        crossCorrelation = np.correlate(w1,w2, 'full')
        bestShift = np.argmax(crossCorrelation)

        # This reverses the effect of the padding.
        actualShift = bestShift - len(w2) + 1
        similarity = crossCorrelation[bestShift]

        M[c1,c2] = similarity
        SH[c1,c2] = actualShift
M = M/M.max()
print M, '\n', SH

还有输出:

[[ 1.          1.          0.95454545  0.63636364]
 [ 1.          1.          0.95454545  0.63636364]
 [ 0.95454545  0.95454545  0.95454545  0.63636364]
 [ 0.63636364  0.63636364  0.63636364  0.54545455]] 
[[ 0. -2.  1.  0.]
 [ 2.  0.  3.  2.]
 [-1. -3.  0. -1.]
 [ 0. -2.  1.  0.]]

移位矩阵现在看起来不错,但实际的相关矩阵却不行。我真的很困惑,最低的相关值是用于将 d 与自身相关联。我现在想要实现的是:


编辑 - 更新

按照建议,我使用了推荐的归一化公式(将信号除以其总和),但问题没有解决,只是颠倒过来。现在 d 与 d 的相关性为 1,但所有其他信号都与自身不相关。

新输出:

[[ 0.45833333  0.45833333  0.5         0.58333333]
 [ 0.45833333  0.45833333  0.5         0.58333333]
 [ 0.5         0.5         0.57142857  0.66666667]
 [ 0.58333333  0.58333333  0.66666667  1.        ]] 
[[ 0. -2.  1.  0.]
 [ 2.  0.  3.  2.]
 [-1. -3.  0. -1.]
 [ 0. -2.  1.  0.]]

  1. 在将信号与其自身相关时,相关值应最高(即在主对角线上具有最高值)。
  2. 要获得介于 0 和 1 之间的相关值,因此,我会在主对角线上使用 1,而在其他位置使用其他数字 (0.x)。

我希望 M = M/M.max() 能完成这项工作,但前提是条件不存在。 1 已实现,但目前尚未实现。

【问题讨论】:

    标签: python scipy


    【解决方案1】:

    正如 ssm 所说,numpy 的相关函数可以很好地解决这个问题。您提到您对该职位感兴趣。相关函数还可以帮助您判断一个序列与另一个序列的偏移距离。

    import numpy as np
    
    def compare(a, b):
        # 'full' pads the sequences with 0's so they are correlated
        # with as little as 1 actual element overlapping.
        crossCorrelation = np.correlate(a,b, 'full')
        bestShift = np.argmax(crossCorrelation)
    
        # This reverses the effect of the padding.
        actualShift = bestShift - len(b) + 1
        similarity = crossCorrelation[bestShift]
    
        print('Shift: ' + str(actualShift))
        print('Similatiy: ' + str(similarity))
        return {'shift': actualShift, 'similarity': similarity}
    
    print('\nExpected shift: 0')
    compare([0,0,1,0,0], [0,0,1,0,0])
    print('\nExpected shift: 2')
    compare([0,0,1,0,0], [1,0,0,0,0])
    print('\nExpected shift: -2')
    compare([1,0,0,0,0], [0,0,1,0,0])
    

    编辑:

    您需要在关联每个序列之前对其进行归一化,否则较大的序列将与所有其他序列具有非常高的相关性。

    互相关的一个性质是:

    因此,如果您通过将每个序列除以其总和来进行归一化,则相似度将始终介于 0 和 1 之间。

    我建议你不要取序列的绝对值。这会改变形状,而不仅仅是规模。例如 np.abs([1, -2]) == [1, 2]。规范化已经确保序列大部分是正数并且加起来为 1。

    第二次编辑:

    我意识到了。将信号视为向量。归一化向量总是有一个最大的点积。互相关只是在不同班次计算的点积。如果像向量一样对信号进行归一化(s 除以 sqrt(s dot s)),则自相关将始终为最大且为 1。

    import numpy as np
    
    def normalize(s):
        magSquared = np.correlate(s, s) # s dot itself
        return s / np.sqrt(magSquared)
    
    a = np.array([0., 0, 0, 1., 2., 3., 4., 3, 2, 1, 0, 0, 0])
    b = np.array([0., 0, 0, 0, 0, 1, 2., 3., 4, 3, 2, 1, 0])
    c = np.array([0., 0, 0, 1, 1.5, 2, 1.5, 1, 0, 0, 0, 0, 0])
    d = np.array([0., 0, 0, 0, 0, -2, -4, -2, 0, 0, 0, 0, 0])
    
    a = normalize(a)
    b = normalize(b)
    c = normalize(c)
    d = normalize(d)
    
    M = np.zeros([4,4])
    SH = np.zeros([4,4])
    for c1,w1 in enumerate([a,b,c,d]):
        for c2,w2 in enumerate([a,b,c,d]):
            # Taking the absolute value catches signals which are flipped.
            crossCorrelation = np.abs(np.correlate(w1, w2, 'full'))
            bestShift = np.argmax(crossCorrelation)
    
            # This reverses the effect of the padding.
            actualShift = bestShift - len(w2) + 1
            similarity = crossCorrelation[bestShift]
    
            M[c1,c2] = similarity
            SH[c1,c2] = actualShift
    print(M, '\n', SH)
    

    输出:

    [[ 1.          1.          0.97700842  0.86164044]
    [ 1.          1.          0.97700842  0.86164044]
    [ 0.97700842  0.97700842  1.          0.8819171 ]
    [ 0.86164044  0.86164044  0.8819171   1.        ]]
    [[ 0. -2.  1.  0.]
    [ 2.  0.  3.  2.]
    [-1. -3.  0. -1.]
    [ 0. -2.  1.  0.]]
    

    【讨论】:

    • 谢谢你的回答,肯定越来越清楚了,但还不是100%。当我在上面的示例中尝试并相互关联时,我在矩阵中得到了意想不到的结果。我希望最大相关性总是在主对角线上,即当我将数组与自身相关时。但相关值沿对角线变化,而且变化更令人费解——它们都显示在对角线上的 -1 变化。
    • 糟糕,当我复制代码时,我不小心删除了“actualShift = bestShift - len(b) + 1”中的“1”。
    • 我明白了!这解决了奇怪转变的问题:)。现在,自相关有什么问题?为什么 correlate(d,d) 的值比其他任何值都低? [[ 2.75 2.75 2.625 1.75 ] [ 2.75 2.75 2.625 1.75 ] [ 2.625 2.625 2.625 1.75 ] [ 1.75 1.75 1.75 1.5 ]]
    • 谢谢。尽管如此,仍然没有做这项工作。我更新了我的问题以显示问题。还是我应该在 for 循环中对它们进行规范化?
    • 我又添加了一项更改来捕捉翻转信号。通过选择相关性的最高绝对值而不是最高相关性。
    【解决方案2】:

    您想在向量之间使用互相关:

    例如:

    >>> np.correlate(A,B)
    array([ 31.])
    
    >>> np.correlate(A,C)
    array([ 19.])
    
    >>> np.correlate(A,D)
    array([-28.])
    

    如果你不关心符号,你可以简单地取绝对值......

    【讨论】:

    • 我尝试了互相关,但问题是,结果又是一个数组,而我需要一个数字(如果我不需要,最好在 0 和 1 之间或 -1 和 1 之间使用绝对值),因此是面积。
    • Correlate 将为您总结这些值。所以你可以得到一个号码。如果您愿意,也可以像在数组上一样使用数值积分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    相关资源
    最近更新 更多