Matlab конвертировать вектор в двоичную матрицу

У меня есть вектор v размера (m,1), элементы которого являются целыми числами, выбранными из 1:n. Я хочу создать матрицу M размера (m,n), элементы которой M(i,j) равны 1, если v(i) = j, и 0 в противном случае. Я не хочу использовать циклы и хотел бы реализовать это как простую манипуляцию векторной матрицей.

Поэтому я сначала подумал, чтобы создать матрицу с повторяющимися элементами

 M = v * ones(1,n) % this is a (m,n) matrix of repeated v

Например, v=[1,1,3,2]' m = 4 и n = 3

M =
     1     1     1
     1     1     1
     3     3     3
     2     2     2

тогда мне нужно создать вектор сравнения c размера (1,n)

c = 1:n
1 2 3

Тогда мне нужно выполнить серию логических сравнений

M(1,:)==c % this results in [1,0,0]
.
M(4,:)==c % this results in [0,1,0]

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

M =
     1     0     0
     1     0     0
     0     0     1
     0     1     0

3 ответа

Очень простой вызов bsxfun сделает свое дело:

>> n = 3;
>> v = [1,1,3,2].';
>> M = bsxfun(@eq, v, 1:n)

M =

     1     0     0
     1     0     0
     0     0     1
     0     1     0

Как работает код, на самом деле довольно просто. bsxfun это то, что известно как бинарная E-функция Синглтона E X. Это означает, что вы предоставляете два массива / матрицы любого размера, если они транслируемы. Это означает, что они должны иметь возможность увеличиваться в размере, чтобы они оба были равны по размеру. В этом случае, v Ваш интересный вектор и является первым параметром - обратите внимание, что он транспонирован. Второй параметр - это вектор от 1 до n, Что будет теперь, это вектор столбца v реплицируется / расширяется на столько значений, сколько есть n и второй вектор реплицируется на столько строк, сколько есть в v, Затем мы делаем eq / равно оператор между этими двумя массивами. Эта расширенная матрица фактически имеет все 1 в первом столбце, все 2 во втором столбце до n, Делая eq между этими двумя матрицами, вы в действительности определяете, какие значения в v равны соответствующему индексу столбца.


Вот подробный тест времени и разбивка каждой функции. Я поместил каждую реализацию в отдельную функцию, и я также позволил n=max(v) так что первый код Луиса будет работать. я использовал timeit рассчитать каждую функцию:

function timing_binary

n = 10000;
v = randi(1000,n,1);
m = numel(v);

    function luis_func()
    M1 = full(sparse(1:m,v,1));       
    end

    function luis_func2()
    %m = numel(v);
    %n = 3; %// or compute n automatically as n = max(v);
    M2 = zeros(m, n);
    M2((1:m).' + (v-1)*m) = 1;      
    end

    function ray_func()
    M3 = bsxfun(@eq, v, 1:n);
    end

    function op_func()
    M4= ones(1,m)'*[1:n] == v * ones(1,n);
    end

t1 = timeit(@luis_func);
t2 = timeit(@luis_func2);
t3 = timeit(@ray_func);
t4 = timeit(@op_func);

fprintf('Luis Mendo - Sparse: %f\n', t1);
fprintf('Luis Mendo - Indexing: %f\n', t2);
fprintf('rayryeng - bsxfun: %f\n', t3);
fprintf('OP: %f\n', t4);


end

Этот тест предполагает n = 10000 и вектор v представляет собой вектор 10000 x 1 случайным образом распределенных целых чисел от 1 до 1000. Кстати, мне пришлось изменить вторую функцию Луиса, чтобы индексирование работало, так как для сложения требуются векторы совместимых измерений.

Запустив этот код, мы получим:

>> timing_binary
Luis Mendo - Sparse: 0.015086
Luis Mendo - Indexing: 0.327993
rayryeng - bsxfun: 0.040672
OP: 0.841827

Луис Мендо sparse Код выигрывает (как я и ожидал), а затем bsxfun с последующим индексированием и последующим предложенным вами подходом с использованием матричных операций. Время в секундах.

Если предположить, n равняется max(v), ты можешь использовать sparse:

v = [1,1,3,2];
M = full(sparse(1:numel(v),v,1));

Какие sparse Он создает разреженную матрицу, используя первый аргумент в качестве индексов строк, второй в качестве индексов столбцов и третий в качестве значений матрицы. Затем он преобразуется в полную матрицу с full,


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

v = [1,1,3,2];
m = numel(v);
n = 3; %// or compute n automatically as n = max(v);
M = zeros(m, n);
M((1:m) + (v-1)*m) = 1;

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

M= ones(1,m)'*[1:n] == v * ones(1,n)
Другие вопросы по тегам