1

我正在尝试分析大量数据,这些数据使我的程序运行缓慢。我正在将数据集从 .txt 文件读取到元胞数组。我正在使用一个单元格数组来对我的数据进行分类,它是两个属性的形式,我需要字符类。

我想使用最近的平均分类器找到重新替换错误。我有一个主要的外循环,它遍历我的数据集的每一行(数万行)。依次删除每一行,每次迭代一个。每次迭代都会重新计算两个属性的平均值,并删除线。主要的挂点似乎是我要为数据集中的每一行计算的下一部分:

  • 那条线上的数据(2个属性值)与我的每个类的平均值之间的欧几里得距离。
  • 然后我想记录其平均值最接近属性平均值的类,这将是其分配的类。
  • 最后我想检查这个分配的班级是否是正确的班级。

目前这个循环看起来像这样。

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是包含我的每个属性的平均值的数组。当删除一行时,这些在外部循环的每次迭代中都会更新。

希望这可以帮助您理解我拥有的代码。非常感谢在优化和加速这些计算方面的任何帮助。

4

3 回答 3

2

最简单的速度改进是删除sqrt呼叫。找到最近距离的平方与最近距离完全相同。

接下来,您可以对内部循环进行矢量化。自从我做任何 MatLab 以来已经很长时间了,所以我可能会弄错下面的代码,但我的想法是将这两个属性变成一个长度向量numel(classes)。然后您可以直接计算差异并将它们平方。

像这样的东西:

d1 = attribute1 - meansattr1;
d2 = attribute2 - meansattr2;
[closest, class] = min( d1 .* d1 + d2 .* d2 );

顺便说一句,class用作变量(如果可以的话)并不是一个好主意。这是一个保留字。

于 2013-10-21T22:36:13.303 回答
1

您本质上是在优化 k-means 算法的迭代部分,因此您可以参考我之前的解决方案来获取矢量化方法。但是,这是针对您的问题和数据格式的方法。

取一个如下所示的随机数据集,

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中的结果等价于前面的解。如代码注释所示,您可以删除 sqrt 并在 and 中获得相同的结果。closestDistancenearestClustererrorCountnearestCluster

假设您要进行下一步更新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>THRESHorfor jj = 1:MAXITER中,你应该得到你想要的。

于 2013-10-22T00:44:50.870 回答
0

我从水稻的解决方案开始,简单地替换变量名:

[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”或任何其他保留字用于其他目的。

于 2013-10-21T23:42:05.250 回答