用parfor填充地图
我在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串联地图导致被覆盖,而不是附加价值。这将导致每个类别仅保留该类别的最后解析点。有没有办法避免这种行为?
虽然我很喜欢,促进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
独特是太棒了,并没有循环使matlab走得像我原本预期的那样快。 – Suedocode 2014-10-03 20:26:48
我不确定有多少时间太长。这个脚本把我带到52岁,完成使用6名工人。 parfor为22秒,合并循环为29sec。它不优雅,但它确实应用了一个parfor循环。您可以使用parfeval
和fetchnext
函数进一步提高速度。 fetchnext
将允许您在容器可用时合并容器,从而在工作人员仍然构建地图容器时执行合并。我猜测这将会转化为比52s大概30秒的时间。
注意,parfeval
和fetchnext
仅在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
不幸的是,我不能评论接受的答案,因为我宁愿将它插入那里。我发现这个问题是一个很好的学习经历,因为我从来没有使用maps.containers
或accumarray
函数。我对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秒。
我认为使用'map(category)= mapVal;'代替'map = [map; containers.Map(category,mapVal)];'在你提供的第一个代码中。 – Marcin 2014-10-02 23:37:22
@Marcin是的,现在你提到它了,是不是我认为大声笑 – Suedocode 2014-10-03 16:24:45