MATLAB: duplication du vecteur' n ' times [dupliquer]

Cette question a déjà une réponse ici:

  • Octave / Matlab: étendre un vecteur le faisant se répéter? 2 réponses

j'ai un vecteur, par exemple,

vector = [1 2 3]

je voudrais dupliquer à l'intérieur de lui-même n fois, c'est à dire si n = 3, ce serait la fin de la manière suivante:

vector = [1 2 3 1 2 3 1 2 3]

Comment puis-je atteindre cet pour toute valeur de n? Je sais que je pourrais faire ce qui suit:

newvector = vector;
for i = 1 : n-1
    newvector = [newvector vector];
end

Cela semble un peu lourd. Aucune des méthodes plus efficaces?

18
demandé sur CaptainProg 2012-04-25 16:55:44

3 réponses

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

je vous laisse consulter la documentation repmat.

39
répondu High Performance Mark 2012-04-25 12:59:34

C'est une méthode plus rapide que repmat ou reshape par un Ordre de Grandeur

une des meilleures méthodes pour faire de telles choses est D'utiliser Le truc de Tony. Repmat et Reshape sont généralement plus lents que Tony, car ils utilisent directement L'indexation inhérente à Matlabs. Pour répondre à votre question,

disons, que vous voulez carreler le vecteur de ligne r=[1 2 3]N fois r=[1 2 3 1 2 3 1 2 3...], puis

c=r'
cc=c(:,ones(N,1));
r_tiled = cc(:)';

Cette méthode a économies de temps importantes par rapport à reshape ou repmat pour les grandes N.

EDIT: réponse aux doutes de @Li-Aung Yip

j'ai effectué un petit test de Matlab pour vérifier le différentiel de vitesse entre repmat et tony's trick. En utilisant le code mentionné ci-dessous, j'ai calculé les temps pour construire le même vecteur de carrelage à partir d'un vecteur de base A=[1:N]. Les résultats montrent que oui, le tour de Tony est plus rapide D'un ordre de grandeur, surtout pour les plus grands N. Les gens sont invités à essayer eux-mêmes. Ce grand différentiel de temps peut être critique si une telle opération doit être effectuée en boucles. Voici le petit script que j'ai utilisé;

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

Le Temps (en secondes) pour les deux méthodes sont donnés ci-dessous;

  • N= 10, time_repmat = 8e - 5, time_tony = 3e-5
  • N= 100, time_repmat = 2.9 e - 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

mon RAM ne m'a pas permis d'aller au-delà de N=10000. Je suis sûr que la différence de temps entre les deux méthodes sera encore plus significative pour N=100000. Je sais, ces temps peuvent être différents pour différentes machines, mais la différence relative dans l'ordre de grandeur des temps sera maintenue. Aussi, je sais, la moyenne de temps aurait pu être une meilleure métrique, mais je voulais juste montrer l'ordre de grandeur de la différence de consommation de temps entre les deux approches. Ma machine/os de détails sont donnés ci-dessous :

détails pertinents de la Machine / OS / Matlab : Athlon i686 Arc, Ubuntu 11.04 32 bits, 3 go de ram, Matlab, 2011b

19
répondu Abhinav 2016-07-29 21:55:17

basé sur la réponse D'Abhinav et quelques tests, j'ai écrit une fonction qui est toujours plus rapide que repmat()!

Il utilise les mêmes paramètres, sauf pour le premier paramètre qui doit être un vecteur et non une matrice.

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

N'hésitez pas à tester la fonction avec toutes vos données et me donner des commentaires. Quand tu as trouvé quelque chose pour l'améliorer, dis-le-moi.

4
répondu darkdragon-001 2012-08-26 18:44:11