2011-11-20 26 views
1

加權採樣我在矢量w索引和相應的權重的羣體p。我想獲得k來自該羣體的樣本沒有替換其中選擇與隨機權重成比例地完成。無需更換

我知道randsample可以說

J = randsample(p,k,true,w) 

用於選擇與更換,但是當我與參數false而不是true調用它,我得到

??? Error using ==> randsample at 184 
Weighted sampling without replacement is not supported. 

我寫我自己的函數as discussed in here

p = 1:n; 
J = zeros(1,k); 
for i = 1:k 
    J(i) = randsample(p,1,true,w); 
    w(p == J(i)) = 0; 
end 

但是因爲它在循環中有k迭代,我尋求一個更短/更快的方法來做到這一點。你有什麼建議嗎?

EDIT:我想隨機選擇k與某些權重標準成比例的矩陣的唯一列。這就是爲什麼我使用沒有更換的抽樣。

回答

3

我不認爲這是可能避免某種循環,因爲沒有替代抽樣意味着樣品不再是獨立的。此外,當沒有更換的抽樣時,加權實際上意味着什麼?

在任何情況下,對於相對較小的樣本大小,我不認爲你會發現有任何性能問題。我能想到的所有解決方案基本上都是做你所做的事情,但可能會擴大randsample中正在發生的事情。

+0

我找不到辦法做到這一點。這裏的算法(http://stackoverflow.com/questions/2140787/select-random-k-elements-from-a-list-whose-elements-have-weights)與我的類似,並在O(n + k ) 時間。感謝您的回覆。現在我會添加一個問題,爲什麼我需要這個。 – petrichor

1

我想你應該繼續使用了,但我建議由一個以減少相應的權重。

w(p == J(i)) = w(p == J(i)) -1; 
0

到執行好,如果採樣的數量比元件的數目小得多的Petrichor的for循環的方法的替代方法是計算與更換一個加權隨機樣品,然後刪除重複。當然,如果k的樣本數量接近元素數量n,這是一個非常糟糕的想法,因爲這需要很多次迭代,但是通過避免for循環,掛鐘性能通常更好。你的旅費可能會改變。

function I=randsample_noreplace(n,k,w) 
I = sort(randsample(n, k, true, w)); 
while 1 
    Idup = find(I(2:end)-I(1:end-1) ==0); 
    if length(Idup) == 0 
      break 
    else 
      I(Idup)=randsample(n, length(Idup), true, w); 
      I = sort(I); 
    end 
end 
0

如果你想選擇的列的很大一部分(即,k爲不大於N小很多),或者如果權重是非常扭曲,你可以用傑夫的解決方案,保證了該設計方案每次對randsample的調用都會產生與以前不同的樣本。

而且,它返回在其中無需更換真實採樣將返回他們,而不是排序順序的樣本。

function I=randsample_noreplace(n,k,w) 
I = randsample(n, k, true, w); 
while 1 
    [II, idx] = sort(I); 
    Idup = [false, diff(II)==0]; 
    if ~any(Idup) 
     break 
    else 
     w(I) = 0;   %% Don't replace samples 
     Idup (idx) = Idup; %% find duplicates in original list 
     I = [I(~Idup), (randsample(n, sum(Idup), true, w))]; 
    end 
end 

當選擇29出具有均勻權重30個值,它需要3本或4次迭代,26沒有額外線相比(即給出至少益處的情況下)的。如果權重是統一選擇的,它仍然需要3到5次迭代,相比之下,大約80次沒有額外的迭代。

此外,迭代的數量以k爲界,但分佈是偏斜的。

1

這仍然顯示在搜索結果中,所以我想添加datasample函數作爲選項。以下代碼將根據相應的矢量myWeights提供來自fromVector的5個單元的加權樣本。

mySample = datasample(fromVector, 5, 'Replace', false, 'Weights', myWeights)