Sweet Snippet 之 方差计算

63 篇文章 1 订阅
21 篇文章 1 订阅

方差计算的简单实现

在概率统计中,方差用于衡量一组数据的离散程度,相关的计算公式如下(总体方差):

μ = 1 N ∑ i = 1 N x i σ 2 = 1 N ∑ i = 1 N ( x i − μ ) 2 \begin{aligned} &\mu = \frac{1}{N}\sum_{i = 1}^{N}x_i \\ &\sigma^2 = \frac{1}{N}\sum_{i = 1}^{N}(x_i - \mu)^2 \end{aligned} μ=N1i=1Nxiσ2=N1i=1N(xiμ)2

其中 μ \mu μ 为数据的平均值, 而 σ 2 \sigma^2 σ2 即是(总体)方差.

相应的实现代码如下:

-- Lua
function average(values, count)
    local sum = 0
    
    for i = 1, count do
        sum = sum + values[i]
    end
    
    return sum / count
end

function variance(values, count)
    local average = average(values, count)
    local variance = 0
    
    for i = 1, count do
        local delta = values[i] - average 
        variance = variance + delta * delta
    end
    
    return variance / count
end

通常我们需要在获取新样本数据时更新方差,简单的方法就是按照上述公式重新计算一遍,我们可以通过计算数据子集方差的方式来模拟这个过程:

-- Lua
function variance_list(values)
    local ret = {}
    
    for i = 1, #values do
        ret[i] = variance(values, i)
    end
    
    return ret
end

更好的一种方式是通过递推来计算数据子集的方差,这需要对方差的计算公式做一些变形:

σ 2 = 1 N ∑ i = 1 N ( x i − μ ) 2    ⟹    σ 2 = 1 N ∑ i = 1 N ( x i 2 + μ 2 − 2 x i μ )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 + ∑ i = 1 N μ 2 − ∑ i = 1 N 2 x i μ )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 + N μ 2 − 2 μ ∑ i = 1 N x i )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 + N μ 2 − 2 N μ 2 )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 − N μ 2 )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 − N ( ∑ i = 1 N x i N ) 2 )    ⟹    σ 2 = 1 N ( ∑ i = 1 N x i 2 − ( ∑ i = 1 N x i ) 2 N ) \begin{aligned} &\sigma^2 = \frac{1}{N}\sum_{i = 1}^{N}(x_i - \mu)^2 \implies \\ &\sigma^2 = \frac{1}{N}\sum_{i = 1}^{N}(x_i^2 + \mu^2 - 2x_i\mu) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 + \sum_{i = 1}^{N}\mu^2 - \sum_{i = 1}^{N}2x_i\mu) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 + N\mu^2 - 2\mu\sum_{i = 1}^{N}x_i) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 + N\mu^2 - 2N\mu^2) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 - N\mu^2) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 - N(\frac{\sum_{i=1}^{N}x_i}{N})^2) \implies \\ &\sigma^2 = \frac{1}{N}(\sum_{i = 1}^{N}x_i^2 - \frac{(\sum_{i=1}^{N}x_i)^2}{N}) \end{aligned} σ2=N1i=1N(xiμ)2σ2=N1i=1N(xi2+μ22xiμ)σ2=N1(i=1Nxi2+i=1Nμ2i=1N2xiμ)σ2=N1(i=1Nxi2+Nμ22μi=1Nxi)σ2=N1(i=1Nxi2+Nμ22Nμ2)σ2=N1(i=1Nxi2Nμ2)σ2=N1(i=1Nxi2N(Ni=1Nxi)2)σ2=N1(i=1Nxi2N(i=1Nxi)2)

基于此,我们就可以递推的计算数据子集的方差了,相关的计算复杂度则降低了一个数量级( O ( n 2 )    ⟹    O ( n ) O(n^2) \implies O(n) O(n2)O(n)):

-- lua
function variance_list_recurrence(values)
    local ret = {}
    
    local pre_square_sum = 0
    local pre_sum = 0
    
    for i = 1, #values do
        local val = values[i]
        
        pre_square_sum = pre_square_sum + val * val
        pre_sum = pre_sum + val
        
        ret[i] = (pre_square_sum - (pre_sum * pre_sum / i)) / i
    end
    
    return ret
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值