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)