Быстрая корреляция между соответствующими столбцами в двух матрицах в python [duplicate]

Ребята взгляните на https://github.com/reinforced/ Reinforced.Typings. Последние несколько дней я играю с шаблонами и t4-шаблонами и заканчиваю этот проект. Это супер-просто и работает как шарм. Просто получите пакет, измените файл конфигурации (это похоже на 10 секунд) и выполните сборку. Все делается автоматически без каких-либо проблем. Благословите автора!

Плохая вещь в шаблонах T4 заключается в том, что после сборки из VS отсканированные сборки блокируются, и вы должны перезапустить VS (как это глупо?). В T4 Toolbox + есть некоторые способы очистки VS, но ни один из них не работал для меня.

3
задан Jacques de Hooge 18 January 2017 в 11:38
поделиться

3 ответа

На основе this solution для нахождения корреляционной матрицы между двумя 2D массивами мы можем иметь аналогичный для нахождения корреляционный вектор, который вычисляет корреляцию между соответствующими строками в двух массивах. Реализация будет выглядеть примерно так:

def corr2_coeff_rowwise(A,B):
    # Rowwise mean of input arrays & subtract from input arrays themeselves
    A_mA = A - A.mean(1)[:,None]
    B_mB = B - B.mean(1)[:,None]

    # Sum of squares across rows
    ssA = (A_mA**2).sum(1);
    ssB = (B_mB**2).sum(1);

    # Finally get corr coeff
    return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)

Мы также можем оптимизировать часть, чтобы получить ssA и ssB, введя там магию einsum!

def corr2_coeff_rowwise2(A,B):
    A_mA = A - A.mean(1)[:,None]
    B_mB = B - B.mean(1)[:,None]
    ssA = np.einsum('ij,ij->i',A_mA,A_mA)
    ssB = np.einsum('ij,ij->i',B_mB,B_mB)
    return np.einsum('ij,ij->i',A_mA,B_mB)/np.sqrt(ssA*ssB)

Прогон образца -

In [164]: M1 = np.array ([
     ...:     [1, 2, 3, 4],
     ...:     [2, 3, 1, 4.5]
     ...: ])
     ...: 
     ...: M2 = np.array ([
     ...:     [10, 20, 33, 40],
     ...:     [20, 35, 15, 40]
     ...: ])
     ...: 

In [165]: corr2_coeff_rowwise(M1, M2)
Out[165]: array([ 0.99411402,  0.96131896])

In [166]: corr2_coeff_rowwise2(M1, M2)
Out[166]: array([ 0.99411402,  0.96131896])

Тест времени выполнения -

In [97]: M1 = np.random.rand(256,200)
    ...: M2 = np.random.rand(256,200)
    ...: 

In [98]: out1 = np.diagonal (np.corrcoef (M1, M2), M1.shape [0])
    ...: out2 = corr2_coeff_rowwise(M1, M2)
    ...: out3 = corr2_coeff_rowwise2(M1, M2)
    ...: 

In [99]: np.allclose(out1, out2)
Out[99]: True

In [100]: np.allclose(out1, out3)
Out[100]: True

In [101]: %timeit np.diagonal (np.corrcoef (M1, M2), M1.shape [0])
     ...: %timeit corr2_coeff_rowwise(M1, M2)
     ...: %timeit corr2_coeff_rowwise2(M1, M2)
     ...: 
100 loops, best of 3: 9.5 ms per loop
1000 loops, best of 3: 554 µs per loop
1000 loops, best of 3: 430 µs per loop

20x+ ускорился там, где einsum над встроенным np.corrcoef!

2
ответ дан Community 18 August 2018 в 15:18
поделиться
  • 1
    Я пробовал это решение с сигнальными векторами 10k образцов, но, к сожалению, он оказался значительно медленнее. Еще спасибо за это творческое решение. – Jacques de Hooge 18 January 2017 в 10:47
  • 2
    @JacquesdeHooge Каковы формы M1 и M2 в этом случае? – Divakar 18 January 2017 в 10:49
  • 3
    Есть 256 строк (сигналов), и я запускаю скользящее окно из 200 отсчетов по «основному сигналу». Так что на самом деле не 10k образцов, а 200 образцов векторов по 256 компонентов каждый. Таким образом, M1 и M2 составляют 256 строк х 200 столбцов. Извините за ошибочные образцы 10k. Это полная длина сигнала. Используя корреляцию с скользящим шаблоном, я пытаюсь найти смещения, где шаблон лучше всего подходит. На самом деле я ищу QRS-комплексы в 256-канальной инвазивной кардиограмме (точнее, электрограмме, как ее называют медики). Я попытаюсь добавить некоторые из исходного контекста кода) – Jacques de Hooge 18 January 2017 в 11:13
  • 4
    @JacquesdeHooge Проверьте отредактированный файл corr2_coeff_rowwise2? – Divakar 18 January 2017 в 11:26
  • 5
    @JacquesdeHooge Итак, вы это выяснили? – Divakar 20 January 2017 в 20:17

, не зная достаточного количества магии массива numpy, я бы просто выделил строки, каждый из них передал каждую пару в corrcoeff

[np.corrcoef(i,j)[0][1] for i,j in zip(a,b)]

для вывода столбца np.array

c, c.shape = np.array([np.corrcoef(i,j)[0][1] for i,j in zip(a,b)]), (a.shape[0], 1)

Я уверен, что лучше использовать функции широковещания / индексирования numpy

0
ответ дан f5r5e5d 18 August 2018 в 15:18
поделиться
  • 1
    Я думал об этом, и это было бы приемлемо, но я бы предпочел не зацикливаться на Python по соображениям производительности. Я думаю, однако, падение производительности было бы минимальным, так как большинство времени было бы в самом corcoeff. – Jacques de Hooge 18 January 2017 в 10:03

Я думаю, что это так: (пожалуйста, исправьте, если не так!) [/ ​​g0]

import numpy as np

M1 = np.array ([
    [1, 2, 3, 4],
    [2, 3, 1, 4.5]
])

M2 = np.array ([
    [10, 20, 33, 40],
    [20, 35, 15, 40]
])

v = np.diagonal (np.corrcoef (M1, M2), M1.shape [0])

print (v)

Какие принты:

[ 0.99411402  0.96131896]

Поскольку у него есть только одно измерение, я могу думать об этом как вектор-столбец ...

0
ответ дан Jacques de Hooge 18 August 2018 в 15:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: