找到正确的循环

时间:2016-09-11 12:14:41

标签: matlab loops vectorization cell-array

我有一个由80k行组成的数据集。它存储在一个单元格中。 在第三列中,值应该在第一行中为-3,在第三行中为-2,在第二列中为-2,依此类推,直到整个数据集。 作为:

-3
-2
-1
-3
-2
-1
...

现在我想检查整个数据集中是否实际遵循了这个数字序列。我知道事实并非如此,因此我想制作某种循环,自动删除不遵循-3,-2,-1步骤的整行数据。

我最初的想法是使用diff命令来更改索引,但似乎无法正确使用。

其次是创建一个循环,每当它没有遵循特定的数字序列时就会删除数据。

for i = 1:length(Dataset)
    if Dataset{272,1}(i,3) == -3
        continue
    else
        eraseidx = Dataset{272,1}(i,3)
        if Dataset{272,1}(i+1,3) == -2
            continue
        else
            eraseidx = Dataset{272,1}(i,3)
            if Dataset{272,1}(i+2,3) == -1
                continue
            else
                eraseidx = Dataset{272,1}(i,3)
            end
        end
    end
end

(选择Dataset{272,1}的原因是我知道存在错误。)

任何人都有解决这个问题的方法吗?

1 个答案:

答案 0 :(得分:0)

你的循环存在一个主要问题:你将所有条件嵌套在彼此之下,所以只有当第一个条件i+1时才检查i+2false,但是你再次检查当你进入循环的下一次迭代时对他们来说。如果Dataset{272,1}(i+1,3) == -2,那么您已经知道在下一次迭代中(当您将Dataset{272,1}(i,3)-3进行比较时),它将返回false,但它是falsetrue?根据你的循环,它取决于何时你问这个......

以下两个选项可以解决这个问题,仍然使用循环。第一种方式循环所有k(我用i替换k以不覆盖MATLAB中的虚数单位),但将Dataset{272,1}(i+1,3)与不同的数字进行比较:< / p>

c = [-1 -3 -2];
for k = 1:length(Dataset)
    if Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
        eraseidx = Dataset{272,1}(k,3);
    end
end

另一个选择是比较三元组中的数据:

for k = 1:3:length(Dataset)
    if Dataset{272,1}(k,3) ~= -3
        eraseidx = Dataset{272,1}(k,3);
    end
    if Dataset{272,1}(k+1,3) ~= -2
        eraseidx = Dataset{272,1}(k+1,3);
    end
    if Dataset{272,1}(k+2,3) ~= -1
        eraseidx = Dataset{272,1}(k+2,3);
    end
end

现在您只将有问题的记录保存到eraseidx,但每次满足任何条件时都会覆盖它,因此您还需要索引eraseidx

eraseidx = zeros(length(Dataset),1);
c = [-1 -3 -2];
for k = 1:length(Dataset)
    if Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
        eraseidx(k) = Dataset{272,1}(k,3);
    end
end

但是,如果您只想删除这些记录,则可以将k单独保存为逻辑索引,而不是所有记录。此外,在我看来,你的循环应该在1:length(Dataset{272,1})上运行,所以:

eraseidx = false(length(Dataset{272,1}),1);
c = [-1 -3 -2];
for k = 1:length(Dataset{272,1})
    eraseidx(k) = Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
end

这可以轻松地矢量化为:

c = [-1 -3 -2];
k = 1:length(Dataset{272,1});
eraseidx = Dataset{272,1}(k,3) ~= c(mod(k,3)+1).';

所以现在eraseidx将是一个逻辑向量,因此Dataset{272,1}(eraseidx,:)将是Dataset{272,1}中要删除的所有记录。 修改:要删除它们,您只需撰写:Dataset{272,1}(eraseidx,:) = []

对所有Dataset

进行矢量化

如果所有单元格中的所有数据都具有相同的大小和形状,您可以使用cell2mat将其转换为ND阵列,然后立即对所有数据执行矢量化操作:

data = reshape(cell2mat(Dataset.'),[],3,numel(Dataset)); % convert to 3D array
c = [-1 -3 -2];
k = 1:size(data,1);
correct = c(mod(k,3)+1).'; % the correct values to compare 
eraseidx = squeeze(bsxfun(@ne,data(:,3,:),correct));

现在eraseidx中的每一列都对应Dataset中的第三列,因此Dataset(k,1)的结果在eraseidx(:,1)中给出。
要删除true中的所有eraseidx条记录,您可以使用简单的循环:

for k = 1:numel(Dataset)
    Dataset{k}(eraseidx(:,k),:) = [];
end

请注意,您无法直接从data删除记录,因为数组在第三维的每个元素中的行数不同。

如果Dataset必须是单元格数组......

如果您使用单元格将数据保存在Dataset中,因为它的大小和形状不同,您可以针对所有过程调整上述循环:

c = [-1 -3 -2];
for k = 1:numel(Dataset)
    eraseidx = Dataset{k,1}(:,3) ~= c(mod(1:length(Dataset{k,1}),3)+1).';
    Dataset{k,1}(eraseidx,:) = [];
end

或者您可以使用cellfun(基本上是一个紧凑的循环):

c = [-1 -3 -2];
delfun = @(M) M(M(:,3)==c(mod(1:length(M),3)+1).',:);
Dataset_fixed = cellfun(delfun,Dataset,'UniformOutput',false);

delfun是一个匿名函数,只检索Dataset中每个单元格的所需记录。现在Dataset_fixedDataset,没有删除的行。