我正在寻找有关如何优雅地解决以下问题的建议 . 虽然表现尚未得到好评,但仍然表达了对良好做法的评价 .
提前致谢!
简短版:
我试图根据一些逻辑平均矩阵行,而忽略NaN值 . 我目前的代码没有按照我想要的方式处理NaN值 .
长版:
我的数据以下列方式构建:
-
"bins"的单个(第一个)列 . 每个bin的行数不是恒定的 . 垃圾箱不必是整数 . 行是预先排序的 .
-
可变数量的数据列,可能包括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 ];
The desired result 是一个矩阵,在第一列中包含唯一的"bins",其余为"unspoiled by NaNs",例如:
-
如果对于特定的列bin,只有NaN(在上面的示例中:第1个数据列bin 210) - 结果将是NaN .
-
如果对于特定的列bin,存在NaN和数字的混合,则结果将是有效数字的平均值 . 在上面的示例中:第一个数据列bin 200应该给出
(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 ];
到目前为止我尝试了什么:
这是我设法从几个来源编译的一些代码 . 它适用于仅包含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];
这是我目前得到的:
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 ];
p.s.
-
如果使用电子表格软件(例如MS Excel)更容易做到这一点 - 我很想听到想法 .
-
按列进行计算是我目前关于如何处理这个问题的想法 . 我只是想知道是否有办法将其概括为立即采用完整的矩阵 .
2 回答
一种可能的方法:在第一列中查找更改(利用它已预先排序的事实)并将nanmean应用于每个行块:
您可以通过显式循环替换
arrayfun
. 那may be faster,并避免了单元格引入的开销:您的方法也可以使用 . 您只需要使用
nanmean
函数的句柄调用accumarray
. 这不需要对第一列进行预排序 .这是另一种解决方案,虽然效率极低 . 此外,输出数组会将所有
NaN
值设置为0.我们只是说这对学术研究很有用 . 以下是我所做的步骤:对于第一列中的每个ID,查找唯一列表 .
对于其他列,将每列拆分为单元格数组 .
创建一个新的单元格数组,其中每个列都附加了此单元格数组中每个元素的第一列
为每个包含
NaN
值的单元格数组筛选出这些行对于筛选结果的每一列,使用
mean
作为函数句柄运行accumarray
.使用步骤#1中的ID,索引每个
accumarray
结果并转换回矩阵结果是:
正如你所看到的那样,效率非常低 - 尤其是我所做的
cellfun
电话的数量,但我仍然是一个学术的例子!