Getting Started with Talon
installation
Talon is part of the Raven ecosystem and will be available through OPAM:
opam install talon
For now, you can build from source:
git clone https://github.com/raven-ml/raven.git
cd raven
opam install . --deps-only
dune build
your first dataframe
Let's create a simple dataframe and explore its features:
open Talon
(* Create a dataframe from arrays *)
let df = create [
("name", Col.string [|"Alice"; "Bob"; "Charlie"; "Dana"|]);
("age", Col.int32 [|25l; 30l; 35l; 28l|]);
("height", Col.float64 [|1.70; 1.80; 1.75; 1.65|]);
("weight", Col.float64 [|65.0; 82.0; 90.0; 70.0|]);
("active", Col.bool [|true; false; true; true|])
]
(* Check the shape *)
let () = Printf.printf "Rows: %d, Columns: %d\n"
(num_rows df) (num_columns df)
(* Print the dataframe *)
let () = print df
adding computed columns
One of Talon's strengths is type-safe row operations:
(* Calculate BMI: weight / (height^2) *)
let df = with_column df "bmi" Nx.float64
Row.(map2 (number "weight") (number "height")
~f:(fun w h -> w /. (h ** 2.)))
(* Add a categorical column based on BMI *)
let categories =
match to_array Nx.float64 df "bmi" with
| Some arr ->
Array.map (fun bmi ->
if bmi < 18.5 then "underweight"
else if bmi < 25.0 then "normal"
else if bmi < 30.0 then "overweight"
else "obese") arr
| None -> [||]
let df = add_column df "category" (Col.string categories)
row-wise operations
Talon excels at operations across many columns:
(* Sum across multiple columns *)
let df_scores = create [
("student", Col.string [|"Alice"; "Bob"|]);
("math", Col.float64 [|92.0; 85.0|]);
("science", Col.float64 [|88.0; 92.0|]);
("history", Col.float64 [|95.0; 78.0|]);
("english", Col.float64 [|90.0; 88.0|])
]
(* Calculate total score *)
let scores = Agg.row_sum df_scores
~names:["math"; "science"; "history"; "english"]
let df_scores = add_column df_scores "total" scores
(* Calculate average score *)
let avg = Agg.row_mean df_scores
~names:["math"; "science"; "history"; "english"]
let df_scores = add_column df_scores "average" avg
filtering and sorting
(* Filter students with average >= 90 *)
let top_students = filter_by df_scores
Row.(map (number "average") ~f:(fun avg -> avg >= 90.0))
(* Sort by total score descending *)
let sorted = sort_values ~ascending:false df_scores "total"
working with column selectors
Talon provides composable column selection via select_columns:
(* Select all numeric columns *)
let numeric_cols = select_columns df `Numeric
(* Select columns by prefix using standard list operations *)
let price_cols =
List.filter (fun n -> String.starts_with ~prefix:"price_" n) (column_names df)
(* Select all except specific columns *)
let feature_cols =
List.filter (fun n -> not (List.mem n ["id"; "name"; "timestamp"]))
(column_names df)
(* Use selectors in operations *)
let row_totals = Agg.row_sum df ~names:numeric_cols
functional transformations
Use applicative functors for elegant row transformations:
let df = create [
("a", Col.float64 [|1.0; 2.0; 3.0|]);
("b", Col.float64 [|4.0; 5.0; 6.0|]);
("c", Col.float64 [|7.0; 8.0; 9.0|]);
("x", Col.float64 [|10.0; 20.0; 30.0|]);
("y", Col.float64 [|0.5; 0.5; 0.5|]);
("z", Col.float64 [|1.0; 2.0; 3.0|])
]
(* Add multiple computed columns *)
let df = with_column df "sum" Nx.float64
Row.(map3 (number "a") (number "b") (number "c")
~f:(fun a b c -> a +. b +. c))
let df = with_column df "product" Nx.float64
Row.(map3 (number "a") (number "b") (number "c")
~f:(fun a b c -> a *. b *. c))
(* Use applicative operations *)
let df = with_column df "result" Nx.float64
Row.(map3 (number "x") (number "y") (number "z")
~f:(fun a b c -> a *. b +. c))
data manipulation
joins
let df1 = create [
("id", Col.int32 [|1l; 2l; 3l|]);
("name", Col.string [|"Alice"; "Bob"; "Charlie"|])
]
let df2 = create [
("id", Col.int32 [|2l; 3l; 4l|]);
("score", Col.float64 [|85.0; 92.0; 88.0|])
]
(* Inner join *)
let joined = join df1 df2 ~on:"id" ~how:`Inner ()
(* Left join *)
let left_joined = join df1 df2 ~on:"id" ~how:`Left ()
pivot tables
let sales = create [
("date", Col.string [|"2024-01"; "2024-01"; "2024-02"; "2024-02"|]);
("product", Col.string [|"A"; "B"; "A"; "B"|]);
("amount", Col.float64 [|100.0; 150.0; 120.0; 180.0|])
]
let pivoted = pivot sales ~index:"date" ~columns:"product" ~values:"amount" ()
loading and saving data
Use Talon_csv to control types and null handling on I/O:
let df = Talon_csv.read ~dtype_spec:["id", `Int64; "score", `Float64] "data.csv"
let () = Talon_csv.write "clean.csv" df
Next Steps
Check out the Comparison with Pandas to see how Talon's functional approach differs from Pandas.