在第一个否定之后将元素转换为NaN

时间:2015-03-06 21:19:17

标签: matlab

我在Matlab中有一个三维数组。第一个维度是时间,第二个维度是湿度,第三个维度是温度。如果温度值<1。 0,我希望每个后续温度值都变为NaN。

例如,如果数组是:

>> sampl = randn(4,3,2)

sampl(:,:,1) =

  0.79487     0.71017     -0.39167
  0.51754     -1.3068     0.84166
  0.49461     0.74159     0.082784
  0.66393     1.4677      0.31467


sampl(:,:,2) =

  0.78981      1.3096        1.0434
 -0.80122      0.16037      -1.0682
 -0.32565      -2.1182      -0.31723
  0.28468      0.70708      1.4797

将此转化为最有效的方法是什么:

sampl(:,:,1) = 

  0.79487     0.71017     NaN
  0.51754     NaN         NaN
  0.49461     NaN         NaN
  0.66393     NaN         NaN


sampl(:,:,2) =

  0.78981     1.3096      1.0434
  NaN         0.16037     NaN
  NaN         NaN         NaN
  NaN         NaN         NaN

具体来说,对于特定切片,我们希望沿着每一列进行处理,一旦我们在一列中遇到负数,我们希望该位置为NaN以及该列的所有行位置跟随此NaN值的同一列也是NaN

3 个答案:

答案 0 :(得分:7)

另一种简单的方法是在原始矩阵中找到负数的位置,创建另一个矩阵,将这些值设置为NaN,为每个行调用cumsum或累积和在此新矩阵的每个切片中的列,然后将此cumsum结果中的相应位置设置为原始矩阵中的NaN,以获得最终结果:

>> out = sampl;
>> out(out < 0) = NaN;
>> out = cumsum(out);
>> sampl(isnan(out)) = NaN

sampl(:,:,1) =

    0.7949    0.7102       NaN
    0.5175       NaN       NaN
    0.4946       NaN       NaN
    0.6639       NaN       NaN


sampl(:,:,2) =

    0.7898    1.3096    1.0434
       NaN    0.1604       NaN
       NaN       NaN       NaN
       NaN       NaN       NaN

cumsum在这里有用的原因是因为我们基本上会沿着行独立地检查每个列,并且在每个列的所有行上累积,这些行具有有效的条目直到我们为列命中NaN值。在此值之后,cumsum中的后续值将独立地变为每个切片中每列的NaN。因此,在我们点击列中的第一个NaN后,无论我们在(NaN或有效数字)之后遇到什么值,cumsum中的结果仍然是{{ 1}}。在我们遇到矩阵列中的第一个负数后,这会有效地传播NaN值。最后一点是在此矩阵中找到这些位置,并将原始矩阵中的相应位置设置为NaN,从而得出我们的结果。

答案 1 :(得分:4)

以下是使用accumarray的解决方案。

首先,获取行数并重新整形sampl以获得2D数组;它更容易使用:

NumRow = size(sampl,1);

a = reshape(sampl,NumRow,[])

a看起来像这样:

a =

    0.7949    0.7102   -0.3917    0.7898    1.3096    1.0434
    0.5175   -1.3068    0.8417   -0.8012    0.1604   -1.0682
    0.4946    0.7416    0.0828   -0.3256   -2.1182   -0.3172
    0.6639    1.4677    0.3147    0.2847    0.7071    1.4797

然后找到每列的第一行索引为负数:

[row,col] = find(a<0);
b = accumarray(col,row,[],@min);

现在b看起来像这样:

b =

     0
     2
     1
     2
     3
     2

在插入NaN之前,更改0,以便使用冒号操作符不使用NaN填充整个列(请参阅下一步):

b(b==0) = NumRow+1;

最后循环遍历数组并从b中的相应索引开始插入NaN,直到每列的最后一行。同时重塑a以获得与初始数组相同的大小:

for k = 1:size(a,2)
a(b(k):NumRow,k) = NaN;
end

out = reshape(a,size(sampl))

输出:

out(:,:,1) =

    0.7949    0.7102       NaN
    0.5175       NaN       NaN
    0.4946       NaN       NaN
    0.6639       NaN       NaN


out(:,:,2) =

    0.7898    1.3096    1.0434
       NaN    0.1604       NaN
       NaN       NaN       NaN
       NaN       NaN       NaN

以下是您可以复制/粘贴以运行的完整代码:

clear
clc

NumRow = size(sampl,1);

a = reshape(sampl,NumRow,[])

[row,col] = find(a<0);
b = accumarray(col,row,[],@min)

b(b==0) = NumRow+1;

for k = 1:size(a,2)
a(b(k):NumRow,k) = NaN;
end

out = reshape(a,size(sampl))

答案 2 :(得分:4)

缺少一个基于bsxfun的解决方案,任何人?

[val, ind] = max(sampl<0); %// ind gives row index of first negative value, if any
ind(~val) = inf; %// if no negative values, set ind to inf so it has no effect
sampl(bsxfun(@ge, (1:size(sampl,1)).', ind)) = NaN; %'// logical indexing to fill NaNs