Быстрая корреляция в Matlab

Я пытаюсь вывести функцию для расчета корреляции движущегося/катящегося для двух векторов, и скорость имеет высокий приоритет, так как мне нужно применить эту функцию в функции массива. У меня есть (что слишком медленно):

Data1 = rand(3000,1);
Data2 = rand(3000,1); 

function y = MovCorr(Data1,Data2)

[N,~] = size(Data1);

correlationTS = nan(N, 1);

for t = 20+1:N
    correlationTS(t, :) = corr(Data1(t-20:t, 1),Data2(t-20:t,1),'rows','complete');
end
    y = correlationTS;
end

Я думаю, что цикл for можно было бы выполнить более эффективно, если бы я знал, как генерировать индексы окна ролинга, а затем применять accumarray. Какие-либо предложения?


person Mace    schedule 20.02.2015    source источник
comment
Разве это не похоже на свертку поэлементного произведения с ones(1,21)? Поскольку я не очень хорошо с этим знаком: у вас есть формула для движущейся корреляции?   -  person knedlsepp    schedule 20.02.2015
comment
Не знаете, что вы подразумеваете под поэлементным произведением с единицами (1,21)? Функция выше MovCorr выдает правильные значения. Это слишком медленно. Он производит 21 наблюдение, перемещая корреляцию между двумя векторами, Data1 и Data2.   -  person Mace    schedule 20.02.2015
comment
Кстати: ваш приведенный выше код даже не запускается (из-за Data1(.,2))   -  person knedlsepp    schedule 20.02.2015
comment
Аргх, извините.... Теперь это должно сработать   -  person Mace    schedule 20.02.2015
comment
Также: Это 22 наблюдения.   -  person knedlsepp    schedule 20.02.2015
comment
Ах да, сейчас поменяли. Спасибо. Я хочу (3000-20) корреляций. Они должны быть рассчитаны на движущихся данных...   -  person Mace    schedule 20.02.2015
comment
Я думаю, вы сможете взломать это вместе, используя movingstd из файлообменника и фильтра скользящего среднего.   -  person knedlsepp    schedule 20.02.2015
comment
У меня сейчас нет кода, но вы должны проверить en.wikipedia.org/wiki/Algorithms_for_calculating_variance. . Раздел: Онлайн-алгоритм. Это показывает, как вычислить среднее значение и дисперсию переменной при введении новой переменной. Вы должны иметь возможность рассчитать обновленное среднее значение и дисперсию, удалив последнее значение и вставив новое значение в две строки. Расширьте его до формулы корреляции. Результат будет не очень, но быстро.   -  person lonstud    schedule 20.02.2015
comment
@knedlsepp Я посмотрел на movingstd из файлового обмена, и он действительно кажется очень быстрым. К сожалению, мне трудно понять, что делает фильтр, но, похоже, это хороший путь...   -  person Mace    schedule 20.02.2015


Ответы (1)


Следуя совету @knedlsepp и используя фильтр, как в movingstd, я нашел следующее решение, которое довольно быстро:

function Cor = MovCorr1(Data1,Data2,k)
y = zscore(Data2);
n = size(y,1);

if (n<k)
    Cor = NaN(n,1);
else
    x = zscore(Data1);
    x2 = x.^2;
    y2 = y.^2;
    xy = x .* y;
    A=1;
    B = ones(1,k);
    Stdx = sqrt((filter(B,A,x2) - (filter(B,A,x).^2)*(1/k))/(k-1));
    Stdy = sqrt((filter(B,A,y2) - (filter(B,A,y).^2)*(1/k))/(k-1));
    Cor = (filter(B,A,xy) - filter(B,A,x).*filter(B,A,y)/k)./((k-1)*Stdx.*Stdy);
    Cor(1:(k-1)) = NaN;
end
end

По сравнению с моим исходным решением время выполнения:

tic
MovCorr(Data1,Data2);
toc
Elapsed time is 1.017552 seconds.

tic
MovCorr1(Data1,Data2,21);
toc
Elapsed time is 0.019400 seconds.
person Mace    schedule 23.02.2015