корреляция трехмерной матрицы с вектором в Matlab

У меня есть матрица KxLxM A, которая представляет собой изображение с вектором признаков длиной M для каждого местоположения пикселя. У меня также есть вектор признаков v, длина M. В каждом местоположении пикселя изображения A я хочу вычислить корреляцию вектора признаков пикселя с моим вектором признаков v.

Я уже сделал это с помощью цикла, но циклы в Matlab работают медленно. Есть ли у кого-нибудь предложение о том, как векторизовать это?

function test()
A = rand(4,5,3);
v = [1 2 3];
c = somecorr(A, v);
size(c)

function c = somecorr(a,v)
c = a(:,:,1).*0;
for y = 1:size(a,1)
    for x = 1:size(a,2)
        c(y,x) = corr2(squeeze(a(y,x,1:length(v)))',v);
    end
end

>>test()
ans =

 4     5

person Goosebumps    schedule 24.04.2013    source источник
comment
Я думаю, что раньше циклы в Matlab были медленными. Но в наши дни из-за мощи компиляции Just In Time это уже не обязательно верно. ссылка   -  person sietschie    schedule 24.04.2013


Ответы (1)


Вы можете попробовать это и посмотреть, будет ли это быстрее:

function c = somecorr2(a,v)

    as = reshape(a,size(a,1)*size(a,2),size(a,3));
    cs = corr(as',v');
    c = reshape(cs,size(a,1),size(a,2));
    size(c)

Я сделал только несколько небольших тестов, но, похоже, это более чем в 100 раз быстрее. По крайней мере, для моих тестовых случаев.

Если у вас нет функции 'corr', вы можете использовать ее, вдохновившись этим [ответом]( Как быстро вычислить корреляцию столбца за столбцом в Matlab):

function C = manualCorr(A,B)
    An=bsxfun(@minus,A,mean(A,1)); %%% zero-mean
    Bn=bsxfun(@minus,B,mean(B,1)); %%% zero-mean
    An=bsxfun(@times,An,1./sqrt(sum(An.^2,1))); %% L2-normalization
    Bn=bsxfun(@times,Bn,1./sqrt(sum(Bn.^2,1))); %% L2-normalization
    C=sum(An.*repmat(Bn,1,size(An,2)),1); %% correlation

Для матрицы 100x100x3 я получаю следующие времена выполнения:

Ваша версия: 1.643065 секунд. мой с 'corr': 0,007191 секунды. мой с 'manualCorr': 0,006206 секунды.

Я использовал Matlab R2012a.

person sietschie    schedule 24.04.2013
comment
кстати reshape(a,size(a,1)*size(a,2),size(a,3)); тоже может быть просто reshape(a,[],size(a,3)); - person Dan; 24.04.2013
comment
Черт, моя довольно архаичная версия Matlab (2007b) не имеет функции исправления. Я вижу вашу точку зрения однако. Я дам ему попробовать - person Goosebumps; 24.04.2013
comment
Кажется, что он примерно на треть быстрее. Это уже неплохой выигрыш. - person Goosebumps; 24.04.2013
comment
Я вижу, что вы нашли коэффициент 100, а я нашел 1,5-кратный. Вероятно, это связано с тем, что я не использую функцию коррекции Matlab, а ту, которую я нашел в наборе инструментов статистики с открытым исходным кодом. Мне придется обновить мой матлаб! - person Goosebumps; 24.04.2013
comment
почему repmat для вычислений C? почему бы снова не использовать bsxfun? - person Shai; 25.04.2013
comment
Корреляция теперь примерно в 270 раз быстрее. Большое спасибо! Я хотел бы поставить вам больше +1. - person Goosebumps; 25.04.2013
comment
@Shai, потому что я не очень хорошо разбираюсь в bsxfun и в основном просто скопировал его из другого ответа. Как я могу имитировать поведение repmat с bsxfun? - person sietschie; 25.04.2013