Dev*_*-iL 8 matlab nan accumarray
我正在寻找有关如何优雅地解决以下问题的建议.虽然在我的具体案例中表现不是问题,但我会对有关良好做法的评论表示赞赏.
提前致谢!
我试图根据一些逻辑平均矩阵行,而忽略NaN值.我目前的代码没有按照我想要的方式处理NaN值.
我的数据以下列方式构建:
这是一个例子:
DATA = [...
180 NaN NaN 1.733
180 NaN NaN 1.703
200 0.720 2.117 1.738
200 0.706 2.073 1.722
200 0.693 2.025 1.723
200 NaN NaN 1.729
210 NaN NaN 1.820
210 NaN NaN 1.813
210 NaN NaN 1.805
240 NaN NaN 1.951
240 NaN NaN 1.946
240 NaN NaN 1.946
270 NaN NaN 2.061
270 NaN NaN 2.052
300 0.754 2.356 2.103
300 0.758 2.342 2.057
300 NaN NaN 2.066
300 NaN NaN 2.066 ];
Run Code Online (Sandbox Code Playgroud)
期望的结果是在第一列中包含唯一"箱"的矩阵,并且在其余部分中表示"未被NaNs",例如:
(0.720+0.706+0.693)/3=0.7063- 请注意此列+ bin的除以3(而不是4).以下是上述示例的预期结果:
RES = [...
180 NaN NaN 1.718
200 0.7063 2.072 1.728
210 NaN NaN 1.812
240 NaN NaN 1.948
270 NaN NaN 2.056
300 0.756 2.349 2.074 ];
Run Code Online (Sandbox Code Playgroud)
这是我设法从几个来源编译的一些代码.它适用于仅包含NaN或数字的列+ bin.
nDataCols=size(DATA,2)-1;
[u,m,n] = unique(DATA(:,1));
sz = size(m);
N=accumarray(n,1,sz);
RES(length(u),nDataCols) = 0; %Preallocation
for ind1 = 1:nDataCols
RES(:,ind1)=accumarray(n,DATA(:,ind1+1),sz)./N;
end
RES= [u,RES];
Run Code Online (Sandbox Code Playgroud)
这是我目前得到的:
RES = [...
180 NaN NaN 1.718
200 NaN NaN 1.728
210 NaN NaN 1.812
240 NaN NaN 1.948
270 NaN NaN 2.056
300 NaN NaN 2.074 ];
Run Code Online (Sandbox Code Playgroud)
一种可能的方法:在第一列中查找更改(利用它已预先排序的事实)并应用于nanmean每个行块:
ind = find(diff([-inf; (DATA(:,1)); inf])~=0); %// value changed: start of block
r = arrayfun(@(n) nanmean(DATA(ind(n):ind(n+1)-1,:)), 1:numel(ind)-1, 'uni', 0);
RES = vertcat(r{:});
Run Code Online (Sandbox Code Playgroud)
您可以arrayfun通过显式循环替换.这可能会更快,并避免单元格引入的开销:
ind = find(diff([-inf; (DATA(:,1)); inf])~=0); %// value changed: start of block
RES = zeros(numel(ind)-1, size(DATA,2)); %// preallocate
for n = 1:numel(ind)-1 %// loop over blocks
RES(n,:) = nanmean(DATA(ind(n):ind(n+1)-1,:));
end
Run Code Online (Sandbox Code Playgroud)
您的方法也可以使用.您只需要accumarray使用nanmean函数句柄调用.这不需要对第一列进行预排序.
nDataCols = size(DATA,2)-1;
[u, ~, n] = unique(DATA(:,1));
RES = zeros(length(u), nDataCols); %// Preallocation
for ind1 = 1:nDataCols
RES(:,ind1) = accumarray(n, DATA(:,ind1+1), [], @nanmean);
end
RES = [u, RES];
Run Code Online (Sandbox Code Playgroud)