Search code examples
f#deedle

Map state transitions with Deedle


Suppose I have a table with products and events (processing steps), like

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    

and a transition function which determines a new state given the old state and the event

type State = S0 | S1 | S2

let evolve (s:State) (e:Event) :State =
    match s,e with
    | _, E1 -> S1
    | S0, E2 -> S0
    | _, E2 -> S2

How can the state transitions be mapped? The result should be something like

let stateTransitions = df |> ???

stateTransitions.Print()
     Product Event NewState 
0 -> A       E1    S1    
1 -> A       E2    S2    
2 -> B       E2    S0       

Update: I know how to get the final state of every product but the aggregate function does not show the transitions.

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    

Solution

  • I guess there is no existing function. I did grouping/nesting by product, fold with storing all states and build a new series/column of the results, unnest.

    let stateTransitions =  
        df
        |> Frame.groupRowsByString "Product"
        |> Frame.nest
        |> Series.mapValues (fun nf ->
            let events = nf.Columns.["Event"].As<Event>()
            let values' = 
                events.Values
                |> Seq.fold (fun acc e ->
                    let s = acc |> List.head 
                    let s' = evolve s e
                    s'::acc) [S0]
                |> Seq.rev
                |> Seq.tail
            let states' =
                Seq.zip events.Keys values'
                |> Series.ofObservations
            nf.AddColumn("NewState", states')
            nf
            )
        |> Frame.unnest
        |> Frame.indexRowsOrdinally 
    
    stateTransitions.Print()
    
         Product Event NewState 
    0 -> A       E1    S1       
    1 -> A       E2    S2       
    2 -> B       E2    S0