2014-10-02 68 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秒。