2014-08-29 47 views
5

MATLAB'da, her bir sütunu rastgele karıştırmak için shake.m işlevini (http://www.mathworks.com/matlabcentral/fileexchange/10067-shake) kullanıyorum. Örneğin:MATLAB'da bir matrisi rastgele karıştırmanın daha iyi/daha hızlı bir yolu var mı?

a = [1 2 3; 4 5 6; 7 8 9] 
a = 

    1  2  3 
    4  5  6 
    7  8  9 

b = shake(a) 
b = 

    7  8  6 
    1  5  9 
    4  2  3 

Bu fonksiyon, istediğim tam olarak ne yapar ancak benim sütunları olan çok uzun (> 10.000.000) ve bu nedenle bu çalıştırmak için uzun zaman alır. Bunu gerçekleştirmenin daha hızlı bir yolu bilen var mı? Her sütun vektörünü ayrı ayrı çalmaya çalıştım ama bu daha hızlı değil. Teşekkürler!

+0

Bu shake işlevine bakıldığında tamamen vectorized görünüyor, ancak bir matrisin sütun şeklinde sıralamasını kullanır. Yani Sizin durumunuzda, şaşırtıcı derecede yavaş olan> 10.000.000 satır içeren sütunları sıralar. – Nras

cevap

5

İşte basit bir vektörel yaklaşım. a ile aynı boyutta bir yardımcı matris (ind) oluşturduğuna dikkat edin, bu nedenle belleğinize bağlı olarak kullanılabilir veya olmayabilir.

[~, ind] = sort(rand(size(a))); %// create a random sorting for each column 
b = a(bsxfun(@plus, ind, 0:size(a,1):numel(a)-1)); %// convert to linear index 
+0

+ 1 bu çok akıllı. – Dan

+0

@Dan Fikir (vektörize sıralama) [sizden geldi] (http://stackoverflow.com/a/25547312/2586922) :-) –

+0

+1 Gerçekten çok ilginç bir yaklaşım! Eh, bu tür çözümümde darboğaz olduğunu kanıtladı. – Divakar

5

vektör karıştırmak randperm

idx = randperm(size(a,1)); 

Kullanım endeksleri kullanılarak karıştırılır endeks edinin: Bu cevaba

m = size(a,1); 
for i=1:m 
b(:,i) = a(randperm(m,:); 
end 

bak: Matlab: How to random shuffle columns of matrix

+0

'a' bir vektör değil ... – Dan

+0

@lakesh bunun için teşekkürler - b için yukarıda sahip olduğum çıktı matrisini gerçekten elde etmek için bunu nasıl kullandığımı bilmiyorum. Sütunları dikey olarak karıştırmak istiyorum, yani sallayın ([1 4 7]); çalkalayın ([2 5 8]); çalkalayın ([3 6 9]); – user2861089

+0

@Dan, şimdiden düzeltildi .. – lakesh

8

Böyle randperm kullanabilirsiniz, ancak ben shake'dan daha hızlı olup olmayacağını bilmiyorum:

[m,n]=size(a) 
for c = 1:n 
    a(randperm(m),c) = a(:,c); 
end 

Yoksa etrafında randperm daha hızlı olduğunu görmek için (aynı sonucu üretmelidir) geçiş deneyebilirsiniz:

[m,n]=size(a) 
for c = 1:n 
    a(:,c) = a(randperm(m),c); 
end 

sen Aksi kaç satır var?

[m,n]=size(a) 
cols = randperm(n); 
k = 5; %//This is a parameter you'll need to tweak... 
set_size = floor(n/k); 
for set = 1:set_size:n 
    set_cols = cols(set:(set+set_size-1)) 
    a(:,set_cols) = a(randperm(m), set_cols); 
end 

kitlesel randperm yapılan aramaların sayısını azaltacak: sütun çok daha az satır varsa, her permütasyon böyle bir şey hakkında tekrarlanan, ne yani edilecektir varsayabiliriz olasıdır. k eşit büyüklükteki kümelere ayırmak en uygun olmayabilir, bununla birlikte biraz rasgelelik eklemek de isteyebilirsiniz. Bununla birlikte, buradaki temel fikir, sadece factorial(m) farklı düzenlerin olacağıdır ve m, n'dan (örneğin, m=5, verileriniz gibi n=100000) çok daha küçükse, bu sıralamalar doğal olarak tekrarlanacaktır. Dolayısıyla, bunun kendiliğinden gerçekleşmesine izin vermek yerine süreci yönetin ve aynı sonucu üretecek olan çağrıları randperm'a azaltın.

+0

Teşekkürler @Dan! 10.000.000 satır ve 5 sütunum var ... 1000 satırlık veri üzerinde hızlı bir profil özeti hazırladım ve ilk iki seçeneğiniz zaten sallamaktan daha hızlı! Muhteşem. Üçüncü öneriyi deneyecek. – user2861089

+1

@ user2861089 üçüncü ile dikkat, 'k' parametresine bağlı olarak ilk iki kadar rastgele olmayabilir. Her randevuyu * randperm'in ortalama * * n/faktoriyel (m) sütunlarını etkilemesi * istiyorsun. – Dan

4

Tüm endeksleri bir kerede işlediğinden döngüsel olmayan bir yaklaşım var ve bunun yalnızca her bir sütun arasında karıştırmanın gereklilikleri göz önüne alındığında bu kadar rastgele olduğuna inanıyorum.

Kod

%// Get sizes 
[m,n] = size(a); 

%// Create an array of randomly placed sequential indices from 1 to numel(a) 
rand_idx = randperm(m*n); 

%// segregate those indices into rows and cols for the size of input data, a 
col = ceil(rand_idx/m); 
row = rem(rand_idx,m); 
row(row==0)=m; 

%// Sort both these row and col indices based on col, such that we have col 
%// as 1,1,1,1 ...2,2,2,....3,3,3,3 and so on, which would represent per col 
%// indices for the input data. Use these indices to linearly index into a 
[scol,ind1] = sort(col); 
a(1:m*n) = a((scol-1)*m + row(ind1)) 

nihai çıkış kendisi a elde edilir.

+0

Teşekkürler @Divakar - sadece bunu test ettim ama yukarıdaki cevaplar kadar hızlı değil. Yine de teşekkürler! – user2861089

+0

@Divakar, lütfen bir açıklama ekleyin - özellikle son satırınız – Dan

+0

@Dan Son satır, 'sub2ind' elkitabına benziyor. Manuel olarak yapmak genellikle 'sub2ind' den daha hızlıdır. –

İlgili konular