使用deedle快速扩展性能的建议

Suggestion for fast performance expanding apply with deedle

Stats.expandingXXXX 函数非常快。但是,没有 public api 来应用 expandingWindow。当涉及到像 100k 这样的大数据集时,我创建的以下解决方案非常慢。有什么建议吗?

 let ExpWindowApply f minSize data = 
        let keys = dataSeries.Keys
        let startKey = dataSeries.FirstKey()
        let values = keys
                     |> Seq.map(fun k -> 
                                    let ds = data.Between(startKey,k) 
                                    match ds with 
                                    |_ when ds.ValueCount >= minSize -> f ds.Values
                                    |_ -> Double.NaN
                                )                     
        let result = Series(keys, values)
        result

我理解 Stats.expandingXXX 函数实际上是特殊情况,应用的函数可以根据先前循环的状态迭代计算。并非所有功能都可以利用先前计算的状态。在创建 window 数据方面,有什么比 Series.Between 更好的方法吗?

更新

对于同样对类似问题感兴趣的人。答案提供了替代实现和对很少记录的序列向量和索引操作的洞察。但它并没有提高性能。

Deedle 中的扩展函数速度很快,因为它们使用了 an efficient online algorithm,这使得只需一次通过就可以即时计算统计数据,而不是实际为子范围构建中间序列。

有一个内置函数 aggregate 可以让您执行此操作 - 尽管它以相反的方式工作。比如想对从当前开始到末尾的所有元素求和,可以这样写:

let s = series [ for i in 1 .. 10 -> i, float i ]

s |> Series.aggregateInto
        (Aggregation.WindowWhile(fun _ _ -> true))
        (fun seg -> seg.Data.FirstKey()) 
        (fun seg -> OptionalValue(Stats.sum seg.Data))

如果您想使用底层表示做同样的事情,您可以直接使用 Deedle 使用的寻址方案来 link 具有值(在数据向量中)的键(在索引中)。这是一个丑陋的可变样本,但您可以将其封装成更好的东西:

[ let firstAddr = s.Index.Locate(s.FirstKey())
  for k in s.Index.KeySequence ->
    let lastAddr = s.Index.Locate(k)
    seq { 
      let a = ref firstAddr
      while !a <> lastAddr do
        yield s.Vector.GetValue(!a).Value
        a := s.Index.AddressOperations.AdjustBy(!a, +1L) } |> Seq.sum ]