我在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
。
答案 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