2012-04-25 15 views
18

Ho un vettore, ad es.MATLAB: duplicazione vettore 'n' volte

vector = [1 2 3] 

Vorrei duplicarlo in sé n volte, vale a dire se n = 3, sarebbe finire come:

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

Come posso raggiungere questo obiettivo per ogni valore di n? So che potrei fare quanto segue:

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

Questo sembra un po 'ingombrante però. Qualche metodo più efficace?

risposta

39

Prova

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

lascio a voi di controllare la documentazione per repmat.

+0

Perfetto. Grazie. – CaptainProg

19

Questo è un metodo più veloce di repmat o reshape da un ordine di grandezza

Uno dei migliori metodi per fare queste cose sta usando Tony's Trick. Repmat e Reshape si trovano di solito ad essere più lento di trick di Tony come utilizza direttamente l'indicizzazione intrinseca di Matlabs. Per rispondere si mette in discussione,

Diciamo che, vuoi per affiancare l'vettore riga r=[1 2 3]N momenti come r=[1 2 3 1 2 3 1 2 3...], quindi,

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

Questo metodo ha un notevole risparmio di tempo contro reshape o repmat per grandi N 's.

EDIT: Rispondi a @ dubbi di Li-Aung Yip

ho condotto un piccolo test Matlab per verificare la differenza di velocità tra repmat e tony's trick. Usando il codice menzionato di seguito, ho calcolato i tempi per la costruzione dello stesso vettore piastrellato da un vettore di base A=[1:N]. I risultati mostrano che YES, Tony's-Trick è PIÙ VELOCE DI UN ORDINE di MAGNITUDINE, specialmente per i più grandi N. Le persone sono benvenute a provarle da sole. Questo differenziale molto tempo può essere critico se tale operazione deve essere eseguita in loop. Ecco la piccola sceneggiatura che ho usato;

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 

I tempi (in secondi) per entrambi i metodi sono indicati di seguito;

  • 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

mio RAM non mi ha permesso di andare oltre N = 10000. Sono sicuro che la differenza di tempo tra i due metodi sarà ancora più significativa per N = 100000. Lo so, questi tempi potrebbero essere diversi per macchine diverse, ma la differenza relativa in ordine di grandezza dei tempi sarà valida.Inoltre, lo so, la media dei tempi avrebbe potuto essere una metrica migliore, ma volevo solo mostrare l'ordine di grandezza della differenza nel consumo di tempo tra i due approcci. I miei contatti macchina/OS sono i seguenti:

Rilevante macchina/OS/Matlab Dettagli: Athlon i686 Arch, Ubuntu 11.04 a 32 bit, 3GB di RAM, Matlab 2011b

+1

In primo luogo; Che cosa?! In secondo luogo, ci si chiede perché 'repmat()' sia più lento di farlo 'manualmente'. In terzo luogo, chiunque usi questo meglio mette un commento accanto ad esso ... –

+1

Dopo alcune [ricerche su Tony's Trick] (http://www.mathworks.com/matlabcentral/newsreader/view_thread/261716), sembra che sia stato più veloce al momento della stesura - * 14 anni fa *. MATLAB è migliorato molto da allora e Tony's Trick potrebbe non essere più veloce di "repmat". (Dovresti scrivere un punto di riferimento e testarlo.;)) –

+0

Lo faremo, grazie per i link. – Abhinav

4

in base alla risposta del Abhinav e alcuni test, ho ha scritto una funzione SEMPRE più veloce di repmat()!

Utilizza gli stessi parametri, ad eccezione del primo parametro che deve essere un vettore e non una 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 

Sentitevi liberi di testare la funzione con tutti i tuoi dati e mi danno un feedback. Quando hai trovato qualcosa per migliorarlo, per favore dimmelo.

+2

Sempre più veloce? Possiamo vedere alcuni numeri, multipiattaforma/OS/dimensione vettoriale/ecc.? – patrickvacek

Problemi correlati