Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Keith DОтветов: 3

Я только начал изучать мир векторизации. Я получил одномерную векторизацию, но у меня возникли проблемы с векторизацией следующего кода. Я хочу покончить, по крайней мере, с одним из циклов 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

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

Кейт

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

matlabvectorization

Ответы

Ответ 1 · рейтинг 2 · Eitan T

Вот альтернативное решение с 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 ГГц)

Ответ 2 · рейтинг 2 · Oleg

Ваша задача - некоторая выборочная перекрестная таблица. Вы можете легко добиться этого, накапливая счетчики для интересующих позиций, проиндексированных вашим 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

Ответ 3 · Keith D

Ответ предоставлен Седриком Ванназом на форуме 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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы