2011-08-11 17 views
6

Tengo una bigmatrix que está ordenada. Sin embargo, necesito reordenarlo según el orden de los ID en otra matriz (col. 1 here for both matrices). ¿Cómo puedo hacer esto usando vectorización? Por ejemplo:Ordenar una matriz según el orden dado en una segunda matriz (MATLAB)

bigmat = [ ... 
      1 10 ; 
      1 30 ; 
      1 40 ; 
      2 1 ; 
      2 11 ; 
      3 58 ; 
      4 2 ; 
      4 5 ] ; 

ordermat = [ 2 ; 1 ; 4 ; 3 ; 6] ;  % Integer IDs 

finalans = [ ... 
      2 1 ; 
      2 11 ; 
      1 10 ; 
      1 30 ; 
      1 40 ; 
      4 2 ; 
      4 5 ; 
      3 58 ; ] ; 

Es posible que todos los ID de algunos números enteros (aquí) en ordermat pueden no estar presentes en bigmat. Se pueden ignorar como se muestra arriba con id = 6. ¡Gracias!

+0

¿Qué quiere decir por vectorización? – Mark

+0

Quise decir sin usar un for-loop en bigmatrix. Espero que la solución use una función como 'ismember', etc. Bigmatrix tiene más de 0.5 millones de filas. – Maddy

Respuesta

1
%# Input values: 
bigmat = [1 10; 1 30; 1 40; 2 1; 2 11; 3 58; 4 2; 4 5]; 
ordermat = [ 2 ; 1 ; 4 ; 3 ; 6] ; 

%# Make a look-up table that tells us the relative order for each order id 
sortmat(ordermat) = 1:length(ordermat); 

%# Extract the order ID's from the big matrix 
keys = bigmat(:,1); 

%# Get the new ordering 
new_key = sortmat(keys); 

%# Sort the new ordering, remembering the permutation necessary 
[~, permutation] = sort(new_key); 

%# Apply the permutation to the big matrix 
finalans = bigmat(permutation, :); 
2

Aquí está mi solución:

ordermat = [2; 1; 4; 3; 6]; 
bigmat = [ 
    1 10 
    1 30 
    1 40 
    2 1 
    2 11 
    3 58 
    4 2 
    4 5 
]; 
%#bigmat = sortrows(bigmat,1); 

%# keep valid IDs, 
ord = ordermat(ismember(ordermat,bigmat(:,1))); 
ord = grp2idx(ord); 

%# starting/ending locations of the different IDs in bigmat 
startInd = find(diff([0;bigmat(:,1)])); 
endInd = [startInd(2:end)-1; size(bigmat,1)]; 

%# generate startInd(i):endInd(i) intervals 
ind = arrayfun(@colon, startInd, endInd, 'UniformOutput',false); 

%# order then combine the intervals of indices 
ind = [ind{ord}]; 

%# get final sorted result 
finalans = bigmat(ind,:); 

Me aseguré que maneja diferentes casos como:

  • ordermat contiene IDs no se encuentran en bigmat: ordermat = [2;1;4;3;6]
  • no están representados todos los ID de bigmat en ordermat: ordermat = [2;1]
  • IDs no secuenciales y/o no a partir de 1: ordermat=ordermat+10; bigmat=bigmat+10;
+0

¿'grp2idx' requiere la caja de herramientas de estadísticas? – nibot

+0

@nibot: sí, pero es una caja de herramientas muy popular que supongo que todos lo tienen :) – Amro

+0

podemos usar el tercer argumento de la función ÚNICA en lugar de GRP2IDX – Amro

0

que habíamos separado bigmat en trozos de acuerdo con los identificadores únicos, y luego volver a ordenar los trozos, como esto:

%# this assumes bigmat is sorted, btw 
%# i.e. that the different ids are grouped together 

%# find unique ids 
dd = [true;diff(bigmat(:,1))~=0]; 

uniqueIDs = bigmat(dd,1); 

%# reorder uniqueIDs 
[~,newOrder] = ismember(uniqueIDs,ordermat); 

%# if there are uniqueIDs that are not in ordermat 
%# we'd need to remove those. I assume this won't 
%# be the case 

%# chop up bigmat 
numUniqueIds = diff([find(dd);length(dd)+1]); 
bigChunks = mat2cell(bigmat,numUniqueIds,size(bigmat,2)); 

%# reorder chunks 
finalans = cat(1,bigChunks{newOrder}); 
+1

una alternativa es numerar ordermat, use intlut para reemplazar cada índice valor con su número, luego use sortrows, seguido por el intlut inverso. Espero que quede claro: no conozco suficiente matlab como para publicar una respuesta completa, por lo que lo agrego como comentario. –

Cuestiones relacionadas