Матрица и вектор столбца, содержащие индексы, как перебирать без цикла? - PullRequest
1 голос
/ 08 апреля 2019

У меня есть большая матрица (500212x7) и вектор столбца, как показано ниже

matrix F         vector P
0001011          4
0001101          3
1101100          6
0000110          1
1110000          7

Вектор содержит индексы, рассматриваемые в строках матрицы. Р (1) предназначен для указания на F (1,4), Р (2) на F (2,3) и так далее.

Я хочу отменить бит в каждой строке F в столбце, указанном элементом P (в той же строке).

Я думал о таких вещах, как

F(:,P(1)) = ~F(:,P(1));
F(:,P(:)) = ~F(:,P(:));

но, конечно, эти сценарии не дадут ожидаемого результата, так как первая строка не изменит элемент P, а вторая даже не позволит мне запустить программу, потому что полный вектор не может создать индекс.

Идея состоит в том, что мне нужно сделать это для всех строк F и P (изменяя / увеличивая «одновременно»), но взять значение элемента P.

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

Существует ли какое-либо волшебство Matlab, позволяющее решить такую ​​задачу с использованием матричных операций?

Ответы [ 3 ]

4 голосов
/ 08 апреля 2019

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

Вы никогда не должны делать такиепредположение.Сначала реализуйте цикл, затем проверьте, действительно ли он слишком медленный для вас или нет, затем подумайте об оптимизации.

Здесь я сравниваю ответ Луиса и цикл trival:

N = 500212;
F = rand(N,7) > 0.6;
P = randi(7,N,1);

timeit(@()method1(F,P))
timeit(@()method2(F,P))

function F = method1(F,P)
   ind = (1:size(F,1)) + (P(:).'-1)*size(F,1); % create linear index
   F(ind) = ~F(ind); % negate those entries
end

function F = method2(F,P)
   for ii = 1:numel(P)
      F(ii,P(ii)) = ~F(ii,P(ii));
   end
end

Времена 0,0065 с для ответа Луиса и 0,0023 с для цикла (MATLAB Online R2019a).

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

Уроки: не отклоняет циклы, не пытается преждевременно оптимизировать и не оптимизирует без сравнения.

3 голосов
/ 08 апреля 2019

Другое решение:

xor( F, 1:7 == P )

Объяснение:

  • 1:7 == P генерирует массивы с одним нагретым значением.
  • xor вызовет сохранение немногоего значение против 0, и переверните его против 1
2 голосов
/ 08 апреля 2019

Не уверен, что он квалифицируется как wizardry , но линейное индексирование делает именно то, что вы хотите:

F = [0 0 0 1 0 1 1; 0 0 0 1 1 0 1; 1 1 0 1 1 0 0; 0 0 0 0 1 1 0; 1 1 1 0 0 0 0];
P = [4; 3; 6; 1; 7];
ind = (1:size(F,1)) + (P(:).'-1)*size(F,1); % create linear index
F(ind) = ~F(ind); % negate those entries
...