1.1.3 Expressions and contexts
Expressions such as (col "weight") describe a computation; a context (select, with-columns, filter, group-by/agg) runs it against a frame.
1.1.3.1 select
> (~> df (select "name" (~> (col "birthdate") dt-year (alias "birth_year")) (~> (col "weight") (/ (pow (col "height") 2)) (alias "bmi"))))
shape: (4, 3)
┌────────────────┬────────────┬───────────┐
│ name ┆ birth_year ┆ bmi │
│ --- ┆ --- ┆ --- │
│ str ┆ i32 ┆ f64 │
╞════════════════╪════════════╪═══════════╡
│ Alice Archer ┆ 1997 ┆ 23.791913 │
│ Ben Brown ┆ 1985 ┆ 23.141498 │
│ Chloe Cooper ┆ 1983 ┆ 19.687787 │
│ Daniel Donovan ┆ 1981 ┆ 27.134694 │
└────────────────┴────────────┴───────────┘
> (~> df (select "name" (~> (col "weight") (* 0.95) (round #:decimals 2) (alias "weight-5%")) (~> (col "height") (* 0.95) (round #:decimals 2) (alias "height-5%"))))
shape: (4, 3)
┌────────────────┬───────────┬───────────┐
│ name ┆ weight-5% ┆ height-5% │
│ --- ┆ --- ┆ --- │
│ str ┆ f64 ┆ f64 │
╞════════════════╪═══════════╪═══════════╡
│ Alice Archer ┆ 55.0 ┆ 1.48 │
│ Ben Brown ┆ 68.88 ┆ 1.68 │
│ Chloe Cooper ┆ 50.92 ┆ 1.57 │
│ Daniel Donovan ┆ 78.94 ┆ 1.66 │
└────────────────┴───────────┴───────────┘
API gaps: no multi-column col("weight", "height"); no name.suffix.
1.1.3.2 with-columns
> (~> df (with-columns (~> (col "birthdate") dt-year (alias "birth_year")) (~> (col "weight") (/ (pow (col "height") 2)) (alias "bmi"))))
shape: (4, 6)
┌────────────────┬────────────┬────────┬────────┬────────────┬───────────┐
│ name ┆ birthdate ┆ weight ┆ height ┆ birth_year ┆ bmi │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ date ┆ f64 ┆ f64 ┆ i32 ┆ f64 │
╞════════════════╪════════════╪════════╪════════╪════════════╪═══════════╡
│ Alice Archer ┆ 1997-01-10 ┆ 57.9 ┆ 1.56 ┆ 1997 ┆ 23.791913 │
│ Ben Brown ┆ 1985-02-15 ┆ 72.5 ┆ 1.77 ┆ 1985 ┆ 23.141498 │
│ Chloe Cooper ┆ 1983-03-22 ┆ 53.6 ┆ 1.65 ┆ 1983 ┆ 19.687787 │
│ Daniel Donovan ┆ 1981-04-30 ┆ 83.1 ┆ 1.75 ┆ 1981 ┆ 27.134694 │
└────────────────┴────────────┴────────┴────────┴────────────┴───────────┘
1.1.3.3 filter
> (~> df (filter (< (dt-year "birthdate") 1990)))
shape: (3, 4)
┌────────────────┬────────────┬────────┬────────┐
│ name ┆ birthdate ┆ weight ┆ height │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ date ┆ f64 ┆ f64 │
╞════════════════╪════════════╪════════╪════════╡
│ Ben Brown ┆ 1985-02-15 ┆ 72.5 ┆ 1.77 │
│ Chloe Cooper ┆ 1983-03-22 ┆ 53.6 ┆ 1.65 │
│ Daniel Donovan ┆ 1981-04-30 ┆ 83.1 ┆ 1.75 │
└────────────────┴────────────┴────────┴────────┘
> (~> df (filter (and (is-between "birthdate" (str->date (lit "1982-12-31")) (str->date (lit "1996-01-01"))) (> (col "height") 1.7))))
shape: (1, 4)
┌───────────┬────────────┬────────┬────────┐
│ name ┆ birthdate ┆ weight ┆ height │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ date ┆ f64 ┆ f64 │
╞═══════════╪════════════╪════════╪════════╡
│ Ben Brown ┆ 1985-02-15 ┆ 72.5 ┆ 1.77 │
└───────────┴────────────┴────────┴────────┘
API gaps: no date literals, so the bounds parse a string with str->date; filter takes one predicate, so combine with and.
1.1.3.4 group-by
/ on an integer column is integer division, so Python’s // 10 * 10 is (* (/ e 10) 10).
> (define decade (~> (col "birthdate") dt-year (/ 10) (* 10) (alias "decade"))) > (~> df (group-by decade) (agg (~> (col "name") count (alias "len"))))
shape: (2, 2)
┌────────┬─────┐
│ decade ┆ len │
│ --- ┆ --- │
│ i32 ┆ u32 │
╞════════╪═════╡
│ 1980 ┆ 3 │
│ 1990 ┆ 1 │
└────────┴─────┘
> (~> df (group-by decade) (agg (~> (col "name") count (alias "sample_size")) (~> (col "weight") mean (round #:decimals 2) (alias "avg_weight")) (~> (col "height") max (alias "tallest"))))
shape: (2, 4)
┌────────┬─────────────┬────────────┬─────────┐
│ decade ┆ sample_size ┆ avg_weight ┆ tallest │
│ --- ┆ --- ┆ --- ┆ --- │
│ i32 ┆ u32 ┆ f64 ┆ f64 │
╞════════╪═════════════╪════════════╪═════════╡
│ 1980 ┆ 3 ┆ 69.73 ┆ 1.77 │
│ 1990 ┆ 1 ┆ 57.9 ┆ 1.56 │
└────────┴─────────────┴────────────┴─────────┘
API gaps: no maintain_order, so row order differs from the Python pair; no pl.len() (count a column instead).
1.1.3.5 More complex queries
> (~> df (with-columns decade (str-extract "name" "^(\\S+)")) (select (exclude (all) "birthdate")) (group-by "decade") (agg (col "name") (~> (col "weight") mean (round #:decimals 2) (alias "avg_weight")) (~> (col "height") mean (round #:decimals 2) (alias "avg_height"))))
shape: (2, 4)
┌────────┬────────────────────────────┬────────────┬────────────┐
│ decade ┆ name ┆ avg_weight ┆ avg_height │
│ --- ┆ --- ┆ --- ┆ --- │
│ i32 ┆ list[str] ┆ f64 ┆ f64 │
╞════════╪════════════════════════════╪════════════╪════════════╡
│ 1980 ┆ ["Ben", "Chloe", "Daniel"] ┆ 69.73 ┆ 1.72 │
│ 1990 ┆ ["Alice"] ┆ 57.9 ┆ 1.56 │
└────────┴────────────────────────────┴────────────┴────────────┘
API gaps: no str.split / list.first (regex str-extract instead); no name.prefix.