如何在Deedle中聚合非float类型值(如DateTime、decimal)?
Deedle聚合非float类型(DateTime/decimal)的解决方案
Deedle的Frame.aggregateRowsBy方法常用于行聚合操作,默认搭配Stats.max这类统计函数,但Stats模块的多数函数仅支持float类型,直接用于DateTime或decimal类型会触发类型转换错误。
错误示例
以下代码尝试按id聚合,对date(DateTime类型)和quantity(decimal类型)取最大值,会抛出类型转换异常:
open Deedle open System Frame([ "id"; "date"; "quantity"], [ Series.ofValues [1; 1; 2]; Series.ofValues [ DateTime(2023, 4, 13); DateTime(2023, 4, 10); DateTime(2023, 4, 16) ]; Series.ofValues [ 2.7M; 1.2M; 1.5M; ]]) |> Frame.aggregateRowsBy ["id"] ["date"; "quantity"] Stats.max
错误信息:
System.InvalidCastException: Invalid cast from 'DateTime' to 'Double'.
解决方案:自定义通用聚合函数
由于DateTime和decimal都实现了IComparable接口,我们可以基于Seq.max/Seq.min实现支持任意可比较类型的聚合函数,既满足非float类型的聚合需求,又能保留原数据类型。
1. 定义通用聚合函数
open Deedle open System // 通用最大值聚合函数,支持所有实现IComparable的类型 let aggregateMax (series:Series<'K,'T when 'T :> IComparable>) = series.Values |> Seq.max // 通用最小值聚合函数,支持所有实现IComparable的类型 let aggregateMin (series:Series<'K,'T when 'T :> IComparable>) = series.Values |> Seq.min
2. 使用自定义函数完成聚合
// 构造测试数据 let dataFrame = Frame([ "id"; "date"; "quantity"], [ Series.ofValues [1; 1; 2]; Series.ofValues [ DateTime(2023, 4, 13); DateTime(2023, 4, 10); DateTime(2023, 4, 16) ]; Series.ofValues [ 2.7M; 1.2M; 1.5M; ]]) // 按id分组,对date和quantity分别取最大值 let aggregatedFrame = dataFrame |> Frame.aggregateRowsBy ["id"] ["date"; "quantity"] aggregateMax // 验证结果类型:date列仍为DateTime,quantity列仍为decimal aggregatedFrame.Columns.["date"] |> Series.values |> Seq.head |> typeof<DateTime> aggregatedFrame.Columns.["quantity"] |> Series.values |> Seq.head |> typeof<decimal>
说明
- 自定义函数通过
Seq.max直接操作序列值,无需类型转换,避免了Stats.max的float类型限制。 - 聚合后的Frame会严格保留原列的数据类型,不会将decimal或DateTime转为float。
内容的提问来源于stack exchange,提问作者topica
相关产品推荐
相关产品推荐

