Matlab中基于索引的高效均值计算(避免循环)
用Matlab向量化方法替代循环求分组均值
当然可以用cellfun()来实现无循环的分组均值计算,不过其实Matlab还有更适合这类场景的原生函数,效率会更高。下面先给你展示cellfun()的实现方案,再补充更优的替代方法:
方法一:使用cellfun()配合splitapply()
我们可以先把数据按分组索引拆分成cell数组,再用cellfun()遍历每个cell计算均值:
tVector = 10 : 15; values = [ 10.1 10.2 10.3 11.4 11.5 11.6 11.7 12.8 12.9 13 13.1 13.2 13.3 13.3 14 14.1 14.2 ]; [ x, n ] = histc( values, tVector ); % 过滤掉histc返回的0索引(对应超出tVector范围的元素) validIdx = n ~= 0; filteredValues = values(validIdx); filteredN = n(validIdx); % 将数据按分组索引拆分为cell数组 groupedValues = splitapply(@(v) {v}, filteredValues, filteredN); % 用cellfun计算每个分组的均值 avgList = cellfun(@mean, groupedValues); % 补全NaN,让结果对应tVector的每个位置 fullAvgList = NaN(size(tVector)); fullAvgList(unique(filteredN)) = avgList;
方法二:更高效的accumarray()(推荐)
对于数值型的分组聚合计算,accumarray()是更合适的选择——它专门针对这类场景优化,比cellfun()的运行效率更高,尤其是处理大数据量时:
tVector = 10 : 15; values = [ 10.1 10.2 10.3 11.4 11.5 11.6 11.7 12.8 12.9 13 13.1 13.2 13.3 13.3 14 14.1 14.2 ]; [ x, n ] = histc( values, tVector ); % 过滤无效索引 validIdx = n ~= 0; filteredValues = values(validIdx); filteredN = n(validIdx); % 直接用accumarray计算分组均值 avgList = accumarray(filteredN, filteredValues, [], @mean); % 补全NaN到tVector对应的长度 fullAvgList = NaN(size(tVector)); fullAvgList(1:length(avgList)) = avgList;
为什么这两种方法更好?
你的原始循环在大数据量下会因为多次调用find()和逐次赋值变慢,而上述向量化方法都是Matlab底层优化过的操作,能大幅提升运行速度。其中accumarray()的性能最优,因为它不需要创建中间cell数组,直接完成分组聚合。
内容的提问来源于stack exchange,提问作者Benjamin Levy
相关产品推荐
相关产品推荐

