Подтвердить что ты не робот

MATLAB: дублирование вектора 'n' times

У меня есть вектор, например

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

Это кажется немного громоздким. Какие-либо более эффективные методы?

4b9b3361

Ответ 1

Try

repmat([1 2 3],1,3)

Я оставлю вас проверить документацию на repmat.

Ответ 2

Это более быстрый метод, чем 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 = 10, time_repmat = 8e-5, time_tony = 3e-5
  • N = 100, time_repmat = 2.9e-4, time_tony = 6e-5
  • N = 1000, time_repmat = 0.0302, time_tony = 0.0058
  • N = 10000, time_repmat = 2.9199, time_tony = 0.5292

Моя оперативная память не позволила мне выйти за пределы N = 10000. Я уверен, разница во времени между этими двумя методами будет еще более значимой для N = 100000. Я знаю, что эти времена могут отличаться для разных машин, но будет относительная разница в порядке величины. Кроме того, я знаю, средние времена могли быть лучшей метрикой, но я просто хотел показать разницу в величине разности во времени между этими двумя подходами. Информация о машине /os приведена ниже:

Релевантная машина /OS/Matlab Подробности: Athlon i686 Arch, Ubuntu 11.04 32 бит, 3 ГБ оперативной памяти, Matlab 2011b

Ответ 3

На основании ответа 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

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