On this page:
2.1 Series
series?
series
series->string
polars-null
polars-null?
dtype
len
null-count
sum
mean
min
max
rename
rename!
clone
series-clone
2.1.1 dtype promotion
2.1.2 Low-level Series API
Series-ptr?
series-new-i8
series-new-i16
series-new-i32
series-new-i64
series-new-u8
series-new-u16
series-new-u32
series-new-u64
series-new-f32
series-new-f64
series-new-bool
series-new-str
series-sum-i32
series-min-i32
series-max-i32
series-mean-i32
series-sum-f64
series-min-f64
series-max-f64
series-mean-f64
series-cast
2.2 Data  Frames
dataframe?
dataframe
shape
shape/  values
height
width
column-names
column-name
ref
describe
2.2.1 Low-level Data  Frame API
dataframe-new
dataframe-shape
dataframe-height
dataframe-width
dataframe-column
dataframe-column-name
dataframe-column-names
dataframe-select
display-dataframe
Data  Frame-ptr?
dataframe-vstack
2.2.2 Reading & writing
dataframe-write-csv
dataframe-read-csv
dataframe-write-parquet
dataframe-read-parquet
dataframe-write-json-lines
dataframe-read-json-lines
2.3 Expressions
Expr-ptr?
col
lit
expr-alias
expr-add
expr-sub
expr-mul
expr-div
expr-mod
expr-gt
expr-lt
expr-ge
expr-le
expr-eq
expr-ne
expr-and
expr-or
expr-xor
expr-not
expr-sum
expr-mean
expr-min
expr-max
expr-median
expr-count
expr-n-unique
expr-first
expr-last
expr-std
expr-var
2.3.1 Eager expression contexts
dataframe-select-exprs
dataframe-with-columns
dataframe-filter-expr
dataframe-group-by-agg
2.4 Lazy frames
Lazy  Frame-ptr?
lazyframe?
dataframe-lazy
lazyframe-collect
lazyframe-select
lazyframe-with-columns
lazyframe-filter
lazyframe-group-by-agg
lazyframe-join
2.5 Fluent pipelines
>
<
>=
<=
=
!=
and
or
not
xor
+
-
*
/
filter
sort
select
with-columns
cast
vstack
lazy
collect
group-by
agg
grouped?
count
n-unique
median
std
var
alias
first
last
2.5.1 Shadowed bindings
2.6 Generic interfaces
gen:  has-ref
has-ref?
gen:  sized
sized?
gen:  has-shape
has-shape?
gen:  has-dtype
has-dtype?
gen:  has-null-count
has-null-count?
9.3

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? v)  boolean?

  v : any/c
Returns #t if v is a series.

procedure

(series elements [#:name name #:dtype dtype])  series?

  elements : (or/c list? vector?)
  name : string? = ""
  dtype : (or/c #f symbol? pair?) = #f
Builds a series from a list or vector. When #:dtype is omitted the dtype is inferred from the elements; otherwise it is taken from dtype. Both short spellings ('i32, 'f64, 'str, 'bool) and canonical symbols ('int32, 'float64, 'string, 'boolean) are accepted. Use polars-null for missing values. Exact integers are coerced to flonums when the target dtype is floating point.

procedure

(series->string s)  string?

  s : series?
Renders s in Polars’ series format (a shape line, a Series: name [dtype] line, then the bracketed values, truncated to the first and last five when longer than ten). This is also what a series prints as in the REPL.

value

polars-null : any/c

procedure

(polars-null? v)  boolean?

  v : any/c
polars-null is the sentinel marking a missing value: pass it among the elements given to series to produce nulls, and it is what ref returns for a null entry. polars-null? tests for it.

procedure

(dtype s)  (or/c symbol? pair?)

  s : has-dtype?

procedure

(len x)  exact-nonnegative-integer?

  x : sized?

procedure

(null-count s)  exact-nonnegative-integer?

  s : has-null-count?
Generic series accessors. dtype returns the canonical dtype symbol (e.g. 'int32, 'float64, '(datetime milliseconds #f)). len returns the number of elements (and, on a dataframe, the number of rows). null-count returns the number of null entries.

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
These dispatch on their argument. Applied to a single series, they reduce it (dispatching on its dtype): min, max and sum preserve the input dtype, while mean always returns a float64, so the mean of an integer series is a flonum (see dtype promotion). Applied to a single expression or a bare column-name string, they produce the corresponding aggregation expression — so (sum (col "value")) reads like Polars’ col("value").sum() and is used inside agg (see Fluent pipelines). Applied to anything else they fall back to the usual numeric behaviour, so (max 1 2 3) still works.

procedure

(rename s new-name)  series?

  s : series?
  new-name : string?

procedure

(rename! s new-name)  void?

  s : series?
  new-name : string?

procedure

(clone s)  series?

  s : series?

procedure

(series-clone s)  series?

  s : series?
rename! renames a series in place (matching Polars), returning void as is conventional for ! mutators; rename returns a renamed copy and leaves the original untouched. clone (and its series-specific alias series-clone) returns an independent copy.

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.1.2 Low-level Series API🔗ℹ

The generic layer is built on monomorphic, dtype-suffixed bindings that operate directly on the foreign series. They remain exported. A series wrapper is accepted anywhere one of them expects a series (the wrapper marshals transparently, and satisfies Series-ptr?), but what they return is the raw foreign pointer, not a wrapper — so the results do not print in Polars’ format and do not answer to series?. Prefer series and the generic operations above; reach for these when you need a specific dtype or a specific typed result.

procedure

(Series-ptr? v)  boolean?

  v : any/c
Recognises a foreign series pointer. Both raw pointers returned by the low-level constructors and series wrappers satisfy it.

procedure

(series-new-i8 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-i16 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-i32 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-i64 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-u8 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-u16 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-u32 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-u64 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-f32 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-f64 name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-bool name values)  Series-ptr?

  name : string?
  values : list?

procedure

(series-new-str name values)  Series-ptr?

  name : string?
  values : list?
Build a series of the dtype named by the suffix from a list of values. polars-null among the values produces a null entry. Unlike series, no coercion happens: the integer constructors want exact integers, the float constructors want flonums (an exact 1 is rejected), series-new-bool wants booleans and series-new-str wants strings. Each constructor has a /vec sibling (series-new-i32/vec, series-new-f64/vec, …) that takes a vector instead of a list.

procedure

(series-sum-i32 s)  (or/c exact-integer? #f)

  s : Series-ptr?

procedure

(series-min-i32 s)  (or/c exact-integer? #f)

  s : Series-ptr?

procedure

(series-max-i32 s)  (or/c exact-integer? #f)

  s : Series-ptr?

procedure

(series-mean-i32 s)  (or/c flonum? #f)

  s : Series-ptr?

procedure

(series-sum-f64 s)  (or/c flonum? #f)

  s : Series-ptr?

procedure

(series-min-f64 s)  (or/c flonum? #f)

  s : Series-ptr?

procedure

(series-max-f64 s)  (or/c flonum? #f)

  s : Series-ptr?

procedure

(series-mean-f64 s)  (or/c flonum? #f)

  s : Series-ptr?
Typed reductions. The suffix names the dtype the series must have ('int32 or 'float64); applied to a series of any other dtype they return #f rather than converting, so (series-sum-i32 (series '(1 2))) is #f because series infers 'int64 for those elements. They also return #f when the reduction is undefined — the min, max or mean of a series whose entries are all null — while the sum of such a series is 0. The generic sum, min, max and mean dispatch on the dtype for you and are the preferred surface.

procedure

(series-cast s dtype)  Series-ptr?

  s : Series-ptr?
  dtype : (or/c symbol? pair?)
Returns a copy of s converted to dtype, given as a canonical dtype symbol ('int8 through 'int64, 'uint8 through 'uint64, 'float32, 'float64, 'boolean, 'string, 'binary, 'date, 'time, 'datetime, 'duration, 'null) or, for the two temporal dtypes with a time unit, as a list — '(datetime milliseconds), '(duration nanoseconds) — where the unit is one of 'nanoseconds, 'microseconds or 'milliseconds. Bare 'datetime and 'duration default to microseconds. Raises an error when Polars cannot perform the cast. The fluent cast wraps this for the generic layer.

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
Returns #t if v is a dataframe.

procedure

(dataframe columns)  dataframe?

  columns : (listof series?)
Builds a dataframe from a list of equal-length series. The columns may be series wrappers built with series; their names become the column names.

procedure

(shape x)  (listof exact-nonnegative-integer?)

  x : has-shape?

procedure

(shape/values x)  
exact-nonnegative-integer? ...
  x : has-shape?

procedure

(height d)  exact-nonnegative-integer?

  d : dataframe?

procedure

(width d)  exact-nonnegative-integer?

  d : dataframe?
shape returns the dimensions as a list — (list rows cols) for a dataframe and (list n) for a series — mirroring Polars’ shape tuples. shape/values returns the same dimensions as multiple values, for callers that want to bind them positionally with let-values or define-values. height and width return the row and column counts of a dataframe; height is also (len d).

procedure

(column-names d)  (listof string?)

  d : dataframe?

procedure

(column-name d i)  string?

  d : dataframe?
  i : exact-nonnegative-integer?
column-names returns all column names in order; column-name returns the name of the column at index i.

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
The generic element / column accessor. On a series, (ref s i) returns the element at index i. On a dataframe, a single selector — given positionally or as #:columns — returns that column (by name or index) as a series, and a list of selectors returns a column-projected dataframe. It is data-first, so it threads. #:rows is reserved for row slicing and currently raises an error. Provided by the gen:has-ref interface.

procedure

(describe x)  dataframe?

  x : (or/c series? dataframe?)
Mirrors Polars’ .describe(): returns a summary-statistics dataframe (which prints as a table). For a series the result has a "statistic" column and a "value" column, with rows adapted to the dtype — a numeric series gets "count", "null_count", "mean", "std", "min", "25%", "50%", "75%" and "max"; a boolean series drops "std" and the quantiles; other dtypes (string, temporal) keep just "count", "null_count", "min" and "max". For a dataframe the result uses Polars’ fixed nine-row layout (a "statistic" column plus one column per input column), leaving a cell polars-null where a column has no value for that statistic. Quantiles use nearest interpolation. Dispatches on series? / dataframe?.

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

(dataframe-height d)  exact-nonnegative-integer?

  d : dataframe?

procedure

(dataframe-width d)  exact-nonnegative-integer?

  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)
The low-level dataframe operations underlying dataframe, shape, height, width, ref, column-name, and column-names. display-dataframe prints the Polars table to out; since a dataframe now prints itself, prefer plain display.

procedure

(DataFrame-ptr? v)  boolean?

  v : any/c
Recognises a foreign dataframe pointer. Both raw pointers returned by the low-level operations and dataframe wrappers satisfy it.

procedure

(dataframe-vstack top bottom)  DataFrame-ptr?

  top : DataFrame-ptr?
  bottom : DataFrame-ptr?
Stacks the rows of bottom beneath those of top, which must have the same columns in the same order, and returns the combined frame (Polars’ vstack). The fluent vstack is the wrapper-returning equivalent.

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?
Round-trip a dataframe through CSV, Parquet, or newline-delimited JSON.

2.3 Expressions🔗ℹ

An expression describes a column computation — a column reference, a literal, or an operation over other expressions — without running it. The same expression can be reused across the select, with_columns, filter and group_by/agg contexts, exactly as in Polars, and is evaluated only when a context runs it against a frame. Expressions are foreign values recognised by Expr-ptr?.

The bindings below are the monomorphic expr-* layer. Most of them have a generic counterpart in Fluent pipelinesexpr-gt underlies >, expr-sum underlies the expression arm of sum, expr-alias underlies alias — and the generic spelling is the preferred one; the expr-* names are useful when a name would otherwise be shadowed, or when you want to be explicit that an expression is being built.

procedure

(Expr-ptr? v)  boolean?

  v : any/c
Returns #t if v is an expression.

procedure

(col name)  Expr-ptr?

  name : string?

procedure

(lit v)  Expr-ptr?

  v : (or/c boolean? exact-integer? real? string?)

procedure

(expr-alias e name)  Expr-ptr?

  e : Expr-ptr?
  name : string?
The leaves. col refers to the column called name (pl.col). lit lifts a Racket scalar to a literal expression: booleans, exact integers (32-bit when they fit, 64-bit otherwise), other reals (as 'float64) and strings. Every binary expr-* operation applies lit to a non-expression operand automatically, so it is rarely needed explicitly. expr-alias names the column an expression produces, matching .alias: (expr-alias (expr-sum (col "value")) "total").

procedure

(expr-add a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-sub a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-mul a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-div a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-mod a b)  Expr-ptr?

  a : any/c
  b : any/c
Element-wise arithmetic. At least one operand is normally an expression; the other may be a scalar, which is lifted with lit, so (expr-mul (col "value") 2) reads like col("value") * 2. The generic +, -, * and / dispatch to these when given an expression.

procedure

(expr-gt a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-lt a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-ge a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-le a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-eq a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-ne a b)  Expr-ptr?

  a : any/c
  b : any/c
Element-wise comparisons producing a boolean expression; scalars are lifted with lit. (expr-gt (col "value") 15) is col("value") > 15. The generic >, <, >=, <=, = and != dispatch to these when given an expression.

procedure

(expr-and a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-or a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-xor a b)  Expr-ptr?

  a : any/c
  b : any/c

procedure

(expr-not e)  Expr-ptr?

  e : Expr-ptr?
Element-wise boolean logic over boolean expressions, for combining predicates: (expr-and (expr-gt (col "value") 15) (expr-lt (col "cost") 3.0)). The generic and, or, xor and not dispatch to these when given an expression.

procedure

(expr-sum e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-mean e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-min e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-max e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-median e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-count e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-n-unique e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-first e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-last e)  Expr-ptr?

  e : Expr-ptr?

procedure

(expr-std e [#:ddof ddof])  Expr-ptr?

  e : Expr-ptr?
  ddof : exact-nonnegative-integer? = 1

procedure

(expr-var e [#:ddof ddof])  Expr-ptr?

  e : Expr-ptr?
  ddof : exact-nonnegative-integer? = 1
Aggregations. Each reduces the column e evaluates to — over the whole frame in a select, or per group inside group_by/agg. expr-count counts the non-null entries, as Polars’ .count() does. expr-std and expr-var take a #:ddof degrees-of-freedom adjustment, defaulting to 1. The generic sum, mean, min, max, median, count, n-unique, first, last, std and var dispatch to these when given an expression or a column name.

2.3.1 Eager expression contexts🔗ℹ

These run expressions against a dataframe and return a new frame in one step. Each is the eager convenience over the corresponding lazy operation in Lazy frames: it converts with dataframe-lazy, applies the operation, and lazyframe-collects. Like the rest of the low-level layer they accept a dataframe wrapper but return a raw DataFrame-ptr?; the fluent select, with-columns, filter and group-by/agg are the wrapper-returning equivalents.

procedure

(dataframe-select-exprs df exprs)  DataFrame-ptr?

  df : DataFrame-ptr?
  exprs : (listof Expr-ptr?)

procedure

(dataframe-with-columns df exprs)  DataFrame-ptr?

  df : DataFrame-ptr?
  exprs : (listof Expr-ptr?)

procedure

(dataframe-filter-expr df predicate)  DataFrame-ptr?

  df : DataFrame-ptr?
  predicate : Expr-ptr?
dataframe-select-exprs evaluates exprs and returns a frame containing only the resulting columns (df.select(...)). dataframe-with-columns evaluates them and adds (or replaces) the resulting columns alongside the existing ones (df.with_columns(...)). dataframe-filter-expr keeps the rows for which the boolean predicate holds (df.filter(...)).

procedure

(dataframe-group-by-agg df keys aggs)  DataFrame-ptr?

  df : DataFrame-ptr?
  keys : (listof (or/c string? Expr-ptr?))
  aggs : (listof Expr-ptr?)
Groups df by keys — column names, or expressions — and evaluates each aggregation in aggs once per group, returning a frame with one row per group (df.group_by(...).agg(...)). The row order of the result is not guaranteed.

2.4 Lazy frames🔗ℹ

A lazyframe is a query plan: a sequence of operations over a frame that Polars optimises as a whole and runs only when asked to collect. The low-level surface mirrors the eager dataframe-* bindings and, like them, returns raw foreign pointers; the fluent lazy and collect are the wrapper-returning equivalents.

procedure

(LazyFrame-ptr? v)  boolean?

  v : any/c

procedure

(lazyframe? v)  boolean?

  v : any/c
LazyFrame-ptr? recognises a foreign lazyframe pointer, raw or wrapped. lazyframe? recognises only the wrapper produced by the fluent lazy.

procedure

(dataframe-lazy df)  LazyFrame-ptr?

  df : DataFrame-ptr?

procedure

(lazyframe-collect lf)  DataFrame-ptr?

  lf : LazyFrame-ptr?
dataframe-lazy starts a plan from an in-memory frame (df.lazy()); lazyframe-collect executes a plan and returns the resulting frame (lf.collect()).

procedure

(lazyframe-select lf exprs)  LazyFrame-ptr?

  lf : LazyFrame-ptr?
  exprs : (listof Expr-ptr?)

procedure

(lazyframe-with-columns lf exprs)  LazyFrame-ptr?

  lf : LazyFrame-ptr?
  exprs : (listof Expr-ptr?)

procedure

(lazyframe-filter lf predicate)  LazyFrame-ptr?

  lf : LazyFrame-ptr?
  predicate : Expr-ptr?

procedure

(lazyframe-group-by-agg lf keys aggs)  LazyFrame-ptr?

  lf : LazyFrame-ptr?
  keys : (listof (or/c string? Expr-ptr?))
  aggs : (listof Expr-ptr?)
The lazy forms of the Eager expression contexts. Each appends a step to the plan and returns the extended plan; nothing runs until lazyframe-collect.

procedure

(lazyframe-join left    
  right    
  [#:on on    
  #:left-on left-on    
  #:right-on right-on    
  #:how how])  LazyFrame-ptr?
  left : LazyFrame-ptr?
  right : LazyFrame-ptr?
  on : (or/c #f (listof string?)) = #f
  left-on : (or/c #f (listof string?)) = #f
  right-on : (or/c #f (listof string?)) = #f
  how : (or/c 'inner 'left 'outer 'full 'cross) = 'inner
Joins two plans. Give the key columns either as one list with #:on, when they have the same names on both sides, or as parallel #:left-on and #:right-on lists. #:how selects the join kind; 'outer and 'full are synonyms, and a 'cross join takes no keys. Omitting the keys for any other kind is an error. Collect the result with lazyframe-collect:

(lazyframe-collect
 (lazyframe-join (dataframe-lazy users) (dataframe-lazy orders)
                 #:on '("uid") #:how 'inner))

2.5 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
Overloaded comparison operators. If an operand is an expression, they build a comparison expression (scalars are lifted automatically), so (> (col "value") 15) reads like col("value") > 15. If an operand is a series, they build an eager boolean-mask series — element-wise over every numeric dtype, including 'int64 — so (> (ref df #:columns "value") 15) is a mask. Otherwise they fall back to the numeric racket/base operator and stay variadic, so (> 3 2) and (< 1 2 3) still work. != has no racket/base spelling; on numbers it is (not (= a b)). These shadow the racket/base comparisons; see Shadowed bindings.

syntax

(and expr ...)

syntax

(or expr ...)

procedure

(not x)  any/c

  x : any/c

procedure

(xor a b)  any/c

  a : any/c
  b : any/c
Overloaded boolean connectives. When an operand is an expression they build the element-wise expression (expr-and, expr-or, expr-not, expr-xor), so (and (> (col "value") 15) (< (col "cost") 3.0)) is a predicate for filter. When an operand is a series they compute an eager boolean mask. Otherwise they behave as the racket/base forms: and and or short-circuit and return the deciding value, and not negates. Note that once and or or meets an expression or series operand it evaluates its remaining operands eagerly to combine them. These shadow the racket/base bindings; see Shadowed bindings.

procedure

(+ v ...)  any/c

  v : any/c

procedure

(- v ...)  any/c

  v : any/c

procedure

(* v ...)  any/c

  v : any/c

procedure

(/ v ...)  any/c

  v : any/c
Overloaded arithmetic. When every argument is a number they are exactly the racket/base operators. Otherwise they fold left over the arguments: an expression operand yields an expression (via expr-add, expr-sub, expr-mul, expr-div), so (* (col "value") 2) reads like col("value") * 2, and a series operand yields an eagerly computed series. A single non-numeric argument is returned unchanged. These shadow the racket/base bindings; see Shadowed bindings.

procedure

(filter d predicate)  dataframe?

  d : dataframe?
  predicate : any/c
Keeps the rows of d matching predicate, which may be a boolean expression — (filter df (> (col "value") 15)) — or a precomputed boolean-mask series. Returns a new dataframe. Applied to a non-dataframe it falls back to racket/base’s filter, so (filter even? '(1 2 3 4)) is '(2 4).

procedure

(sort d names [#:descending descending])  dataframe?

  d : dataframe?
  names : (or/c string? (listof string?))
  descending : (or/c boolean? (listof boolean?)) = #f
Sorts d by one or more columns. #:descending is a single boolean applied to all keys, or a per-key list. Applied to a non-dataframe it falls back to racket/base’s sort, so (sort '(3 1 2) <) is '(1 2 3).

procedure

(select d spec ...)  (or/c dataframe? lazyframe?)

  d : (or/c dataframe? lazyframe?)
  spec : any/c

procedure

(with-columns d spec ...)  (or/c dataframe? lazyframe?)

  d : (or/c dataframe? lazyframe?)
  spec : any/c
The select and with_columns contexts. Each spec is a column name, a column index, an expression, or a list of those (which is spliced); names and indices are lifted with col. select returns a frame holding only the resulting columns; with-columns adds them to (or replaces them in) the existing columns. Given a dataframe they run eagerly and return a dataframe; given a lazyframe they extend the plan and return a lazyframe.

procedure

(cast x dtype)  (or/c Expr-ptr? series?)

  x : (or/c Expr-ptr? series? string?)
  dtype : (or/c symbol? pair?)
Changes dtype. On an expression (or a column name, lifted with col) it builds a cast expression, matching .cast; on a series it converts eagerly and returns a series. dtype takes the same spellings as series-cast.

procedure

(vstack top bottom)  dataframe?

  top : dataframe?
  bottom : dataframe?
Stacks the rows of bottom beneath those of top, which must have the same columns in the same order (Polars’ vstack).

procedure

(lazy d)  lazyframe?

  d : dataframe?

procedure

(collect lf)  dataframe?

  lf : lazyframe?
lazy turns a dataframe into a lazyframe — a plan that select, with-columns, filter and the other fluent operations extend without running anything — and collect executes the plan and returns the resulting dataframe.

procedure

(group-by d key ...)  grouped?

  d : dataframe?
  key : (or/c string? any/c)

procedure

(agg g agg-expr ...)  dataframe?

  g : grouped?
  agg-expr : any/c

procedure

(grouped? v)  boolean?

  v : any/c
group-by captures d and one or more group keys in a deferred grouped handle — no work happens yet — so it threads cleanly. agg consumes the handle, computing the aggregation expressions per group in a single pass, and returns a dataframe with one row per group. The split mirrors df.group_by("g").agg(...); the row order of the result is not guaranteed.

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?
Aggregation-expression builders for use inside agg, alongside the expression arms of sum, mean, min and max. Each accepts an expression or a bare column-name string (lifted with col), so (count "value") and (count (col "value")) are equivalent. alias names a result, matching Polars’ .alias: (alias (sum (col "value")) "total"). std and var take a #:ddof degrees-of-freedom adjustment, defaulting to 1.

procedure

(first x)  any/c

  x : (or/c string? pair? any/c)

procedure

(last x)  any/c

  x : (or/c string? pair? any/c)
Dual-purpose. On an expression or column-name string they build the first/last-element aggregation (Polars’ .first() / .last()), for use inside agg. On a list they are the ordinary list accessors, so (first '(1 2 3)) is 1 and (last '(1 2 3)) is 3 — matching racket/list.

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.5.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.6 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

gen:has-ref

procedure

(has-ref? v)  boolean?

  v : any/c
The ref capability (method: ref). Implemented by series and dataframes.

syntax

gen:sized

procedure

(sized? v)  boolean?

  v : any/c
The len capability (method: len). Implemented by series (number of elements) and dataframes (number of rows).

syntax

gen:has-shape

procedure

(has-shape? v)  boolean?

  v : any/c
The shape capability (method: shape). Implemented by series and dataframes.

syntax

gen:has-dtype

procedure

(has-dtype? v)  boolean?

  v : any/c
The dtype capability (method: dtype). Implemented by series.

syntax

gen:has-null-count

procedure

(has-null-count? v)  boolean?

  v : any/c
The null-count capability (method: null-count). Implemented by series.