2015-09-09 3 views
4

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

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

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

Для примера V = [1,1,3,2]» т = 4 и п = 3

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

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

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 

ответ

5

Очень простой вызов 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 - это то, что известно как B inary S ingleton E X pansion function. Это означает, что вы предоставляете два массива/матрицы любого размера, если они широковещательный. Это означает, что они должны иметь возможность расширяться по размеру, чтобы обе они были равны по размеру. В этом случае v - ваш вектор интереса и является первым параметром - обратите внимание, что он транспонирован. Второй параметр - вектор от 1 до n. Что же будет теперь есть вектор-столбец v получает реплицируются/расширяет столько значений, сколько n и второй вектор получает реплицируются на столько строк, сколько в v. Затем мы выполняем оператор eq/equals между этими двумя массивами. Эта расширенная матрица имеет все 1s в первом столбце, все 2s во втором столбце, вплоть до 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 х 1 вектором случайно распределенных целых чисел от 1 до 1000. Кстати, я должен был изменить вторую функцию Луиса так, что индексирование будет работать, так как добавление требует векторов совместимых измерений.

Выполнение этого кода мы получаем: sparse код

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

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

+0

oh shoot Я писал этот точный ответ, ха-ха, я определенно набираю слишком медленно! –

+0

Хорошее объяснение! –

+0

@ Benoit_11 - lol sorry :) – rayryeng

3

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

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

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


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

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; 
1

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

M= ones(1,m)'*[1:n] == v * ones(1,n)