Как преобразовать вектор в матрицу, где значения в столбцах равны 1, где номер столбца — векторный элемент, иначе 0?

#matlab #matrix #vector

#matlab — математическая лаборатория #матрица #вектор

Вопрос:

Я не уверен, как сформулировать вопрос, но я думаю, что пример поможет. Предположим, у меня есть вектор y = [3;1;4;1;6]. Я хочу создать матрицу Y =

 [0     0     1     0     0     0;
 1     0     0     0     0     0;
 0     0     0     1     0     0;
 1     0     0     0     0     0;
 0     0     0     0     0     1]

 ↑     ↑     ↑     ↑     ↑     ↑
 1     2     3     4     5     6
  

где элемент в каждом столбце равен единице или нулю, соответствующему значению в векторе.

Я обнаружил, что могу сделать это с помощью

 Y = []; for k = 1:max(y); Y = [Y (y==k)]; end
  

Могу ли я сделать это без цикла for (и является ли этот метод более эффективным, если y содержит тысячи элементов)?

Спасибо!

Ответ №1:

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

 Ele = numel(y); 
Y= zeros(Ele, max(y));
for k = 1:Ele
    Y (k,y(k))= 1;
end
  

И вот альтернативный подход без цикла:

 Ele = numel(y);          %Finding no. of elements in y
Y= zeros(Ele, max(y));   % Initiailizing the matrix of the required size with all zeros
lin_idx = sub2ind(size(Y), 1:Ele, y.'); % Finding linear indexes
Y(lin_idx)=1             % Storing 1 in those indexes
  

Комментарии:

1. Спасибо, Сардар_Усама. Отлично работает! Есть ли причина для использования «y.’ » вместо просто «y» в третьей строке. Кроме того, является ли sub2ind более эффективным, чем использование for, если имеется не более 10 столбцов?

2. @Gnubie Потому что размер I и J в sub2ind(SIZ,I,J) должен быть одинаковым. Это должно быть эффективно с точки зрения скорости!

3. @Sadar_Usama: Я понимаю, почему вы переносили y, но обнаружили, что y’ идентично y.’ (дополнительная точка в вашем ответе). В чем разница?

4. @Gnubie ! Простой ' — это не транспонирование. Это комплексное сопряжение, которое совпадает с транспонированием, если нет сложного элемента. Прочитайте документацию для справки здесь: mathworks.com/help/matlab/ref/transpose.html и здесь: mathworks.com/help/matlab/ref/ctranspose.html

5. @Gnubie Идея использования sub2ind на самом деле лучше, чем bsxfun здесь, особенно если y могут иметь большие значения.

Ответ №2:

Вы можете использовать bsxfun :

 result = double(bsxfun(@eq, y(:), 1:max(y)));
  

Если вы запускаете код в Matlab версии R2016b или более поздней, вы можете упростить синтаксис до

 result = double(y(:)==(1:max(y)));
  

Другой подход, возможно, более эффективный, заключается в заполнении значений непосредственно с помощью accumarray :

 result = accumarray([(1:numel(y)).' y(:)], 1);
  

Комментарии:

1. это решение медленное: n ^ 2 операции, из которых n (n-1) являются проверкой, ни к чему не приводящей, и только n приводят к записи 1.

2. @titus Вы правы. Я добавил другой подход, который, вероятно, более эффективен

Ответ №3:

Я нашел другое решение:

 E = eye(max(y));
Y = E(y,:);
  

Комментарии:

1. Это выглядит довольно аккуратно, но не так быстро, как sub2ind подход. Осторожно! Если max(y) >> numel(y) , это становится, безусловно, самым медленным. Но если max(y) << numel(y) , это почти так же хорошо, как sub2ind .

Ответ №4:

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

 Y = repmat(1:max(y), size(y)) == repmat(y, 1, max(y))