如何使用Deedle映射产品事件的状态转移?
问题描述
现有包含产品与事件的Deedle DataFrame定义如下:
type Event = | E1 | E2 let events = Series.ofValues [ E1;E2;E2 ] let products = Series.ofValues [ "A";"A";"B"] let df = Frame(["Product"; "Event"], [products; events]) df.Print()
输出结果:
Product Event 0 -> A E1 1 -> A E2 2 -> B E2
同时定义了根据旧状态与事件计算新状态的转移函数:
type State = S0 | S1 | S2 let evolve (s:State) (e:Event) :State = match s,e with | _, E1 -> S1 | S0, E2 -> S0 | _, E2 -> S2
需要实现状态转移的映射,得到如下格式的结果:
let stateTransitions = df |> ??? stateTransitions.Print()
期望输出:
Product Event NewState 0 -> A E1 S1 1 -> A E2 S2 2 -> B E2 S0
补充说明:已通过聚合函数获取到各产品的最终状态,但无法查看每一步的转移过程:
let finalStates = df |> Frame.aggregateRowsBy ["Product"] ["Event"] (fun s -> s.Values |> Seq.fold evolve S0) finalStates.Print()
输出结果:
Product Event 0 -> A S2 1 -> B S0
解决方案
要记录每一步的状态转移过程,需按Product分组后,对每组的事件序列使用Seq.scan追踪状态变化,再将结果合并回原DataFrame。具体实现代码如下:
// 按产品分组计算每一步的状态转移 let stateSeries = df |> Frame.groupRowsBy "Product" |> Series.map (fun _ group -> // 从初始状态S0开始,扫描每个事件得到每一步的新状态 group?Event.Values |> Seq.scan evolve S0 |> Seq.skip 1 // 跳过初始的S0,只保留事件对应的新状态 |> Series.ofValues |> Series.indexWith group.RowKeys) // 用原行索引对齐状态序列 |> Series.concat // 合并所有分组的状态结果 // 将状态序列作为新列添加到原DataFrame let stateTransitions = df |> Frame.addCol "NewState" stateSeries stateTransitions.Print()
运行后将输出期望的结果:
Product Event NewState 0 -> A E1 S1 1 -> A E2 S2 2 -> B E2 S0
代码说明
Frame.groupRowsBy "Product":按产品分组,确保同一产品的事件按顺序处理。Seq.scan evolve S0:从初始状态S0出发,依次对每个事件应用转移函数,生成包含初始状态和所有步骤新状态的序列。Seq.skip 1:剔除初始状态,只保留每个事件对应的新状态。Series.indexWith group.RowKeys:用原分组的行索引对齐状态序列,避免后续合并时出现索引错位。Frame.addCol "NewState" stateSeries:将状态序列作为新列追加到原DataFrame中。
内容的提问来源于stack exchange,提问作者jim108dev
相关产品推荐
相关产品推荐

