Векторизация 2 циклов for в MATLAB

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

CityPairs = [7 3
3 1
3 1
1 7
7 1
3 4
5 1
4 6];
Offices = [1;3;7];
nOffices = size(Offices,1);

connection = zeros(nOffices);
for i = 1:nOffices
    for j = 1:nOffices
        connection(i,j) = sum(Offices(i) == CityPairs(:,1)...
            & CityPairs(:,2) == Offices(j));
    end
end   
disp(connection)

В этом примере 7 городов, в трех из которых есть офисы. Я хочу, чтобы попарная матрица для городов с офисами отражала сумму всех односторонних соединений между ними. Ответ на вышеуказанную проблему должен быть:

 0     0     1
 2     0     0
 1     1     0

Любые предложения приветствуются. Заранее спасибо.

Кейт


person Keith D    schedule 24.10.2013    source источник
comment
Есть ли причина для connection(i,:) = connection(i,:);? В противном случае удалите строку.   -  person Daniel    schedule 24.10.2013
comment
это было частью чего-то другого, что я сделал, здесь это неважно - я удалил это.   -  person Keith D    schedule 24.10.2013
comment
Итак, вы хотите еще один ответ или ваша проблема решена?   -  person chappjc    schedule 24.10.2013
comment
проблема решена. я просто не мог опубликовать свой ответ, пока не прошло 6 часов. спасибо за альтернативные решения - я проверю их позже и отдам должное тем, которые работают должным образом.   -  person Keith D    schedule 24.10.2013


Ответы (3)


Вот альтернативное решение с sparse:

dims = max(max(CityPairs), max(Offices));
A = sparse(CityPairs(:, 1), CityPairs(:, 2), 1, dims(1), dims(2));
result = full(A(Offices, Offices));

Это должно немного ускорить ваши вычисления1 по сравнению с предлагаемым bsxfun решением.


1 Работает в 5 раз быстрее на MATLAB 2012a (Windows Server 2008 R2 на 16-ядерном процессоре Intel Xeon с частотой 2,27 ГГц)

person Eitan T    schedule 24.10.2013
comment
Хороший, я всегда забываю о редком накоплении. - person Oleg; 24.10.2013
comment
Эйтан, мне нравится. работает быстро, но столкнулся с проблемой. Мой набор данных меняется динамически, и я столкнулся с ситуацией, когда один из столбцов пар городов больше не имеет индексов городов, превышающих самый большой индекс офиса, который прерывает всю операцию. есть идеи? - person Keith D; 24.10.2013
comment
Выше я имел в виду значения, а не индексы. - person Keith D; 25.10.2013
comment
@ user2913719 Можете ли вы привести пример? Я не вижу, как это нарушает операцию. - person Eitan T; 25.10.2013
comment
Хорошо, на небольшом примере я указал, что это не так (следовало сначала проверить это), но на более крупном наборе образцов из 20 000 + это так, но, возможно, происходит что-то еще. Позвольте нам исследовать больше, в то же время я подключу вас к обратной связи! - person Keith D; 25.10.2013
comment
Eitan, Наконец-то нашел время засесть за это (и поменять userID). В исходном примере, если вы измените Office на [1,3,8], он сломается, потому что индекс превышает размеры - я могу понять, почему в моей голове, но не уверен, как это настроить в вашем решении. Количество офисов фиксировано в моем более крупном приложении, но соединения пары городов меняются динамически, неизбежно уменьшаясь до размера, вызывающего эту ошибку. есть идеи? Я вижу потенциал для использования sparse в остальной части моего кода, поэтому разобраться в этом было бы очень полезно. Спасибо. КД - person Keith D; 29.10.2013
comment
@KeithD Думаю, я понял. Вы получаете ошибку, потому что матрица A имеет размеры, соответствующие наибольшим значениям в CityPairs (7 в вашем примере), а вы пытаетесь использовать индексы с большим значением (то есть 8). Решением будет создание разреженной матрицы с размерами, соответствующими наибольшему из двух. Пожалуйста, попробуйте мое исправленное решение. - person Eitan T; 29.10.2013

Ваша задача - некоторая выборочная перекрестная таблица. Вы можете легко добиться этого, накапливая счетчики для интересующих позиций, проиндексированных вашим Offices:

% Row and col subs
[~,rsubs] = ismember(CityPairs(:,1),Offices);
[~,csubs] = ismember(CityPairs(:,2),Offices);

% Select where both belong to Offices, i.e. non 0
subs = [rsubs,csubs];
subs = subs(all(subs,2),:);

% Accumulate
accumarray(subs,1)

Результат

ans =
     0     0     1
     2     0     0
     1     1     0

Если у вас есть панель инструментов статистики, вы можете использовать crosstab напрямую, но тогда вам нужно будет выбрать интересующие строки и столбцы:

crosstab(CityPairs(:,1),CityPairs(:,2))
ans =
     0     0     0     0     1
     2     0     1     0     0
     0     0     0     1     0
     1     0     0     0     0
     1     1     0     0     0
person Oleg    schedule 24.10.2013
comment
Фактически, вы можете напрямую передать accumarray с помощью CityPairs, а затем выбрать строки и столбцы, соответствующие Offices, то есть: A = accumarray(CityPairs, 1); result = A(Offices, Offices);... (что делает это чем-то похожим на мое решение с sparse). - person Eitan T; 24.10.2013

Ответ предоставлен Седриком Ванназом на форуме MathWorks.

Нетривиально «векторизировать» эту настройку, так как есть операции, требующие некоторой таблицы поиска, и есть накопление (если вы не найдете хитрости). Это, вероятно, сделает подход без циклов FOR более сложным (с точки зрения кода), чем базовый подход, основанный на циклах. Итак, давайте начнем сначала с трюка ;-) ..

 A = double( bsxfun(@eq, CityPairs(:,1), Offices.') ) ;
 B = double( bsxfun(@eq, CityPairs(:,2), Offices.') ) ;
 A.' * B

Альтернативный подход: http://www.mathworks.com/matlabcentral/answers/91294-vectorization-of-2-for-loops-in-matlab

person Keith D    schedule 24.10.2013