【问题标题】:Matlab: find neighboring instances of NaN without loopsMatlab:在没有循环的情况下查找 NaN 的相邻实例
【发布时间】:2014-08-25 06:07:16
【问题描述】:

基本上,我有一个数据矩阵,其中包含许多由 NaN 表示的“孔”,我想检索在单个列中聚集 少于 4 次的所有 NaN 的索引。

例如与矩阵:

A = 
    23    12    NaN   56    60    21    NaN
    60    56    94    22    45    NaN   NaN
    23    55    19    83    NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    84    99    43    32    89    12    NaN
    76    92    73    47    22    12    10
    23    55    12    93    61    94    20
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    41    16    83    39    82    37    43
    14    78    92    40    81    29    60

它会返回:

ans = 
    [4; 5; 6; 10; 16; 17; 18; 22; 25; 28; 29; 30; 34; 40; 41; 42; 46; 58; 70; 82]

到目前为止,我有一个向量,其中包含所有 NaN 值的索引

nan_list=find(isnan(A(:)))

但我不知道如何在不使用循环的情况下从该向量中提取序列号,这太昂贵了。我还尝试了类似于 b3 here 发布的答案的方法,将所有 NaN 切换为未出现在矩阵中的值,但该代码不能用于其他数据集。

感谢您的任何建议!

【问题讨论】:

  • 您的 NaN 小于 4 的集群可以重叠,或者您在 4 的重叠集群中查看?还有你的ans 代表什么。看不到与A 的连接。

标签: matlab matrix vectorization nan


【解决方案1】:

代码

N = 4; %// Fewer than clusters of N or N+ NaNs are to be detecteed
nan_pos = isnan(A) %// Find NaN positions as a binary array
conv_res = conv2(double(nan_pos),[0 ones(1,N)]')==N %//' Perform convolution
start_ind = find(conv_res(N+1:end,:)) %// Find positions where clusters of N or N+ NaNs start
nan_pos(unique(bsxfun(@plus,start_ind,[0:N-1])))=0 %// Get positions of all those clustered N or N+ NaNs and set them in NaN position array as zeros
out = find(nan_pos) %// Finally the desired output

示例

作为一个例子,让我们在稍微不同的输入上尝试这段代码,希望能测试问题的各个方面 -

A = [
    23    12    NaN   56    60    21    NaN
    60    56    94    22    45    NaN   NaN
    23    55    19    83    NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    84    99    43    32    89    12    NaN
    76    92    73    47    22    12    10
    23    55    12    93    61    94    20
    NaN   NaN   NaN   NaN   NaN   NaN   NaN
    41    NaN   NaN    39    82    37   43
    14    78    NaN    40    81   NaN   60]

现在,假设我们正在寻找少于3 NaNs 的集群索引。因此在代码中将N编辑为3,输出为-

out =
    10    22    23    25    46    58    70    72    82

当我们查看输入时,这是有道理的。

【讨论】:

  • 我使用来自问题的输入 A 对此进行了测试,它产生了所需的结果。很好地使用卷积。 +1
  • @kkuilla 感谢UP! :)
  • 顺便说一句,conv 不会环绕列,以便将第 6 列的最后一个值与第 7 列中的 NaN 进行卷积?这是我所期望的,但由于您的代码无法正常工作。
  • @kkuilla conv2 不会环绕,因为我使用的是“列过滤器” - [0; 1; 1; 1; 1]。这与声明的问题一致 - fewer than 4 times in a single column。所以提问者不想绕到下一列。
  • 啊,我明白了。因此,您通过创建一个仅限于列的内核来阻止包装。那很好。 :-)
【解决方案2】:

这应该可行:

[rows, ~] = size(A);
maxNansPerCol = 4;

% find which columns have few enough NaNs
Anans = isnan(A);
nansInCols = sum(Anans);
qualifyingCols = nansInCols <= maxNansPerCol;

% zero the other columns
mask = repmat(qualifyingCols,rows,1);
B = Anans .* mask;

% get the NaN locations
indices = find(B(:));

(如果有什么不对劲的地方,我深表歉意——我在这台电脑上没有 MATLAB 来测试它)

【讨论】:

  • 您的代码没有产生预期的结果。这是您的代码使用输入 A 产生的结果,如原始问题中所述:[4 5 6 10 16 17 18 22 40 41 42 46]
  • 啊。您的意思是一列中有 4 个 sequential NaN。是的,上面的卷积方法可能是你想要的(如果是这样,我建议接受他的回答)。
猜你喜欢
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-21
  • 2021-07-12
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多