golars

Cookbook

End-to-end recipes for common tasks. Every snippet compiles.

End-to-end recipes for common tasks. Every snippet compiles and assumes import "github.com/Gaurav-Gosain/golars" plus whatever sub-package a particular line needs.

Typed columns for compile-time literal checks

The expr package ships a typed facade (expr.C[T], expr.Int, expr.Float, expr.Str, expr.Bool) that lets Go infer literal types from method arguments, eliminating the expr.Lit(int64(...)) boilerplate:

import "github.com/Gaurav-Gosain/golars/expr"

qty := expr.Int("qty")
price := expr.Float("price")

out, _ := lazy.FromDataFrame(df).
    Filter(expr.All(qty.Gt(2), price.Lt(50))).
    WithColumns(
        price.MulCol(qty.CastFloat64()).As("total").Expr,
        qty.Between(2, 5).Alias("in_range"),
    ).
    Collect(ctx)

The runtime plan is identical to the untyped expr.Col("qty").GtLit(int64(2)) form. Passing a string literal to an int-typed column fails at build time rather than panicking at evaluation. See examples/*/generic/ for side-by-side comparisons.

List, struct and name namespaces

Expression namespaces mirror polars' .list.*, .struct.* and .name.*. Str().Split produces a List<str> column to work on, and List().Eval runs any expression over the elements of each list, with golars.Element() standing in for the element:

tagList := golars.Col("tags").Str().Split(",")
nums := golars.Col("scores").Str().Split(" ").
    List().Eval(golars.Element().Cast(dtype.Int64()))

out, _ := golars.Lazy(df).
    Select(
        golars.Col("user"),
        tagList.List().Len().Alias("n_tags"),
        tagList.List().Contains("go").Alias("has_go"),
        tagList.List().Unique(true).List().JoinWith("|", true).Alias("unique_tags"),
        nums.List().Sum().Alias("total"),
        nums.List().Sort(true, false).List().Head(2).Alias("top2"),
        nums.List().Eval(golars.Element().Mul(golars.Lit(int64(10)))).Alias("x10"),
    ).
    Collect(ctx)
// "go,db,go" / "3 9 4" gives n_tags=3, has_go=true, unique_tags="go|db",
// total=16, top2=[9, 4], x10=[30, 90, 40].

The list namespace also covers the reducers (Mean, Min, Max, Median, Std, Var, NUnique, ArgMin, ArgMax, Any, All), positional access (Get, First, Last, Gather, Slice, Tail), set operations (SetUnion, SetIntersection, SetDifference), Filter, Explode, ToStruct and ToArray. Fixed-width arrays have the same shape of API under Arr().

Build a struct with golars.Struct, then read, rename or unnest its fields:

packed, _ := golars.Lazy(df).
    Select(golars.Col("user"), golars.Struct(golars.Col("x"), golars.Col("y")).Alias("point")).
    Collect(ctx)

flat, _ := golars.Lazy(packed).
    Select(
        golars.Col("point").Struct().Field("y").Alias("point_y"),
        // Unnest expands into one output column per field.
        golars.Col("point").Struct().RenameFields("px", "py").Struct().Unnest(),
    ).
    Collect(ctx)
// columns: point_y, px, py

Name() renames an expression's output without touching its values:

named, _ := golars.Lazy(df).
    Select(
        golars.Col("x").Name().Prefix("raw_"),                       // raw_x
        golars.Col("y").Mul(golars.Lit(2.0)).Name().Suffix("_x2"),   // y_x2
        golars.Col("user").Name().Map(strings.ToUpper),              // USER
    ).
    Collect(ctx)

See examples/namespaces for a runnable version that also covers the str and cat namespaces.

Parse dates and work with time

Str().ToDate, ToDatetime and ToTime parse strings with strftime-style formats (Str().Strptime takes an explicit dtype). The Dt() namespace then reads calendar fields, truncates, formats, and converts time zones:

df, _ := golars.Lazy(raw).
    WithColumns(golars.Col("ts").Str().ToDatetime("%Y-%m-%d %H:%M")).
    WithColumns(
        golars.Col("ts").Dt().Weekday().Alias("weekday"),     // 1 = Monday
        golars.Col("ts").Dt().Truncate("1h").Alias("hour"),
        golars.Col("ts").Dt().Strftime("%a %H:%M").Alias("label"),
        // Mean over the trailing 2 hours of each row's timestamp.
        golars.Col("temp").RollingMeanBy(golars.Col("ts"), "2h").Alias("temp_2h"),
    ).
    Collect(ctx)

// Attach a zone to naive timestamps, then convert for display.
tokyo, _ := golars.Lazy(df).
    Select(golars.Col("ts").Dt().ReplaceTimeZone("UTC").
        Dt().ConvertTimeZone("Asia/Tokyo").Alias("tokyo")).
    Collect(ctx)

Durations use polars' string form ("90s", "1h30m", "1mo", "2w"), and calendar units such as mo and y respect month lengths. golars.DateRange, DatetimeRange and TimeRange build ranges as expressions; golars.DateRangeSeries builds one directly.

The CSV reader infers ISO dates and timestamps by default. golars.WithTryParseDates(true) also accepts layouts such as 31/12/2021 and UTC offsets, and WithTryParseDates(false) keeps those columns as strings, like polars' default.

Time windows with group_by_dynamic

GroupByDynamic buckets a sorted temporal (or integer) index column into fixed windows, the equivalent of polars' group_by_dynamic:

buckets, _ := golars.Lazy(df).
    GroupByDynamic("ts", golars.DynamicGroupOptions{
        Every:             "3h",
        IncludeBoundaries: true,
    }).
    Agg(
        golars.Col("temp").Mean().Alias("avg_temp"),
        golars.Col("temp").Count().Alias("n"),
    ).
    Collect(ctx)
// _lower_boundary      _upper_boundary      ts                   avg_temp  n
// 2024-03-01T06:00:00  2024-03-01T09:00:00  2024-03-01T06:00:00  18.75     2
// ...

DynamicGroupOptions also takes Period (window length, default Every), Offset, Closed, Label, StartBy and GroupBy for per-key windows. The one-window-per-row variant is lf.Rolling(index, golars.RollingGroupOptions{Period: "2h"}). Both exist on the eager DataFrame too.

Asof joins

JoinAsof matches every left row with the nearest right row by a sorted key, optionally inside exact-match By groups. The classic use is attaching the latest quote to each trade:

at := func(hms string) time.Time {
    t, _ := time.Parse(time.DateTime, "2024-05-01 "+hms)
    return t
}
tt, _ := golars.FromTimes("time", []time.Time{at("09:30:05"), at("09:31:00"), at("09:36:00")}, nil, golars.Milliseconds, "")
tsym, _ := golars.FromString("symbol", []string{"AAPL", "MSFT", "AAPL"}, nil)
qty, _ := golars.FromInt64("qty", []int64{100, 50, 75}, nil)
trades, _ := golars.NewDataFrame(tt, tsym, qty)
defer trades.Release()

qt, _ := golars.FromTimes("time", []time.Time{at("09:30:00"), at("09:30:00"), at("09:33:00")}, nil, golars.Milliseconds, "")
qsym, _ := golars.FromString("symbol", []string{"AAPL", "MSFT", "AAPL"}, nil)
bid, _ := golars.FromFloat64("bid", []float64{189.1, 410.0, 189.4}, nil)
quotes, _ := golars.NewDataFrame(qt, qsym, bid)
defer quotes.Release()

// Latest quote for the same symbol, at most two minutes old.
out, _ := trades.JoinAsof(ctx, quotes, golars.AsofOptions{
    On:        "time",
    By:        []string{"symbol"},
    Strategy:  dataframe.AsofBackward,
    Tolerance: "2m",
})
// bid: 189.1, 410, null (the 09:33 AAPL quote is 3 minutes old)

// The lazy form takes the same options.
near, _ := golars.Lazy(trades).
    JoinAsof(golars.Lazy(quotes), golars.AsofOptions{
        On: "time", By: []string{"symbol"}, Strategy: dataframe.AsofNearest,
    }).
    Collect(ctx)

Strategies are AsofBackward (the default), AsofForward and AsofNearest. Without By, both key columns must be sorted ascending unless SkipSortednessCheck is set. For inequality joins on arbitrary predicates see lf.JoinWhere. A runnable version lives in examples/join_asof.

Bin values with cut and qcut

bins, _ := golars.Lazy(df).
    WithColumns(
        golars.Col("v").Cut([]float64{5, 10}, expr.CutOptions{}).Alias("cut"),
        golars.Col("v").Cut([]float64{5, 10},
            expr.CutOptions{Labels: []string{"low", "mid", "high"}}).Alias("label"),
        golars.Col("v").QCutN(2, expr.CutOptions{}).Alias("half"),
        golars.Col("v").QCut([]float64{0.25, 0.75},
            expr.CutOptions{Labels: []string{"q1", "iqr", "q4"}}).Alias("quartile"),
    ).
    Collect(ctx)
// v=[1, 5, 9, 12, 20]
// cut:      (-inf, 5]  (-inf, 5]  (5, 10]  (10, inf]  (10, inf]
// quartile: q1         q1         iqr      iqr        q4

CutOptions.LeftClosed switches to [a, b) intervals and IncludeBreaks returns a {breakpoint, category} struct. The category column is a string column; polars returns Categorical with the same labels.

Custom Go functions with map_batches

MapBatches hands the whole evaluated column to a Go function and uses the returned Series. Inside GroupBy().Agg and Over the function sees one group at a time.

zscore := func(s *series.Series) (*series.Series, error) {
    mean, err := s.Mean()
    if err != nil {
        return nil, err
    }
    std, err := s.Std()
    if err != nil {
        return nil, err
    }
    return s.ApplyFloat64(func(x float64) float64 { return (x - mean) / std })
}

z, _ := golars.Lazy(df).
    Select(golars.Col("v").Cast(dtype.Float64()).MapBatches(zscore).Alias("z")).
    Collect(ctx)

// Per value, with Go types checked at compile time:
lower, _ := golars.Lazy(df).
    Select(golars.MapElements(golars.Col("symbol"), strings.ToLower).Alias("sym")).
    Collect(ctx)

The function must not retain or release its input. Prefer a built-in expression when one exists: the optimiser can see through it, while a Go callback is opaque to it.

Unnest / explode / upsample

Unnest a struct column:

out, _ := df.Unnest(ctx, "payload")
// struct {x:i64, y:str} becomes two top-level cols `x` and `y`.

Explode a list column (null and empty lists become a single null row):

out, _ := df.Explode(ctx, "tags")
// [[a, b, c], [], NULL, [d]] produces 3 + 1 + 1 + 1 = 6 rows.

Upsample a sorted timestamp column to a dense grid:

out, _ := df.Upsample(ctx, "ts", "1d")
// missing daily slots are inserted with nulls in every other column.

Accepted intervals: ns, us, ms, s, m, h, d, w. The column must already be sorted ascending. Calendar units (mo, q, y) are rejected.

Pretty-print a logical plan

fmt.Println(lazy.ExplainTree(lf.Plan()))
// SORT [total desc]
// └── AGG keys=[dept] [col("salary").sum().alias("total")]
//     └── FILTER (col("salary") > 75)
//         └── SCAN df

lazy.ExplainTreeASCII swaps the box-drawing glyphs for ASCII fallbacks. lf.ExplainTree() is the full three-section report (logical, optimiser, optimised) rendered as a tree.

Read a CSV, filter, write Parquet

df, _ := golars.ReadCSV("trades.csv")
defer df.Release()

out, _ := golars.Lazy(df).
    Filter(golars.Col("volume").GtLit(int64(100))).
    Collect(ctx)
defer out.Release()

golars.WriteParquet(out, "heavy_trades.parquet")

Group + aggregate multiple columns in one pass

agg, _ := golars.Lazy(df).
    GroupBy("symbol").
    Agg(
        golars.Sum("qty"),
        golars.Mean("price").Alias("avg_price"),
        golars.Max("price").Alias("hi"),
    ).
    Sort("qty", true).
    Collect(ctx)

An unaliased aggregation keeps its input column name, so golars.Sum("qty") produces a column named qty. golars buckets the aggregations by input column; when a bucket holds two or more of sum/mean/min/max/count/null_count over an int64 or float64 column, they are fused through dataframe/groupby_fused.go, so the mean and max over price cost one scan.

Join a CSV against a Parquet lookup table

trades, _ := golars.ReadCSV("trades.csv")
defer trades.Release()
lookup, _ := golars.ReadParquet("symbols.parquet")
defer lookup.Release()

out, _ := golars.Lazy(trades).
    Join(golars.Lazy(lookup), []string{"symbol"}, golars.InnerJoin).
    Collect(ctx)

Scan (lazy I/O) plus predicate pushdown

import iocsv "github.com/Gaurav-Gosain/golars/io/csv"

// iocsv.Scan returns a LazyFrame that opens the file only when
// Collect runs. Combined with Filter + Select, the optimiser pushes
// the projection down through the scan.
lf := iocsv.Scan("/tmp/huge.csv").
    Filter(golars.Col("region").EqLit("us")).
    Select(golars.Col("symbol"), golars.Col("price"))

for batch, err := range lf.IterBatches(ctx) {
    if err != nil { log.Fatal(err) }
    // stream-process each batch here
    batch.Release()
}

Null handling: drop, fill, or flag

clean, _ := golars.Lazy(df).DropNulls("price", "qty").Collect(ctx)
filled, _ := golars.Lazy(df).FillNull(int64(0)).Collect(ctx)

mask, _ := df.AnyNullMask(ctx)
defer mask.Release()
// `mask` is a boolean Series you can plug back into Filter to flag
// bad rows without dropping them.

Select by dtype or name predicate

import "github.com/Gaurav-Gosain/golars/selector"

numericOnly, _ := df.SelectBy(selector.Numeric())
noTimes := df.DropBy(selector.EndsWith("_ts"))

// Combinators: intersect, union, minus.
usdCols, _ := df.SelectBy(selector.Intersect(
    selector.Float(),
    selector.StartsWith("price_usd"),
))

Cross-language with Arrow

rec := df.ToArrow()          // arrow.RecordBatch
tbl := df.ToArrowTable()     // arrow.Table (multi-chunk)
roundtrip, _ := dataframe.FromArrowTable(tbl)

Both sides are Arrow IPC format-compatible. Write with io/ipc.Write and read in PyArrow, pola.rs, DuckDB, or any other Arrow-aware tool without format conversion.

String munging

out, _ := df.Apply(func(s *series.Series) (*series.Series, error) {
    if s.Name() != "email" { return s.Clone(), nil }
    return s.Str().Before("@")
})

.Str().Before / .After / .SplitNth cover the common parsing cases; .SplitWide returns multiple Series so you can stitch them into a DataFrame with extra columns.

Cache an intermediate pipeline

base := golars.Lazy(df).
    Filter(golars.Col("active").EqLit(true)).
    Cache()

// Two downstream pipelines share the same filtered base.
top, _ := base.Sort("score", true).Head(10).Collect(ctx)
flag, _ := base.Filter(golars.Col("score").LtLit(0.5)).Collect(ctx)

Cache memoises the first Collect result; subsequent collects reuse it. The cached frame is released automatically when the cache's LazyFrame handle is garbage-collected.

When / then / otherwise

out, _ := golars.Lazy(df).
    Select(golars.When(golars.Col("age").Gt(golars.Lit(18))).
        Then(golars.Lit("adult")).
        Otherwise(golars.Lit("minor")).
        Alias("category")).
    Collect(ctx)

Mixed numeric dtypes are promoted (int then + float otherwise -> float64 out). Null cond values are treated as false (polars semantics).

Rolling operations

// Rolling sum/mean/min/max/std/var with a fixed window.
out, _ := golars.Lazy(df).
    Select(
        golars.Col("price").RollingMean(30, 1).Alias("ma30"),
        golars.Col("price").RollingStd(30, 5).Alias("vol30"),
    ).Collect(ctx)

Second argument is min_periods (0 = require full window). Int64 inputs with no nulls take a SIMD-friendly O(n) slide (two-phase warmup + 4-way unrolled step).

Regex on strings

// Boolean mask for regex hits.
s, _ := series.FromString("s", []string{"a1", "xx", "b22"}, nil)
mask, _ := s.Str().ContainsRegex(`\d+`)

// Extract first capture group.
ids, _ := emails.Str().Extract(`@([a-z.]+)$`, 1)

// Count matches per row.
counts, _ := tokens.Str().CountMatchesRegex(`\w+`)

Pivot (long -> wide)

// Mirror of polars' df.pivot(index="id", on="cat", values="v").
wide, _ := df.Pivot(ctx, []string{"id"}, "cat", "v", dataframe.PivotSum)

Aggregators: PivotFirst, PivotSum, PivotMean, PivotMin, PivotMax, PivotCount.

Window functions with .Over(...)

// Per-group total broadcast back to every row.
out, _ := golars.Lazy(df).
    Select(golars.Col("revenue").Sum().Over("region").Alias("region_total")).
    Collect(ctx)

// Per-group rank.
ranked, _ := golars.Lazy(df).
    Select(golars.Col("score").Rank("dense").Over("cohort").Alias("rank_in_cohort")).
    Collect(ctx)

Forward / backward fill + NaN

// Replace every NaN with 0 in float columns (integer cols pass through).
filled, _ := golars.Lazy(df).FillNan(0).Collect(ctx)

// Carry the last non-null value forward through consecutive nulls.
// Pass limit=3 to stop after three consecutive fills; limit=0 means unlimited.
ff, _ := golars.Lazy(df).ForwardFill(0).Collect(ctx)
bf, _ := golars.Lazy(df).BackwardFill(0).Collect(ctx)

// Per-column variant via Expr:
out, _ := golars.Lazy(df).
    WithColumns(golars.Col("price").ForwardFill(0).Alias("price")).
    Collect(ctx)

Reshape: transpose, unpivot, partition

// Transpose: each input column becomes a row; output value type is
// the promoted float64 (polars' object-dtype fallback is not yet
// supported, so non-numeric inputs error).
wide, _ := df.Transpose(ctx, "column", "row")

// Unpivot (melt): turn value columns into two long-form columns:
//   variable (the original column name) + value.
long, _ := df.Unpivot(ctx, []string{"id"}, nil /* default: all non-id */)

// Partition: one DataFrame per distinct key tuple; ordered by first
// appearance. Caller releases each partition.
parts, _ := df.PartitionBy(ctx, "region", "symbol")
for _, p := range parts {
    defer p.Release()
}

Top-K / Bottom-K / Pipe

topSellers, _ := df.TopK(ctx, 10, "revenue")
worstLatency, _ := df.BottomK(ctx, 5, "p99_ms")

// Pipe keeps chained code flat:
out, _ := df.Pipe(func(d *golars.DataFrame) (*golars.DataFrame, error) {
    return d.Filter(ctx, mask)
})

Stats: skew, kurtosis, corr, cov, approx_n_unique

sk, _ := col.Skew()                    // polars default (biased)
sku, _ := col.SkewUnbiased()           // scipy bias=False
kk, _ := col.Kurtosis()                // excess kurtosis

c, _ := a.PearsonCorr(b)               // Pearson r
cov, _ := a.Covariance(b, 1)           // ddof=1

corrMat, _ := df.Corr(ctx)             // k-by-k frame
covMat, _ := df.Cov(ctx, 1)

approx, _ := col.ApproxNUnique()       // HLL estimate

Extra math helpers

// Trig + hyperbolic family: atan2, cbrt, sinh/cosh/tanh, log1p, expm1,
// radians/degrees, arccos/arcsin/arctan, cot, arcsinh/arccosh/arctanh.
radians, _ := col.Radians()
y, _ := colY.Arctan2(colX)

Coalesce, concat_str, ones/zeros/int_range

picked, _ := golars.Lazy(df).
    Select(golars.Coalesce(golars.Col("primary"), golars.Col("fallback"))).
    Collect(ctx)

joined, _ := golars.Lazy(df).
    Select(golars.ConcatStr("-", golars.Col("sym"), golars.Col("year"))).
    Collect(ctx)

// Build Series out of thin air:
ids, _ := golars.Lazy(df).
    WithColumns(golars.IntRange(0, 100, 1).Alias("idx")).
    Collect(ctx)

Arrow IPC streaming (cross-language)

sw, _ := golars.NewIPCStreamWriter(conn, firstBatch)
for batch := range batches {
    sw.Write(ctx, batch)
}
sw.Close()

// Consumer side (also polars/pyarrow/DuckDB-compatible):
sr, _ := golars.NewIPCStreamReader(conn)
defer sr.Close()
for batch, err := range sr.Iter(ctx) {
    if err != nil { log.Fatal(err) }
    process(batch)
    batch.Release()
}

Row-wise (horizontal) reductions

// Append a column that sums three others on a per-row basis.
withTotal, _ := golars.Lazy(df).
    SumHorizontal("total", "q1", "q2", "q3").
    Collect(ctx)
defer withTotal.Release()

// Or compute the reduction directly as a standalone Series.
total, _ := golars.SumHorizontal(ctx, df, "q1", "q2", "q3")
defer total.Release()

Variants: SumHorizontal, MeanHorizontal, MinHorizontal, MaxHorizontal, AllHorizontal, AnyHorizontal. Omit the column list to span every numeric (or boolean) column. Null handling defaults to IgnoreNulls; pass dataframe.PropagateNulls on the frame-level method for polars' strict semantics.

One-row frame-level aggregates

sums, _ := df.SumAll(ctx)     // one row, one column per numeric input
means, _ := df.MeanAll(ctx)
counts, _ := df.CountAll(ctx) // counts non-nulls for every column
nulls, _ := df.NullCountAll(ctx)

These mirror polars' df.sum(), df.mean(), df.count(). They are convenient for dashboards, describe-style summaries, and streamed ETL checkpoints.

Lazy scans (pushdown-friendly I/O)

lf := golars.ScanCSV("huge.csv").
    Filter(golars.Col("region").EqLit("us")).
    Select(golars.Col("symbol"), golars.Col("price"))

out, _ := lf.Collect(ctx)

Every format has a scan entry point: ScanCSV, ScanParquet, ScanIPC, ScanJSON, ScanNDJSON. Compared to Read*, a scan defers opening the file until Collect so the optimiser can push projections + filters into the reader.

Rank and percent-change

r, _ := golars.Lazy(df).
    Select(
        golars.Col("score").Rank("dense").Alias("rank"),
        golars.Col("score").PctChange(1).Alias("delta"),
    ).
    Collect(ctx)

Apply a custom Go function

out, _ := df.Apply(func(s *series.Series) (*series.Series, error) {
    switch s.DType().String() {
    case "i64":
        return s.ApplyInt64(func(v int64) int64 { return v * 2 })
    case "str":
        return s.Str().Upper()
    }
    return s.Clone(), nil
})

REPL / scripting quickies

Inside golars or in a .glr file:

load data/trades.csv
filter volume > 100
with_row_index row
cast price f64
fill_null 0
rename volume as qty
sum qty
write out.parquet

Scalar-only prints: .sum COL, .mean COL, .min COL, etc. write one-line results instead of a table, convenient for quick spot checks.

Per-language equivalents

polars (Python)golars (Go)
pl.read_csv(p)golars.ReadCSV(p)
df.filter(pl.col("x") > 5)df.Filter(ctx, mask) or lazy with golars.Col("x").GtLit(5)
df.group_by("k").agg(pl.sum("v"))df.GroupBy("k").Agg(ctx, []expr.Expr{expr.Col("v").Sum()})
df.unique()df.Unique(ctx)
df.sample(n=10)df.Sample(ctx, 10, false, seed)
df.with_row_index()df.WithRowIndex("index", 0)
pl.col("s").str.to_uppercase()s.Str().Upper()
df.select(cs.numeric())df.SelectBy(selector.Numeric())
pl.sum_horizontal("a", "b")golars.SumHorizontal(ctx, df, "a", "b")
df.fill_nan(0)lf.FillNan(0)
df.fill_null(strategy="forward")lf.ForwardFill(0)
df.fill_null(strategy="backward")lf.BackwardFill(0)
df.top_k(10, by="x")df.TopK(ctx, 10, "x")
df.transpose()df.Transpose(ctx, "column", "row")
df.unpivot(index=["id"])df.Unpivot(ctx, []string{"id"}, nil)
df.partition_by("k")df.PartitionBy(ctx, "k")
df.corr()df.Corr(ctx)
pl.coalesce(...)golars.Coalesce(...)
pl.concat_str(..., sep)golars.ConcatStr(sep, ...)
pl.int_range(0, n)golars.IntRange(0, int64(n), 1)
pl.when(p).then(a).otherwise(b)golars.When(p).Then(a).Otherwise(b)
pl.col("x").rolling_sum(w)golars.Col("x").RollingSum(w, 0)
pl.col("x").sum().over("k")golars.Col("x").Sum().Over("k")
s.str.extract(pattern, i)s.Str().Extract(pattern, i)
s.str.contains(p) (regex)s.Str().ContainsRegex(p)
df.pivot(index=, on=, values=)df.Pivot(ctx, index, on, values, agg)
df.sum()df.SumAll(ctx)
pl.scan_csv(p)golars.ScanCSV(p)
pl.scan_parquet(p)golars.ScanParquet(p)
s.str.to_datetime(fmt)golars.Col("s").Str().ToDatetime(fmt)
pl.col("ts").dt.truncate("1h")golars.Col("ts").Dt().Truncate("1h")
df.group_by_dynamic("ts", every="1h")lf.GroupByDynamic("ts", golars.DynamicGroupOptions{Every: "1h"})
pl.col("x").rolling_mean_by("ts", "2h")golars.Col("x").RollingMeanBy(golars.Col("ts"), "2h")
df.join_asof(q, on="t", by="k")df.JoinAsof(ctx, q, golars.AsofOptions{On: "t", By: []string{"k"}})
pl.col("l").list.eval(pl.element() * 2)golars.Col("l").List().Eval(golars.Element().Mul(golars.Lit(int64(2))))
pl.struct("a", "b")golars.Struct(golars.Col("a"), golars.Col("b"))
pl.col("x").name.suffix("_raw")golars.Col("x").Name().Suffix("_raw")
pl.col("x").cut([0, 10])golars.Col("x").Cut([]float64{0, 10}, expr.CutOptions{})
pl.col("x").map_batches(f)golars.Col("x").MapBatches(f)

See docs/api-surface.md for the full cross-reference.

On this page