我有一个由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}
的原因是我知道存在错误。)
任何人都有解决这个问题的方法吗?
答案 0 :(得分:0)
你的循环存在一个主要问题:你将所有条件嵌套在彼此之下,所以只有当第一个条件i+1
时才检查i+2
和false
,但是你再次检查当你进入循环的下一次迭代时对他们来说。如果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)
与不同的数字进行比较:< / 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_fixed
是Dataset
,没有删除的行。