我发现这个neat trick计算一次通过数据的平均值和标准差。我希望这适用于float32
和float
。 Again,我正在努力通过通用数字来做到这一点。
module Seq =
let inline private avgVarianceReducer toFloat (count, oldM, oldS) x =
if count = 1 then
2, x, LanguagePrimitives.GenericZero
else
let meanFree = x - oldM
let newM = oldM + meanFree / (toFloat count)
count + 1, newM, oldS + meanFree * (x - newM)
let inline private avgVarianceWith toFloat source =
match source |> Seq.fold (avgVarianceReducer toFloat) (1, LanguagePrimitives.GenericZero, LanguagePrimitives.GenericZero) with
| 0, _, _ -> LanguagePrimitives.GenericZero, LanguagePrimitives.GenericZero
| 1, mean, _ -> mean, LanguagePrimitives.GenericZero
| n, mean, var -> mean, var / (n - 2 |> toFloat)
let avgVariance source = source |> avgVarianceWith float
let avgVariancef source = source |> avgVarianceWith float32
这适用于这两种类型,但我有额外的avgVariancef
加上我必须在调用时选择正确的。{/ p>
对我来说,核心问题是在avgVarianceReducer
中转换为正确的浮点数,我通过传递正确的转换函数来解决。我尝试了op_Explicit
,但失败了。
有人想要更优雅的解决方案吗?
答案 0 :(得分:3)
你试过FSharpPlus吗?
它包含一个通用数学模块和您正在寻找的通用explicit
函数。
以下是您的代码的样子:
#r @"FsControl.dll"
#r @"FSharpPlus.dll"
open FSharpPlus
open FSharpPlus.Operators.GenericMath
module Seq =
let inline private avgVarianceReducer (count, oldM, oldS) (x:'R) =
if count = 1 then
2, x, 0G
else
let meanFree = x - oldM
let newM = oldM + meanFree / explicit count
count + 1, newM, oldS + meanFree * (x - newM)
let inline avgVariance source : 'R * 'R =
match source |> Seq.fold avgVarianceReducer (1, 0G, 0G) with
| 0, _, _ -> 0G, 0G
| 1, mean, _ -> mean, 0G
| n, mean, var -> mean, var / (n - 2 |> explicit)
// or if you prefer specific functions
let avgVarianceF32 source : float32 * float32 = avgVariance source
let avgVarianceF source : float * float = avgVariance source
// it will work with other types as well
let avgVarianceD source : decimal * decimal = avgVariance source
事实上,您不需要函数explicit
,您可以使用更具体数字的函数fromIntegral
。
您还可以浏览库的源代码,并仅提取特定案例所需的代码。