我正在尝试分析大量数据,这些数据让我的程序运行缓慢。 我正在读取从.txt文件到单元格数组的数据集。 我正在使用一个单元格数组,以便对我的数据进行分类,这是两个属性的形式,我需要的是chars类。
我想使用最近的平均分类器找到重新替代错误。 我有一个主外环循环遍历我的数据集的每一行(数万)。依次移除每一行,每次迭代一行。在每次迭代时重新计算两个属性的平均值,并删除该行。主挂点似乎是我要为我的数据集中的每一行计算的下一部分:
目前这个循环看起来像这样。
errorCount = 0;
for l = 1:20000
closest = 100;
class = 0;
attribute1 = d{2}(l);
attribute2 = d{3}(l);
for m = 1:numel(classes)
dist = sqrt((attribute1-meansattr1(m))*(attribute1-meansattr1(m)) + (attribute2-meansattr2(m))*(attribute2-meansattr2(m)));
if dist < closest
closest = dist;
class = m;
end
end
if strcmp(d{1}(l),classes(class))
%correct
else
errorCount = errorCount + 1;
end
end
d
是我的单元格数组,d{2}
是一个包含属性1值的列。我使用d{1}(1)
为该列的第一行访问这些值。
classes
是我的数据集中的唯一类,因此对于我的每个类,我都计算了它的欧几里德距离。
meansattr1
和meansattr2
是包含每个属性的平均值的数组。当删除一行时,这些会在外循环的每次迭代中更新。
希望这可以帮助您理解我拥有的代码。非常感谢任何有关优化和加速这些计算的帮助。
答案 0 :(得分:2)
最简单的速度提升是删除sqrt
电话。找到最近的平方距离与最近的距离完全相同。
接下来,您可以向内循环进行矢量化。我做了任何MatLab已经很久了,所以我可能会得到以下代码错误,但我们的想法是将这两个属性变成长度为numel(classes)
的向量。然后你可以直接计算差异并将它们平方。
这样的事情:
d1 = attribute1 - meansattr1;
d2 = attribute2 - meansattr2;
[closest, class] = min( d1 .* d1 + d2 .* d2 );
顺便说一下,使用class
作为变量(如果你能做到的话)并不是一个好主意。这是一个保守的词。
答案 1 :(得分:1)
您实际上是在优化k-means算法的迭代部分,因此您可以参考my previous solution来获取矢量化的方法。但是,您可以按照以下方式处理问题和数据格式。
获取如下随机数据集
numClasses = 5;
numPoints = 20e3;
numDims = 2;
classes = strsplit(num2str(1:numClasses));
% generate random data (expected error rate of (numClasses-1)/numClasses)
d{1} = classes(randi(numClasses,numPoints,1));
d{2} = rand(numPoints,1);
d{3} = rand(numPoints,1);
% random initial class centers
meansattr1 = rand(5,1);
meansattr2 = rand(5,1);
您的代码,压缩并存储每个点的最接近的类ID以及与该类的距离变为:
closestDistance = zeros(numPoints,1); nearestCluster = zeros(numPoints,1);
errorCount = 0;
for l = 1:numPoints
closest = 100; iclass = 0;
attribute1 = d{2}(l); attribute2 = d{3}(l);
for m = 1:numel(classes)
dist = sqrt((attribute1-meansattr1(m))*(attribute1-meansattr1(m)) + ...
(attribute2-meansattr2(m))*(attribute2-meansattr2(m)));
if dist < closest
closest = dist; closestDistance(l) = closest;
iclass = m; nearestCluster(l) = iclass;
end
end
if ~strcmp(d{1}(l),classes(iclass))
errorCount = errorCount + 1;
end
end
以上的矢量化版本是:
data = [d{2}(:) d{3}(:)];
meansattr = [meansattr1(:) meansattr2(:)];
kdiffs = bsxfun(@minus,data,permute(meansattr,[3 2 1]));
allDistances = sqrt(sum(kdiffs.^2,2)); % no need to do sqrt
allDistances = squeeze(allDistances); % Nx1xK => NxK
[closestDistance,nearestCluster] = min(allDistances,[],2); % Nx1
correctClassIds = str2num(char(d{1}(:)));
errorCount = nnz(nearestCluster ~= correctClassIds);
errorCount
,closestDistance
和nearestCluster
中的结果与之前的解决方案相同。您可以删除sqrt并在errorCount
和nearestCluster
中获得相同的结果,如代码注释所示。
假设您要执行更新meansattr1
和meansattr2
的下一步:
% Calculate the NEW cluster centers (mean the data)
meansattr_new = zeros(numClasses,numDims);
clustersizes = zeros(numClasses,1);
for ii=1:numClasses,
indk = nearestCluster==ii;
clustersizes(ii) = nnz(indk);
meansattr_new(ii,:) = mean(data(indk,:))';
end
meansattr1_next = meansattr_new(:,1);
meansattr2_next = meansattr_new(:,2);
将这一切全部放在while errorCount>THRESH
或for jj = 1:MAXITER
中,你应该拥有你想要的东西。
答案 2 :(得分:0)
我开始使用paddy的解决方案,简单地替换变量名称:
[closest, cl] = min( (d{2}(m) - meansattr1).^2 +(d{3}(m) - meansattr2).^
2);
因此我们有一个单行for循环,通用策略:创建它的函数并将其放入arrayfun:
f=@(x)min( (d{2}(x) - meansattr1).^2 +(d{3}(x) - meansattr2).^2)
[sqclosest,cl]=arrayfun(f,1:numel(d{2}));
%If necessary real distances could be calculated:
%closest=sqrt(sqclosest)
errorCount=sum(arrayfun(@(x,c)(1-strcmp(x,classes(c))),d{1},cl))
注意:请勿将“class”或任何其他保留字用于其他目的。