什么是一种数值稳定的方法来获取迭代器元素的方差?举个例子,我想做一些像
这样的事情var((rand(4,2) for i in 1:10))
并返回(4,2)
矩阵,该矩阵是每个系数的方差。这会使用Julia的基础var
引发错误。有没有可以处理这个的包?或者使用Base Julia功能轻松(并且存储效率)这样做?或者是否需要自己开发?
答案 0 :(得分:0)
有关数值稳定的版本
,请参阅下面的更新另一种计算方法:
srand(0) # reset random for comparing across implementations
moment2var(t) = (t[3]-t[2].^2./t[1])./(t[1]-1)
foldfunc(x,y) = (x[1]+1,x[2].+y,x[3].+y.^2)
moment2var(foldl(foldfunc,(0,zeros(1,1),zeros(1,1)),(rand(4,2) for i=1:10)))
给出:
4×2 Array{Float64,2}:
0.0848123 0.0643537
0.0715945 0.0900416
0.111934 0.084314
0.0819135 0.0632765
类似于:
srand(0) # reset random for comparing across implementations
# naive component-wise application of `var` function
map(var,zip((rand(4,2) for i=1:10)...))
是非迭代器版本(或CS术语中的离线版本)。
此方法基于平均值和平方和的方差计算。 moment2var
和foldfunc
只是一个辅助函数,但它没有它们就适合单行。
评论:
速度方面,这应该也很不错。也许,StaticArrays并使用正确的foldl
迭代器初始化v0
' eltype
可以节省更多时间。
基准测试在样本输入上比componentwise_meanvar
(来自另一个答案)提供了 5x 速度优势(以及更好的内存使用率)。
使用moment2meanvar(t)=(t[2]./t[1],(t[3]-t[2].^2./t[1])./(t[1]-1))
同时给出componentwise_meanvar
等均值和方差。
正如@ChrisRackauckas所指出的,当总和的元素数量很大时,这种方法会受到数值不稳定的影响。
---更新方法---
对问题的一点抽象要求在迭代器上执行foldl
(和reduce
,foldr
)的方法,返回矩阵,按元素和保持形状。为此,我们可以定义一个辅助函数mfold
,该函数采用折叠函数并使其按元素方式折叠矩阵。按如下方式定义:
mfold(f) = (x,y)->[f(t[1],t[2]) for t in zip(x,y)]
对于这个特定的方差问题,我们可以定义分量方面的折叠函数,以及将矩组合成方差的最终函数(如果需要,则表示平均值)。代码:
ff(x,y) = (x[1]+1,x[2]+y,x[3]+y^2) # fold and collect moments
moment2var(t) = (t[3]-t[2]^2/t[1])/(t[1]-1) # calc variance from moments
moment2meanvar(t) = (t[2]./t[1],(t[3]-t[2].^2./t[1])./(t[1]-1))
我们可以看到moment2meanvar
适用于单个向量,如下所示:
julia> moment2meanvar(foldl(ff,(0.0,0.0,0.0),[1.0,2.0,3.0]))
(2.0, 1.0)
现在使用foldm
(使用.
- 表示法)对其进行矩阵化:
moment2var.(foldl(mfold(ff),fill((0,0,0),(4,2)),(rand(4,2) for i=1:10)))
@ChrisRackauckas注意到这不是数值稳定的,另一种方法(在维基百科中详述)更好。使用foldm
这可以实现为:
# better fold function compensating the sums for stability
ff2(x,y) = begin
delta=y-x[2]
mean=x[2]+delta/(x[1]+1)
return (x[1]+1,mean,x[3]+delta*(y-mean))
end
# combine the collected information for the variance (and mean)
m2var(t) = t[3]/(t[1]-1)
m2meanvar(t) = (t[2],t[3]/(t[1]-1))
我们再次:
m2var.(foldl(mfold(ff2),fill((0,0.0,0.0),(4,2)),(rand(4,2) for i=1:10)))
给出相同的结果(可能更准确一点)。
答案 1 :(得分:0)
使用Base Julia功能还是一种简单(并且存储效率)的方法吗?
出于好奇,为什么在外部维度上使用DB_CON->exec("INSERT INTO `users` (`email`, `first_name`) VALUES (".$email.", ".firstname."")
的标准解决方案对你不利?
var
显然,我在这里使用julia> var(cat(3,(rand(4,2) for i in 1:10)...),3)
4×2×1 Array{Float64,3}:
[:, :, 1] =
0.08847 0.104799
0.0946243 0.0879721
0.105404 0.0617594
0.0762611 0.091195
,显然效率不高,所以我可以根据您的问题使用Base Julia函数和原始生成器语法。但是如果你直接在一个预先分配的大小数组(4,2,10)上初始化你的随机值,你也可以使这个存储有效,所以这里不是真正的问题。
或者我误解了你的问题?
EDIT - 回应评论的基准
cat
function standard_var(Y, A)
for i in 1 : length(A)
Y[:,:,i], = next(A,i);
end
var(Y,3)
end
function testit()
A = (rand(4,2) for i in 1:10000);
Y = Array{Float64, 3}(4,2,length(A));
@time componentwise_meanvar(A); # as defined in Chris's answer above
@time standard_var(Y, A) # standard variance + using preallocation
@time var(cat(3, A...), 3); # standard variance without preallocation
return nothing
end