2014-10-02 95 views
0

我在Matlab中解析數據文件來繪製它。我解析的數據有3列:用parfor填充地圖

category | x | y

該文件可能有任何類別的幾個點。爲了將它們組合在一起並獲得正確的圖例,我需要對數據進行排序,以便每個類別生成一個n x 2矩陣,它表示給定類別中的n點。

在下面的摘錄中,不用擔心解析,而是重要的部分是如何添加地圖。 category是關鍵,而newVal是單個x-y對值,需要連接到該點的矩陣。

disp('Sorting categories...') 
map = containers.Map(); 
for i = 2:size(data,2) 
    str = strsplit(data{i}, '\t'); 
    category = strsplit(str{1}, '.'); 
    category = category{1}; 
    newVal=sscanf([str{2} ',' str{3}],'%f,%f')'; 

    %Interesting stuff starts here 
    if(isKey(map, category)) 
     mapVal = [map(category); newVal]; 
    else 
     mapVal = newVal; 
    end 

    map = [map; containers.Map(category, mapVal)]; 
end 

這需要有59K點的時間太長了,我真的想給for變成parfor。我的過程需要在map變量上進行讀 - 修改 - 寫操作,這是行不通的。我想代碼做這樣的事情,而不是(假設它會更快,這可能不是真的反正):

disp('Sorting categories...') 
map = containers.Map(); 
for i = 2:size(data,2) 
    str = strsplit(data{i}, '\t'); 
    category = strsplit(str{1}, '.'); 
    category = category{1}; 
    newVal=sscanf([str{2} ',' str{3}],'%f,%f')'; 

    maps{i} = containers.Map(category, mapVal); 

end 
map = [maps{:}]; 

然而,在Matlab串聯地圖導致被覆蓋,而不是附加價值。這將導致每個類別僅保留該類別的最後解析點。有沒有辦法避免這種行爲?

+1

我認爲使用'map(category)= mapVal;'代替'map = [map; containers.Map(category,mapVal)];'在你提供的第一個代碼中。 – Marcin 2014-10-02 23:37:22

+0

@Marcin是的,現在你提到它了,是不是我認爲大聲笑 – Suedocode 2014-10-03 16:24:45

回答

1

雖然我很喜歡,促進PARFOR和PARFEVAL,我真的認爲這是爲ACCUMARRAY工作。這是一個非常接近你的問題。在第一部分中,我綜合了一些數據 - 在您的真實情況下,我建議您旨在從一個文件中讀取所有數據(可能使用TEXTSCAN)。無論如何,一旦你完成了這個任務,我們的想法就是將類別轉換爲數字形式,然後致電accumarray將結果收集在同一類別中。 accumarray是一個棘手的野獸掌握,所以也許本領域更熟練的人可以找出比我正在做的兩個電話更好的方式 - 但在我的機器上,accumarray件運行在0.02秒...

% Generate some data rather than reading from a file 
N = 59000; 
allCats = {'foo', 'bar', 'baz'}; 
categoryData = allCats(randi([1,numel(allCats)], N, 1)); 
xyData = rand(N, 2); 

% work out which category each row is in (in your case, you could 
% first generate allCats using "unique(categoryData)" 
[allCats, ~, whichCategory] = unique(categoryData); 

% Use accumarray to build up one cell array for each category, once 
% each for the x and y data 
tic 
xByCategory = accumarray(whichCategory, xyData(:,1), [], @(x){x}); 
yByCategory = accumarray(whichCategory, xyData(:,2), [], @(x){x}); 
toc 
+0

獨特是太棒了,並沒有循環使matlab走得像我原本預期的那樣快。 – Suedocode 2014-10-03 20:26:48

1

我不確定有多少時間太長。這個腳本把我帶到52歲,完成使用6名工人。 parfor爲22秒,合併循環爲29sec。它不優雅,但它確實應用了一個parfor循環。您可以使用parfevalfetchnext函數進一步提高速度。 fetchnext將允許您在容器可用時合併容器,從而在工作人員仍然構建地圖容器時執行合併。我猜測這將會轉化爲比52s大概30秒的時間。

注意,parfevalfetchnext僅在2013b及更高版本中可用。

% Create some test data 
N = 59000; 
aa(:,1) = 10*rand(N,1); 
% aa(:,1) = [1 2 2 4 5 6 6 8 9 10]; 
aa(:,2) = rand(N,1); 
aa(:,3) = rand(N,1); 
data = strtrim(cellstr(num2str(aa,'%g,%g,%g'))'); 


ndata = size(data,2); 
p = gcp; 
if isempty(p) 
    NumWorkers = 1; 
else 
    NumWorkers = p.NumWorkers; 
end 

tic; 
% work out the indices for each worker 
numchunks = ceil(ndata/NumWorkers); 
for kk = 1:numchunks 
    strt = (kk-1)*NumWorkers+1; 
    endl = kk*NumWorkers; 
    if endl > ndata 
     endl = ndata; 
    end 
    ind{kk} = strt:endl; 
end 

maps = cell(0); 
parfor jj = 1:numel(ind) 
%  disp('Sorting categories...') 
    maps{jj,1} = containers.Map(); 
    for i = 1:numel(ind{jj}) 
     str = strsplit(data{ind{jj}(i)}, ','); 
     category = strsplit(str{1}, '.'); 
     category = category{1}; 
     newVal=sscanf([str{2} ',' str{3}],'%f,%f')'; 

     %Interesting stuff starts here 
     if(isKey(maps{jj,1}, category)) 
      mapVal = [maps{jj,1}(category); newVal]; 
     else 
      mapVal = newVal; 
     end 

     maps{jj,1} = [maps{jj,1}; containers.Map(category, mapVal)]; 

    end 
end 

% merge your map containers one-by-one 
for kk = 2:numel(maps) 
    auxkeys = maps{1}.keys; 
    currkeys = maps{2}.keys; 
    [ia,ib] = ismember(currkeys,auxkeys); 
    if any(ia) 
     ia = find(ia); 
     for mm = 1:numel(ia) 
      maps{1}(auxkeys{ib(ia(mm))}) = [maps{1}(auxkeys{ib(ia(mm))}); maps{2}(currkeys{ia(mm)})]; 
      remove(maps{2},currkeys{ia(mm)}); 
     end 
    end 
    maps{1} = [maps{1}; maps{2}]; 
    maps(2) = []; 
end 
toc 
0

不幸的是,我不能評論接受的答案,因爲我寧願將它插入那裏。我發現這個問題是一個很好的學習經歷,因爲我從來沒有使用maps.containersaccumarray函數。我對accumarray感興趣,並試圖將其應用於我自己的問題之一,但我發現它要慢得多。在這種情況下,我有一個帶有5e6個元素的向量,並且我將8e5個類別分組並且採用值的L2規範。然後,我決定在這裏採用類似的方法解決問題。我發現沒有使用accumarray更快地成爲頭髮。下面是我做的,

tic; 
xyByCategory = cell(numel(allCats),1); 
for kk = 1:numel(allCats) 
    xyByCategory{kk} = xyData(strcmp(categoryData,allCats{kk}),:); 
end 
toc 
使用N = 6E6

accumarray方法在回答


經過時間是0.611510秒。

上述方法
已用時間爲0.429321秒。