2 Reference
Alongside the monomorphic, dtype-suffixed bindings (series-new-i32, series-sum-f64, and friends), polars provides a small, "rackety" high-level layer: series and dataframe wrapper values reached through a handful of purpose-named generic operations. The generics dispatch at runtime on the wrapper’s type, or — for the reductions — on the series’ dtype (read via dtype).
2.1 Series
A series wraps a typed column and prints in the REPL the way Polars prints it; series? is its predicate. (The underlying foreign pointer is an implementation detail and not part of the public series API.)
procedure
(series->string s) → string?
s : series?
value
polars-null : any/c
procedure
(polars-null? v) → boolean?
v : any/c
procedure
s : has-dtype?
procedure
x : sized?
procedure
s : has-null-count?
procedure
(sum v ...) → any/c
v : any/c
procedure
(mean v ...) → any/c
v : any/c
procedure
(min v ...) → any/c
v : any/c
procedure
(max v ...) → any/c
v : any/c
procedure
s : series? new-name : string?
procedure
s : series? new-name : string?
procedure
s : series?
procedure
(series-clone s) → series?
s : series?
2.1.1 dtype promotion
Reductions follow a simple, predictable rule. The widening order, narrow to wide, is
'int8 < 'int16 < 'int32 < 'int64
'uint8 < 'uint16 < 'uint32 < 'uint64
any integer < 'float32 < 'float64
sum, min and max preserve the input dtype. mean promotes to 'float64. Use series-cast to change a series’ dtype explicitly.
2.2 DataFrames
A dataframe is a collection of equal-length named series. Like a series it is a wrapper value (dataframe?) carrying the column data; it prints as a Polars table, so display (or ~a, or the REPL) renders it with no separate display call.
procedure
(dataframe? v) → boolean?
v : any/c
procedure
(dataframe columns) → dataframe?
columns : (listof series?)
procedure
(shape x) → (listof exact-nonnegative-integer?)
x : has-shape?
procedure
(shape/values x) →
exact-nonnegative-integer? ... x : has-shape?
procedure
d : dataframe?
procedure
d : dataframe?
procedure
(column-names d) → (listof string?)
d : dataframe?
procedure
(column-name d i) → string?
d : dataframe? i : exact-nonnegative-integer?
procedure
(ref x [key #:columns columns #:rows rows]) → any/c
x : has-ref? key : (or/c exact-nonnegative-integer? string?) = absent
columns :
(or/c exact-nonnegative-integer? string? (listof (or/c exact-nonnegative-integer? string?))) = absent rows : any/c = absent
procedure
(describe x) → dataframe?
x : describable?
2.2.1 Low-level DataFrame API
The generic layer above is built on a set of monomorphic dataframe-* bindings that operate directly on the foreign dataframe. They remain exported and accept the dataframe wrapper (it marshals transparently); the generic operations are simply the preferred surface.
procedure
(dataframe-new columns) → dataframe?
columns : (listof series?)
procedure
(dataframe-shape d) →
exact-nonnegative-integer? exact-nonnegative-integer? d : dataframe?
procedure
d : dataframe?
procedure
d : dataframe?
procedure
(dataframe-column d name) → series?
d : dataframe? name : string?
procedure
(dataframe-column-name d i) → string?
d : dataframe? i : exact-nonnegative-integer?
procedure
(dataframe-column-names d) → (listof string?)
d : dataframe?
procedure
(dataframe-select d names) → dataframe?
d : dataframe? names : (listof string?)
procedure
(display-dataframe d [out]) → void?
d : dataframe? out : output-port? = (current-output-port)
2.2.2 Reading & writing
procedure
(dataframe-write-csv d path) → void?
d : dataframe? path : path-string?
procedure
(dataframe-read-csv path) → dataframe?
path : path-string?
procedure
(dataframe-write-parquet d path) → void?
d : dataframe? path : path-string?
procedure
(dataframe-read-parquet path) → dataframe?
path : path-string?
procedure
(dataframe-write-json-lines d path) → void?
d : dataframe? path : path-string?
procedure
(dataframe-read-json-lines path) → dataframe?
path : path-string?
2.3 Fluent pipelines
A data-first layer that mirrors Polars’ Python method chaining. Because each operation takes the frame as its first argument, a pipeline reads as a thread-first ~> chain (re-provided from threading, so (require polars) is enough):
(~> df (filter (> (col "value") 15)) (group-by "group") (agg (alias (sum (col "value")) "sum_value")))
procedure
(> a b ...) → any/c
a : any/c b : any/c
procedure
(< a b ...) → any/c
a : any/c b : any/c
procedure
(>= a b ...) → any/c
a : any/c b : any/c
procedure
(<= a b ...) → any/c
a : any/c b : any/c
procedure
(= a b ...) → any/c
a : any/c b : any/c
procedure
(!= a b ...) → any/c
a : any/c b : any/c
procedure
(filter d predicate) → dataframe?
d : dataframe? predicate : any/c
procedure
(sort d names [#:descending descending]) → dataframe?
d : dataframe? names : (or/c string? (listof string?)) descending : (or/c boolean? (listof boolean?)) = #f
procedure
d : dataframe? key : (or/c string? any/c)
procedure
(agg g agg-expr ...) → dataframe?
g : grouped? agg-expr : any/c
procedure
v : any/c
procedure
(count x) → any/c
x : any/c
procedure
(n-unique x) → any/c
x : any/c
procedure
(median x) → any/c
x : any/c
procedure
(std x [#:ddof ddof]) → any/c
x : any/c ddof : exact-nonnegative-integer? = 1
procedure
(var x [#:ddof ddof]) → any/c
x : any/c ddof : exact-nonnegative-integer? = 1
procedure
(alias e name) → any/c
e : any/c name : string?
procedure
(first x) → any/c
x : (or/c string? pair? any/c)
procedure
(last x) → any/c
x : (or/c string? pair? any/c)
Name clash. racket/list also exports first and last (along with count and group-by, which polars exports too). Requiring both modules explicitly — (require racket/list polars) — is an error (identifier already required). A plain #lang racket/base program is unaffected, because racket/base does not export these names. See Shadowed bindings for how to take control.
2.3.1 Shadowed bindings
(require polars) re-exports a handful of generic operations whose names also live in racket/base (min, max, sort, filter, >, <, >=, <=, =) and in racket/list (first, last, count, group-by). Under #lang racket/base this is seamless — these names are either not bound (so polars simply provides them) or bound only by the module language (which an explicit require silently shadows), and the polars versions intentionally fall back to the numeric/list behaviour for non-frame arguments.
A conflict arises only when another module providing the same name is also required explicitly — most commonly racket/list. Resolve it with the usual require sub-forms:
; keep polars' first/last/count/group-by, drop racket/list's: (require (except-in racket/list first last count group-by) polars) ; keep racket/list's, reach polars' under a prefix: (require racket/list (prefix-in pl: polars)) ; then (pl:first (col "v")) for the Expr, (first '(1 2 3)) for the list ; keep polars', reach racket/list's under a prefix: (require polars (prefix-in list: racket/list))
2.4 Generic interfaces
The high-level operations are small, purpose-named racket/generic interfaces. A wrapper implements the interface for each capability it has — a series and a dataframe both have a len and a shape, so both implement gen:sized and gen:has-shape; only a series has a dtype. Each interface exports its method(s) and a predicate that recognises values implementing it.
syntax
procedure
(describable? v) → boolean?
v : any/c
syntax
procedure
v : any/c
syntax
procedure
(has-shape? v) → boolean?
v : any/c
syntax
procedure
(has-dtype? v) → boolean?
v : any/c
syntax
procedure
(has-null-count? v) → boolean?
v : any/c