Ответ 1
Try
repmat([1 2 3],1,3)
Я оставлю вас проверить документацию на repmat
.
У меня есть вектор, например
vector = [1 2 3]
Я хотел бы дублировать его внутри себя n раз, т.е. если n = 3, это будет выглядеть как:
vector = [1 2 3 1 2 3 1 2 3]
Как я могу достичь этого для любого значения n? Я знаю, что могу сделать следующее:
newvector = vector;
for i = 1 : n-1
newvector = [newvector vector];
end
Это кажется немного громоздким. Какие-либо более эффективные методы?
Try
repmat([1 2 3],1,3)
Я оставлю вас проверить документацию на repmat
.
Это более быстрый метод, чем repmat
или reshape
по порядку величины
Один из лучших методов для таких вещей - использование Tony Trick. Репмат и Решап обычно оказываются медленнее, чем трюк Тони, он напрямую использует встроенную индексацию Matlabs. Чтобы ответить на ваш вопрос,
Предположим, вы хотите нарисовать вектор строки r=[1 2 3]
N
раз, например r=[1 2 3 1 2 3 1 2 3...]
, затем
c=r'
cc=c(:,ones(N,1));
r_tiled = cc(:)';
Этот метод имеет значительную экономию времени для reshape
или repmat
для больших N
.
РЕДАКТИРОВАТЬ: Ответ на @Li-aung Yip сомнения
Я провел небольшой тест Matlab, чтобы проверить разницу в скорости между repmat
и tony trick
. Используя приведенный ниже код, я вычислил времена для построения одного и того же разбитого вектора из базового вектора A=[1:N]
. Результаты показывают, что ДА, Tony's Trick является ОСНОВНЫМ ПО ЗАКАЗУ MAGNITUDE, особенно для больших N. Люди могут попробовать сами. Этот многократный дифференциал может быть критическим, если такая операция должна выполняться в циклах. Вот небольшой script, который я использовал;
N= 10 ;% ASLO Try for values N= 10, 100, 1000, 10000
% time for tony_trick
tic;
A=(1:N)';
B=A(:,ones(N,1));
C=B(:)';
t_tony=toc;
clearvars -except t_tony N
% time for repmat
tic;
A=(1:N);
B=repmat(A,1,N);
t_repmat=toc;
clearvars -except t_tony t_repmat N
Времена (в секундах) для обоих методов приведены ниже;
Моя оперативная память не позволила мне выйти за пределы N = 10000. Я уверен, разница во времени между этими двумя методами будет еще более значимой для N = 100000. Я знаю, что эти времена могут отличаться для разных машин, но будет относительная разница в порядке величины. Кроме того, я знаю, средние времена могли быть лучшей метрикой, но я просто хотел показать разницу в величине разности во времени между этими двумя подходами. Информация о машине /os приведена ниже:
Релевантная машина /OS/Matlab Подробности: Athlon i686 Arch, Ubuntu 11.04 32 бит, 3 ГБ оперативной памяти, Matlab 2011b
На основании ответа Abhinav и некоторых тестов я написал функцию, которая ВСЕГДА быстрее, чем repmat()!
Он использует те же параметры, за исключением первого параметра, который должен быть вектором, а не матрицей.
function vec = repvec( vec, rows, cols )
%REPVEC Replicates a vector.
% Replicates a vector rows times in dim1 and cols times in dim2.
% Auto optimization included.
% Faster than repmat()!!!
%
% Copyright 2012 by Marcel Schnirring
if ~isscalar(rows) || ~isscalar(cols)
error('Rows and cols must be scaler')
end
if rows == 1 && cols == 1
return % no modification needed
end
% check parameters
if size(vec,1) ~= 1 && size(vec,2) ~= 1
error('First parameter must be a vector but is a matrix or array')
end
% check type of vector (row/column vector)
if size(vec,1) == 1
% set flag
isrowvec = 1;
% swap rows and cols
tmp = rows;
rows = cols;
cols = tmp;
else
% set flag
isrowvec = 0;
end
% optimize code -> choose version
if rows == 1
version = 2;
else
version = 1;
end
% run replication
if version == 1
if isrowvec
% transform vector
vec = vec';
end
% replicate rows
if rows > 1
cc = vec(:,ones(1,rows));
vec = cc(:);
%indices = 1:length(vec);
%c = indices';
%cc = c(:,ones(rows,1));
%indices = cc(:);
%vec = vec(indices);
end
% replicate columns
if cols > 1
%vec = vec(:,ones(1,cols));
indices = (1:length(vec))';
indices = indices(:,ones(1,cols));
vec = vec(indices);
end
if isrowvec
% transform vector back
vec = vec';
end
elseif version == 2
% calculate indices
indices = (1:length(vec))';
% replicate rows
if rows > 1
c = indices(:,ones(rows,1));
indices = c(:);
end
% replicate columns
if cols > 1
indices = indices(:,ones(1,cols));
end
% transform index when row vector
if isrowvec
indices = indices';
end
% get vector based on indices
vec = vec(indices);
end
end
Не стесняйтесь протестировать функцию со всеми вашими данными и дать мне обратную связь. Когда вы нашли что-то, чтобы улучшить его, скажите, пожалуйста.