2013-03-15 53 views
3

我有一個向量和單元格陣列(與重複的字符串)具有相同的大小。單元格數組定義組。我想在每個組的向量中查找最小/最大值。準確的指數與最大/最小

例如:

value = randperm(5) %# just an example, non-unique in general 
value = 
    4  1  2  3  5 
group = {'a','b','a','c','b'}; 
[grnum, grname] = grp2idx(group); 

我使用ACCUMARRAY函數爲這樣:

grvalue = accumarray(grnum,value,[],@max); 

所以我有唯一的組名稱(grname)和新的載體(grvalue)新單元陣列。

grname = 
    'a' 
    'b' 
    'c' 
grvalue = 
    4 
    5 
    3 

但我還需要找到已包含在新向量中的舊向量的值的位置索引。

gridx = 1 5 4 

任何想法?沒有必要使用準系統,但我正在尋找快速矢量化解決方案。

+1

你使用哪種matlab版? – Jonas 2013-03-15 21:04:42

+0

@Jonas:2012b,Windows7 x64。 – yuk 2013-03-15 23:19:35

回答

1

最好的量化答案,我可以看到的是:

gridx = arrayfun(@(grix)find((grnum(:)==grix) & (value(:)==grvalue(grix)),1),unique(grnum)); 

,但我不能說這是一個「快」矢量化的解決方案。 arrayfun真的很有用,但通常不會比循環更快。


但是,最快的答案並不總是矢量化的。如果我重新實現代碼,你寫它,但有一個更大的數據集:

nValues = 1000000; 
value = floor(rand(nValues,1)*100000); 
group = num2cell(char(floor(rand(nValues,1)*4)+'a')); 
tic; 
[grnum, grname] = grp2idx(group); 
grvalue = accumarray(grnum,value,[],@max); 
toc; 

我的電腦給我的0.886秒抽動/ TOC時間。 (注意,所有tic/tock時間來自文件中定義的函數的第二次運行,以避免一次性生成pcode。)

添加「矢量化」(真的是arrayfun)一行gridx計算導致tic/tock時間爲0.975秒。還不錯,另外一項調查顯示大部分時間都在撥打grp2idx電話。

如果我們重新實現這個作爲一個非矢量化,簡單的循環,包括gridx計算,像這樣:

tic 
[grnum, grname] = grp2idx(group); 
grvalue = -inf*ones(size(grname)); 
gridx = zeros(size(grname)); 
for ixValue = 1:length(value) 
    tmpGrIdx = grnum(ixValue); 
    if value(ixValue) > grvalue(tmpGrIdx) 
     grvalue(tmpGrIdx) = value(ixValue); 
     gridx(tmpGrIdx) = ixValue; 
    end 
end 
toc 

抽動/ TOC時間約爲0.847秒,稍微比原來的代碼快。


採取這種有點進一步,大部分時間出現在細胞陣列的存儲器訪問丟失。例如:

tic; groupValues = double(cell2mat(group')); toc %Requires 0.754 seconds 
tic; dummy  =  (cell2mat(group')); toc %Requires 0.718 seconds 

如果您最初定義組名稱爲數字陣列(例如,我將使用groupValues正如我上面所定義它們),該時間減少了不少,甚至使用相同的代碼:

groupValues = double(cell2mat(group')); %I'm assuming this is precomputed 
tic 
[grnum, grname] = grp2idx(groupValues); 
grname = num2cell(char(str2double(grname))); %Recapturing your original names 
grvalue = -inf*ones(size(grname)); 
gridx = zeros(size(grname)); 
for ixValue = 1:length(value) 
    tmpGrIdx = grnum(ixValue); 
    if value(ixValue) > grvalue(tmpGrIdx) 
     grvalue(tmpGrIdx) = value(ixValue); 
     gridx(tmpGrIdx) = ixValue; 
    end 
end 
toc 

這產生了0.16秒的tic/tock時間。

+0

謝謝,我會嘗試你的代碼。 – yuk 2013-03-15 21:09:54

1

當面對類似的問題*,我想出了這個解決方案:

  • 定義下列函數(在.m文件)

    function i=argmax(x) 
        [~,i]=max(x); 
        end 
    
  • 那麼你就可以找到最大位置爲

    gridx = accumarray(grnum,grnum,[],@(i)i(argmax(value(i)))); 
    
  • 和最大值爲

    grvalue = value(gridx); 
    

(*如果我正確地理解您的問題)