【问题标题】:Finding correct loop找到正确的循环
【发布时间】:2016-09-11 12:14:40
【问题描述】:

我有一个包含 80k 行的数据集。它存储在一个单元格中。 在第三列中,值应该是第一行中的 -3,第二行中的 -2,第三列中的 -1,依此类推,贯穿整个数据集。 如:

-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}的原因是我知道有故障)。

谁有办法解决这个问题?

【问题讨论】:

    标签: matlab loops vectorization cell-array


    【解决方案1】:

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

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

    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) 中给出。
    要删除 eraseidx 中的所有 true 记录,您可以使用简单的循环:

    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 没有删除的行。

    【讨论】:

    • 感谢您的回复。当它应该贯穿整个数据集而不仅仅是 Dataset{272,1} 时,我可以对其进行矢量化吗?此外,当我运行Dataset{272,1}(eraseidx,3) 时,它不会删除“损坏”的数字,而只会返回数据集中的循环出错的两个数字(在本例中为 -2 和 -1)
    • @user3161344 查看我对所有 Dataset 进行矢量化并删除记录的编辑。
    • @user3161344 如果这回答了您的问题,请告诉我,如果可以,请考虑upvote/accepting
    猜你喜欢
    • 1970-01-01
    • 2015-10-10
    • 2019-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多