大多数工科学生或者刚刚入门近年来比较火的“人工智能”相关算法的同窗,在选择语言的时候,都会选择MATLAB、Python、R等等这些高级语言,对本身所学的算法进行实现和调试。这些高级语言中,包含了实现复杂算法的基础数学算法、基本统计算法、基础数据结构的实现,好比均值(mean)、方差(std)、向量(Vector)等等。借助于这些高级语言的Built-in Function,咱们的一些想法会在较短期内实现。而且,解释型的编程方式,也方便了你们去调试代码、运行代码。可是使用这些语言和它们的函数,会带来一些效率下降的问题。大多数人首先想到的解决方式,多是去选择底层语言来实现算法,好比C/C++, JAVA等。但其实,咱们在运用高级语言进行编码时,也有大量须要进行优化的内容。咱们应当从“调包”和利用Built-in Function的习惯中解放出来。算法
最近在用C++实现CUSUM时,我参考该算法的MATLAB的代码直接翻译成了C++的代码。本想到算法应该会很是迅速,可是它的表现的确让我大失所望。在优化掉输出(ostream
)带来的时间损耗后,算法的速度依然没有达到指望的要求。因而,观察代码细节时发现,在迭代过程当中,咱们对一段随迭代次数其长度线性增加的数组片断(slice
)求取均值、方差时,使用了mean()
和std()
函数。编程
那么,每一次新的数据添加进一个数组(Array或者Vector),就去调用上述这类函数,真的有必要嘛?咱们是否是引入了太多的重复计算?数组
咱们先来看一下CUSUM算法的MATLAB实现的一个片断:数据结构
%% Global Loop
% w = waitbar(0,'Calculating Cumulative Sums, please wait...');
while k < length(x)
% current sample
k = k+1;
% mean and variance estimation (from initial to current sample)
m(k) = mean(x(k0:k));
v(k) = var(x(k0:k));
复制代码
上述代码片断里,在while
循环中,咱们调用了length(x)
次函数mean
和std
,这其中包含了大量的重复计算,带来了大量的计算开销(计算均值,确定有大量的加和操做)。假设咱们已经计算了实数数组的均值,记为
。当一个新的数据
被采样到,并加入
中,造成
。在计算均值
时,能够利用如下公式:框架
同理,咱们能够获得计算新方差的公式:函数
新的编码方案就变成:oop
// Global Loop
while (k < len - 1) {
k++;
prev_delta = X[k] - m[k - 1]; // online average
m.emplace_back(m[k - 1] + prev_delta / (k - k0 + 1));
post_delta = X[k] - m[k]; // online s.t.d
v.emplace_back(std::sqrt(v[k - 1]*v[k - 1] + prev_delta*post_delta));
复制代码
这样计算速度就快不少了。post
如上所述的这种从左至右计算统计量的过程,在不少算法中出现过,好比著名的决策树算法。决策树在某个节点肯定分裂特征和分裂点的计算过程当中,是如何进行计算统计量的呢?著名的决策树开源框架,如XGBoost中,又是如何编码,对样本梯度进行统计的呢?这些留给你们去思考和发现。优化