Documentation
¶
Overview ¶
Package examples is the documentation site's code. Each Example function in it is a code block on a page, and `go test` holds it to its output, so a page cannot show code that does not run or an answer it does not give (context_files/docs-site-scope.md §2).
Example (AggByExpression) ¶
df, err := sales().
GroupBy(ursus.Col("qty").Ge(8).Alias("bulk")).
Agg(ursus.Len().Alias("orders"), ursus.Col("qty").Sum().Alias("qty")).
Sort(ursus.Asc(ursus.Col("bulk"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (2, 3) ┌───────┬────────┬────────┐ │ bulk │ orders │ qty │ │ Bool │ Uint64 │ Int128 │ ├───────┼────────┼────────┤ │ false │ 5 │ 22 │ │ true │ 3 │ 31 │ └───────┴────────┴────────┘
Example (AggConditional) ¶
df, err := sales().
GroupBy(ursus.Col("region")).
Agg(
ursus.Col("qty").Filter(ursus.Col("product").Eq("apple")).Sum().
Alias("apple_qty"),
ursus.Col("qty").Ge(8).Sum().Alias("bulk_orders"),
ursus.Col("product").MaxBy(ursus.Col("qty")).Alias("biggest"),
).
Sort(ursus.Asc(ursus.Col("region"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 4) ┌─────────┬───────────┬─────────────┬─────────┐ │ region │ apple_qty │ bulk_orders │ biggest │ │ String │ Int128 │ Int128 │ String │ ├─────────┼───────────┼─────────────┼─────────┤ │ "east" │ 12 │ 1 │ "apple" │ │ "north" │ 10 │ 1 │ "apple" │ │ "south" │ 4 │ 1 │ "fig" │ └─────────┴───────────┴─────────────┴─────────┘
Example (AggCounting) ¶
df, err := sales().
GroupBy(ursus.Col("product")).
Agg(
ursus.Len().Alias("orders"),
ursus.Col("region").NUnique().Alias("regions"),
ursus.Col("region").First().Alias("first"),
ursus.Col("region").Last().Alias("last"),
).
Sort(ursus.Asc(ursus.Col("product"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 5) ┌─────────┬────────┬─────────┬─────────┬─────────┐ │ product │ orders │ regions │ first │ last │ │ String │ Uint64 │ Uint64 │ String │ String │ ├─────────┼────────┼─────────┼─────────┼─────────┤ │ "apple" │ 3 │ 3 │ "north" │ "east" │ │ "fig" │ 2 │ 2 │ "south" │ "north" │ │ "pear" │ 3 │ 3 │ "north" │ "south" │ └─────────┴────────┴─────────┴─────────┴─────────┘
Example (AggDescribe) ¶
df, err := sales().
Select(ursus.Col("qty"), ursus.Col("price")).
Describe(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (9, 3) ┌──────────────┬───────────────────┬────────────────────┐ │ statistic │ qty │ price │ │ String │ Float64 │ Float64 │ ├──────────────┼───────────────────┼────────────────────┤ │ "count" │ 8 │ 8 │ │ "null_count" │ 0 │ 0 │ │ "mean" │ 6.625 │ 2.15625 │ │ "std" │ 3.543101950067402 │ 0.6258922202972101 │ │ "min" │ 2 │ 1.5 │ │ "25%" │ 4 │ 1.5 │ │ "50%" │ 7 │ 2.25 │ │ "75%" │ 9 │ 2.25 │ │ "max" │ 12 │ 3 │ └──────────────┴───────────────────┴────────────────────┘
Example (AggFirstNonNull) ¶
temps, read := []float64{0, 21.5, 22.0, 0}, []bool{false, true, true, false}
readings := ursus.Frame(
ursus.Values("sensor", []string{"a", "a", "a", "b"}),
ursus.ValuesNullable("temp", temps, read),
)
g := readings.GroupBy(ursus.Col("sensor")).MaintainOrder()
show(g.Agg(
ursus.Col("temp").First().Alias("first"),
ursus.Col("temp").FirstNonNull().Alias("first_seen"),
ursus.Col("temp").LastNonNull().Alias("last_seen"),
))
show(g.All())
Output: shape: (2, 4) ┌────────┬─────────┬────────────┬───────────┐ │ sensor │ first │ first_seen │ last_seen │ │ String │ Float64 │ Float64 │ Float64 │ ├────────┼─────────┼────────────┼───────────┤ │ "a" │ null │ 21.5 │ 22 │ │ "b" │ null │ null │ null │ └────────┴─────────┴────────────┴───────────┘ shape: (2, 2) ┌────────┬──────────────────┐ │ sensor │ temp │ │ String │ List(Float64) │ ├────────┼──────────────────┤ │ "a" │ [null, 21.5, 22] │ │ "b" │ [null] │ └────────┴──────────────────┘
Example (AggFrame) ¶
lines := sales().Select(ursus.Col("region"), ursus.Col("qty"), ursus.Col("price"))
show(lines.Mean())
show(lines.Max())
Output: shape: (1, 3) ┌────────┬─────────┬─────────┐ │ region │ qty │ price │ │ String │ Float64 │ Float64 │ ├────────┼─────────┼─────────┤ │ null │ 6.625 │ 2.15625 │ └────────┴─────────┴─────────┘ shape: (1, 3) ┌─────────┬───────┬─────────┐ │ region │ qty │ price │ │ String │ Int64 │ Float64 │ ├─────────┼───────┼─────────┤ │ "south" │ 12 │ 3 │ └─────────┴───────┴─────────┘
Example (AggHaving) ¶
show(sales().
GroupBy(ursus.Col("region")).
MaintainOrder().
Having(ursus.Len().Gt(2)).
Agg(ursus.Col("qty").Sum().Alias("qty")))
Output: shape: (2, 2) ┌─────────┬────────┐ │ region │ qty │ │ String │ Int128 │ ├─────────┼────────┤ │ "north" │ 20 │ │ "south" │ 19 │ └─────────┴────────┘
Example (AggHeadTail) ¶
show(sales().
Select(ursus.Col("region"), ursus.Col("product"), ursus.Col("qty")).
GroupBy(ursus.Col("region")).
Tail(1))
Output: shape: (3, 3) ┌─────────┬─────────┬───────┐ │ region │ product │ qty │ │ String │ String │ Int64 │ ├─────────┼─────────┼───────┤ │ "north" │ "fig" │ 3 │ │ "south" │ "pear" │ 6 │ │ "east" │ "apple" │ 12 │ └─────────┴─────────┴───────┘
Example (AggLists) ¶
df, err := sales().
GroupBy(ursus.Col("region")).
Agg(
ursus.Col("order_id").Implode().Alias("orders"),
ursus.Col("product").Unique().Sort().Alias("products"),
).
Sort(ursus.Asc(ursus.Col("region"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 3) ┌─────────┬─────────────┬──────────────────────────┐ │ region │ orders │ products │ │ String │ List(Int64) │ List(String) │ ├─────────┼─────────────┼──────────────────────────┤ │ "east" │ [4, 6] │ ["apple", "pear"] │ │ "north" │ [1, 3, 7] │ ["apple", "fig", "pear"] │ │ "south" │ [2, 5, 8] │ ["apple", "fig", "pear"] │ └─────────┴─────────────┴──────────────────────────┘
Example (AggMaintainOrder) ¶
df, err := sales().
GroupBy(ursus.Col("product")).
MaintainOrder().
Agg(ursus.Col("qty").Sum().Alias("qty")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 2) ┌─────────┬────────┐ │ product │ qty │ │ String │ Int128 │ ├─────────┼────────┤ │ "apple" │ 26 │ │ "pear" │ 15 │ │ "fig" │ 12 │ └─────────┴────────┘
Example (AggSeveralKeys) ¶
df, err := sales().
GroupBy(ursus.Col("region"), ursus.Col("product")).
Agg(ursus.Col("qty").Sum().Alias("qty")).
Sort(ursus.Asc(ursus.Col("region")), ursus.Asc(ursus.Col("product"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (8, 3) ┌─────────┬─────────┬────────┐ │ region │ product │ qty │ │ String │ String │ Int128 │ ├─────────┼─────────┼────────┤ │ "east" │ "apple" │ 12 │ │ "east" │ "pear" │ 2 │ │ "north" │ "apple" │ 10 │ │ "north" │ "fig" │ 3 │ │ "north" │ "pear" │ 7 │ │ "south" │ "apple" │ 4 │ │ "south" │ "fig" │ 9 │ │ "south" │ "pear" │ 6 │ └─────────┴─────────┴────────┘
Example (AggShortcut) ¶
df, err := sales().
Select(ursus.Col("region"), ursus.Col("qty"), ursus.Col("price")).
GroupBy(ursus.Col("region")).
Max().
Sort(ursus.Asc(ursus.Col("region"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 3) ┌─────────┬───────┬─────────┐ │ region │ qty │ price │ │ String │ Int64 │ Float64 │ ├─────────┼───────┼─────────┤ │ "east" │ 12 │ 2.25 │ │ "north" │ 10 │ 3 │ │ "south" │ 9 │ 3 │ └─────────┴───────┴─────────┘
Example (AggStatistics) ¶
df, err := sales().
GroupBy(ursus.Col("region")).
Agg(
ursus.Col("qty").Sum().Alias("sum"),
ursus.Col("qty").Mean().Alias("mean"),
ursus.Col("qty").Median().Alias("median"),
ursus.Col("qty").Min().Alias("min"),
ursus.Col("qty").Max().Alias("max"),
ursus.Col("qty").Std(1).Round(2).Alias("std"),
).
Sort(ursus.Asc(ursus.Col("region"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 7) ┌─────────┬────────┬───────────────────┬─────────┬───────┬───────┬─────────┐ │ region │ sum │ mean │ median │ min │ max │ std │ │ String │ Int128 │ Float64 │ Float64 │ Int64 │ Int64 │ Float64 │ ├─────────┼────────┼───────────────────┼─────────┼───────┼───────┼─────────┤ │ "east" │ 14 │ 7 │ 7 │ 2 │ 12 │ 7.07 │ │ "north" │ 20 │ 6.666666666666667 │ 7 │ 3 │ 10 │ 3.51 │ │ "south" │ 19 │ 6.333333333333333 │ 6 │ 4 │ 9 │ 2.52 │ └─────────┴────────┴───────────────────┴─────────┴───────┴───────┴─────────┘
Example (AggValueCounts) ¶
df, err := sales().ValueCounts(ursus.Col("product")).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 2) ┌─────────┬────────┐ │ product │ count │ │ String │ Uint64 │ ├─────────┼────────┤ │ "apple" │ 3 │ │ "pear" │ 3 │ │ "fig" │ 2 │ └─────────┴────────┘
Example (AggWholeFrame) ¶
df, err := sales().
Select(
ursus.Len().Alias("orders"),
ursus.Col("qty").Sum().Alias("qty"),
ursus.Col("qty").Mul(ursus.Col("price")).Sum().Alias("revenue"),
ursus.Col("date").Max().Alias("last_day"),
).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (1, 4) ┌────────┬────────┬─────────┬────────────┐ │ orders │ qty │ revenue │ last_day │ │ Uint64 │ Int128 │ Float64 │ Date │ ├────────┼────────┼─────────┼────────────┤ │ 8 │ 53 │ 108.75 │ 2026-01-07 │ └────────┴────────┴─────────┴────────────┘
Example (Arrays) ¶
points := ursus.FromRows([]point{
{"a", [3]float64{1, 2, 2}},
{"b", [3]float64{0, 3, 4}},
})
show(points.WithColumns(
ursus.Col("XYZ").Arr().ToList().List().Sum().Alias("sum"),
ursus.Col("XYZ").Arr().ToList().List().Head(2).List().ToArray(2).Alias("xy"),
))
Output: shape: (2, 4) ┌────────┬───────────────────┬─────────┬───────────────────┐ │ Name │ XYZ │ sum │ xy │ │ String │ Array(Float64, 3) │ Float64 │ Array(Float64, 2) │ ├────────┼───────────────────┼─────────┼───────────────────┤ │ "a" │ [1, 2, 2] │ 5 │ [1, 2] │ │ "b" │ [0, 3, 4] │ 7 │ [0, 3] │ └────────┴───────────────────┴─────────┴───────────────────┘
Example (Eager) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
ctx := context.Background()
df, err := sales().Collect(ctx)
if err != nil {
log.Fatal(err)
}
big, err := df.Filter(ctx, ursus.Col("qty").Ge(int64(9)))
if err != nil {
log.Fatal(err)
}
fmt.Println(big.Shape())
}
Output: 3 6
Example (ExprContexts) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
ctx := context.Background()
revenue := ursus.Col("qty").Mul(ursus.Col("price"))
perRow, err := sales().
Select(ursus.Col("order_id"), revenue.Alias("revenue")).
Head(3).
Collect(ctx)
if err != nil {
log.Fatal(err)
}
total, err := sales().Select(revenue.Sum().Alias("revenue")).Collect(ctx)
if err != nil {
log.Fatal(err)
}
byRegion, err := sales().GroupBy(ursus.Col("region")).
Agg(revenue.Sum().Alias("revenue")).
Sort(ursus.Asc(ursus.Col("region"))).Collect(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(perRow)
fmt.Println(total)
fmt.Println(byRegion)
}
Output: shape: (3, 2) ┌──────────┬─────────┐ │ order_id │ revenue │ │ Int64 │ Float64 │ ├──────────┼─────────┤ │ 1 │ 15 │ │ 2 │ 6 │ │ 3 │ 15.75 │ └──────────┴─────────┘ shape: (1, 1) ┌─────────┐ │ revenue │ │ Float64 │ ├─────────┤ │ 108.75 │ └─────────┘ shape: (3, 2) ┌─────────┬─────────┐ │ region │ revenue │ │ String │ Float64 │ ├─────────┼─────────┤ │ "east" │ 22.5 │ │ "north" │ 39.75 │ │ "south" │ 46.5 │ └─────────┴─────────┘
Example (ExprHorizontal) ¶
scores := ursus.Frame(
ursus.Values("name", []string{"ada", "ben"}),
ursus.Values("maths", []int64{90, 60}),
ursus.Values("art", []int64{70, 85}),
ursus.Values("music", []int64{80, 75}),
)
show(scores.Select(
ursus.Col("name"),
ursus.SumHorizontal(ursus.ColDType(ursus.Int64)).Alias("total"),
ursus.MaxHorizontal(ursus.ColDType(ursus.Int64)).Alias("best"),
))
Output: shape: (2, 3) ┌────────┬────────┬───────┐ │ name │ total │ best │ │ String │ Int128 │ Int64 │ ├────────┼────────┼───────┤ │ "ada" │ 240 │ 90 │ │ "ben" │ 220 │ 85 │ └────────┴────────┴───────┘
Example (ExprMany) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
df, err := sales().
Select(
ursus.Col("product"),
ursus.Col("qty", "price").Mul(int64(2)).Suffix("_x2"),
).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 3) ┌─────────┬────────┬──────────┐ │ product │ qty_x2 │ price_x2 │ │ String │ Int64 │ Float64 │ ├─────────┼────────┼──────────┤ │ "apple" │ 20 │ 3 │ │ "apple" │ 8 │ 3 │ │ "pear" │ 14 │ 4.5 │ └─────────┴────────┴──────────┘
Example (ExprNamespaces) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
df, err := sales().
Select(
ursus.Col("product").Str().ToUpper().Alias("product"),
ursus.Col("date").Dt().Weekday().Alias("weekday"),
ursus.Col("product").Str().Contains("p", true).Alias("has_p"),
).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 3) ┌─────────┬─────────┬───────┐ │ product │ weekday │ has_p │ │ String │ Int32 │ Bool │ ├─────────┼─────────┼───────┤ │ "APPLE" │ 6 │ true │ │ "APPLE" │ 6 │ true │ │ "PEAR" │ 7 │ true │ └─────────┴─────────┴───────┘
Example (ExprOver) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
df, err := sales().
Select(
ursus.Col("order_id"),
ursus.Col("region"),
ursus.Col("qty"),
ursus.Col("qty").Sum().Over(ursus.Col("region")).Alias("region_qty"),
ursus.Col("qty").Rank(ursus.RankDense, true).
Over(ursus.Col("region")).Alias("rank"),
).
Sort(ursus.Asc(ursus.Col("region")), ursus.Asc(ursus.Col("rank"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (8, 5) ┌──────────┬─────────┬───────┬────────────┬────────┐ │ order_id │ region │ qty │ region_qty │ rank │ │ Int64 │ String │ Int64 │ Int128 │ Uint32 │ ├──────────┼─────────┼───────┼────────────┼────────┤ │ 6 │ "east" │ 12 │ 14 │ 1 │ │ 4 │ "east" │ 2 │ 14 │ 2 │ │ 1 │ "north" │ 10 │ 20 │ 1 │ │ 3 │ "north" │ 7 │ 20 │ 2 │ │ 7 │ "north" │ 3 │ 20 │ 3 │ │ 5 │ "south" │ 9 │ 19 │ 1 │ │ 8 │ "south" │ 6 │ 19 │ 2 │ │ 2 │ "south" │ 4 │ 19 │ 3 │ └──────────┴─────────┴───────┴────────────┴────────┘
Example (FilterAggregate) ¶
df, err := sales().
Filter(ursus.Col("qty").Gt(ursus.Col("qty").Mean())).
Select(ursus.Col("order_id"), ursus.Col("qty")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (4, 2) ┌──────────┬───────┐ │ order_id │ qty │ │ Int64 │ Int64 │ ├──────────┼───────┤ │ 1 │ 10 │ │ 3 │ 7 │ │ 5 │ 9 │ │ 6 │ 12 │ └──────────┴───────┘
Example (FilterNulls) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
scores := ursus.Frame(
ursus.Values("name", []string{"ana", "ben", "cai", "dee"}),
ursus.ValuesNullable("score",
[]int64{90, 40, 0, 75},
[]bool{true, true, false, true}),
)
kept, err := scores.Filter(ursus.Col("score").Ge(50)).Collect(ctx)
if err != nil {
log.Fatal(err)
}
removed, err := scores.Remove(ursus.Col("score").Ge(50)).Collect(ctx)
if err != nil {
log.Fatal(err)
}
missing, err := scores.Filter(ursus.Col("score").IsNull()).Collect(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(kept)
fmt.Println(removed)
fmt.Println(missing)
}
Output: shape: (2, 2) ┌────────┬───────┐ │ name │ score │ │ String │ Int64 │ ├────────┼───────┤ │ "ana" │ 90 │ │ "dee" │ 75 │ └────────┴───────┘ shape: (1, 2) ┌────────┬───────┐ │ name │ score │ │ String │ Int64 │ ├────────┼───────┤ │ "ben" │ 40 │ └────────┴───────┘ shape: (1, 2) ┌────────┬───────┐ │ name │ score │ │ String │ Int64 │ ├────────┼───────┤ │ "cai" │ null │ └────────┴───────┘
Example (FilterOr) ¶
df, err := sales().
Filter(ursus.Col("region").Eq("east").Or(ursus.Col("price").Ge(3.0))).
Select(ursus.Col("order_id"), ursus.Col("region"), ursus.Col("price")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (4, 3) ┌──────────┬─────────┬─────────┐ │ order_id │ region │ price │ │ Int64 │ String │ Float64 │ ├──────────┼─────────┼─────────┤ │ 4 │ "east" │ 2.25 │ │ 5 │ "south" │ 3 │ │ 6 │ "east" │ 1.5 │ │ 7 │ "north" │ 3 │ └──────────┴─────────┴─────────┘
Example (FilterPredicates) ¶
df, err := sales().
Filter(
ursus.Col("product").IsIn("apple", "fig"),
ursus.Col("qty").IsBetween(4, 10),
).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 6) ┌──────────┬────────────┬─────────┬─────────┬───────┬─────────┐ │ order_id │ date │ region │ product │ qty │ price │ │ Int64 │ Date │ String │ String │ Int64 │ Float64 │ ├──────────┼────────────┼─────────┼─────────┼───────┼─────────┤ │ 1 │ 2026-01-03 │ "north" │ "apple" │ 10 │ 1.5 │ │ 2 │ 2026-01-03 │ "south" │ "apple" │ 4 │ 1.5 │ │ 5 │ 2026-01-05 │ "south" │ "fig" │ 9 │ 3 │ └──────────┴────────────┴─────────┴─────────┴───────┴─────────┘
Example (GoBatches) ¶
type sale struct {
ID int64 `ursus:"order_id"`
Qty int64
}
ctx := context.Background()
total := int64(0)
for batch, err := range sales().CollectBatches(ctx, ursus.WithBatchSize(3)) {
if err != nil {
log.Fatal(err)
}
rows, err := batch.Rows[sale]()
if err != nil {
log.Fatal(err)
}
for _, r := range rows {
total += r.Qty
}
fmt.Println("batch of", len(rows), "- running total", total)
}
Output: batch of 3 - running total 21 batch of 3 - running total 44 batch of 2 - running total 53
Example (GoColumn) ¶
df, err := sales().Collect(context.Background())
if err != nil {
log.Fatal(err)
}
qty, err := df.Column[int64]("qty")
if err != nil {
log.Fatal(err)
}
fmt.Println(qty.Name(), qty.Len(), qty.NullCount())
fmt.Println(qty.Values())
total := qty.Fold(int64(0), func(acc, v int64) int64 { return acc + v })
fmt.Println("total:", total)
kinds := qty.Map[string](func(v int64) string {
if v >= 8 {
return "bulk"
}
return "single"
})
fmt.Println(kinds)
Output: qty 8 0 [10 4 7 2 9 12 3 6] total: 53 [bulk single single single bulk bulk single single]
Example (GoFromRows) ¶
type order struct {
ID int64 `ursus:"id"`
Placed time.Time `ursus:"placed"`
Total float64 `ursus:"total"`
Note *string `ursus:"note"` // nil: no note
}
note := "gift wrap"
show(ursus.FromRows([]order{
{1, time.Date(2026, 1, 3, 9, 0, 0, 0, time.UTC), 15, nil},
{2, time.Date(2026, 1, 4, 14, 30, 0, 0, time.UTC), 27, ¬e},
}))
Output: shape: (2, 4) ┌───────┬────────────────────────────────┬─────────┬─────────────┐ │ id │ placed │ total │ note │ │ Int64 │ Datetime(ns, UTC) │ Float64 │ String │ ├───────┼────────────────────────────────┼─────────┼─────────────┤ │ 1 │ 2026-01-03T09:00:00.000000000Z │ 15 │ null │ │ 2 │ 2026-01-04T14:30:00.000000000Z │ 27 │ "gift wrap" │ └───────┴────────────────────────────────┴─────────┴─────────────┘
Example (GoIn) ¶
type order struct {
ID int64
Placed time.Time
Total float64
Note *string // nil: no note
}
note := "gift wrap"
in := []order{
{1, time.Date(2026, 1, 3, 9, 0, 0, 0, time.UTC), 15, nil},
{2, time.Date(2026, 1, 4, 14, 30, 0, 0, time.UTC), 27, ¬e},
}
ids, totals := make([]int64, len(in)), make([]float64, len(in))
placed := make([]time.Time, len(in))
notes, hasNote := make([]string, len(in)), make([]bool, len(in))
for i, o := range in {
ids[i], placed[i], totals[i] = o.ID, o.Placed, o.Total
if o.Note != nil {
notes[i], hasNote[i] = *o.Note, true
}
}
show(ursus.Frame(
ursus.Values("id", ids),
ursus.Values("placed", placed),
ursus.Values("total", totals),
ursus.ValuesNullable("note", notes, hasNote),
))
Output: shape: (2, 4) ┌───────┬────────────────────────────────┬─────────┬─────────────┐ │ id │ placed │ total │ note │ │ Int64 │ Datetime(ns, UTC) │ Float64 │ String │ ├───────┼────────────────────────────────┼─────────┼─────────────┤ │ 1 │ 2026-01-03T09:00:00.000000000Z │ 15 │ null │ │ 2 │ 2026-01-04T14:30:00.000000000Z │ 27 │ "gift wrap" │ └───────┴────────────────────────────────┴─────────┴─────────────┘
Example (GoNulls) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.ValuesNullable("score", []int64{90, 0, 75}, []bool{true, false, true}),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
score, err := df.Column[int64]("score")
if err != nil {
log.Fatal(err)
}
for v, present := range score.All() {
fmt.Println(v, present)
}
v, ok := score.Get(1)
fmt.Println("row 1:", v, ok)
}
Output: 90 true 0 false 75 true row 1: 0 false
Example (GoRows) ¶
type sale struct {
ID int64 `ursus:"order_id"`
Day time.Time `ursus:"date"`
Product string
Qty int64
Revenue float64 `ursus:"-"` // filled by the program, not read
}
df, err := sales().
Filter(ursus.Col("region").Eq("east")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
rows, err := df.Rows[sale]()
if err != nil {
log.Fatal(err)
}
for _, r := range rows {
fmt.Println(r.ID, r.Day.Format("Jan 2"), r.Product, r.Qty)
}
Output: 4 Jan 5 pear 2 6 Jan 6 apple 12
Example (GoRowsNulls) ¶
type reading struct {
Hour int64
Temp *float64 // nil where the reading is null
}
df, err := readings().Head(3).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
rows, err := df.Rows[reading]()
if err != nil {
log.Fatal(err)
}
for _, r := range rows {
if r.Temp == nil {
fmt.Println(r.Hour, "no reading")
continue
}
fmt.Println(r.Hour, *r.Temp)
}
Output: 0 10 1 no reading 2 no reading
Example (Home) ¶
The home page's query: a CSV scanned, filtered, grouped and sorted.
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.ScanCSV("testdata/sales.csv").
Filter(ursus.Col("qty").Gt(int64(3))).
GroupBy(ursus.Col("region")).
Agg(
ursus.Col("qty").Mul(ursus.Col("price")).Sum().Alias("revenue"),
ursus.Len().Alias("orders"),
).
Sort(ursus.Desc(ursus.Col("revenue"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 3) ┌─────────┬─────────┬────────┐ │ region │ revenue │ orders │ │ String │ Float64 │ Uint64 │ ├─────────┼─────────┼────────┤ │ "south" │ 46.5 │ 3 │ │ "north" │ 30.75 │ 2 │ │ "east" │ 18 │ 1 │ └─────────┴─────────┴────────┘
Example (Install) ¶
The installation page's first program, shown whole.
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.Values("name", []string{"ursus", "polars", "pandas"}),
ursus.Values("language", []string{"Go", "Rust", "Python"}),
).Filter(ursus.Col("language").Eq("Go")).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (1, 2) ┌─────────┬──────────┐ │ name │ language │ │ String │ String │ ├─────────┼──────────┤ │ "ursus" │ "Go" │ └─────────┴──────────┘
Example (IoArrow) ¶
ctx := context.Background()
df, err := sales().
Select(ursus.Col("order_id"), ursus.Col("qty")).
Head(3).
Collect(ctx)
if err != nil {
log.Fatal(err)
}
rec, err := df.Record() // the frame's memory, shared with arrow-go
if err != nil {
log.Fatal(err)
}
fmt.Println(rec.NumRows(), "rows,", rec.Schema().Field(1).Type)
back := ursus.ScanArrowRecords(rec) // copies, so rec can be released
rec.Release()
show(back.WithColumns(ursus.Col("qty").Mul(2).Alias("double")))
Output: 3 rows, int64 shape: (3, 3) ┌──────────┬───────┬────────┐ │ order_id │ qty │ double │ │ Int64 │ Int64 │ Int64 │ ├──────────┼───────┼────────┤ │ 1 │ 10 │ 20 │ │ 2 │ 4 │ 8 │ │ 3 │ 7 │ 14 │ └──────────┴───────┴────────┘
Example (IoCSVGlob) ¶
show(ursus.ScanCSVGlob("testdata/parts/revenue-*.csv").
GroupBy(ursus.Col("month")).
Agg(ursus.Col("revenue").Sum().Alias("revenue")).
Sort(ursus.Asc(ursus.Col("month"))))
Output: shape: (2, 2) ┌───────────┬─────────┐ │ month │ revenue │ │ String │ Float64 │ ├───────────┼─────────┤ │ "2026-01" │ 86.25 │ │ "2026-02" │ 79.25 │ └───────────┴─────────┘
Example (IoCSVOptions) ¶
data := []byte("id;name;score\n1;Ada;90\n2;Ben;NA\n3;Cai;75\n")
show(ursus.ScanCSVReader(data, "scores.csv",
ursus.WithSeparator(';'),
ursus.WithNullValues("NA"),
ursus.WithSchemaOverrides(map[string]ursus.DataType{"score": ursus.Float64}),
))
Output: shape: (3, 3) ┌───────┬────────┬─────────┐ │ id │ name │ score │ │ Int64 │ String │ Float64 │ ├───────┼────────┼─────────┤ │ 1 │ "Ada" │ 90 │ │ 2 │ "Ben" │ null │ │ 3 │ "Cai" │ 75 │ └───────┴────────┴─────────┘
Example (IoCSVWrite) ¶
var out bytes.Buffer
err := readings().Head(3).
WriteCSV(context.Background(), &out, ursus.WithNullValue("NA"))
if err != nil {
log.Fatal(err)
}
fmt.Print(out.String())
Output: hour,temp,backup 0,10.0,9.0 1,NA,11.0 2,NA,NA
Example (IoParquet) ¶
ctx := context.Background()
var file bytes.Buffer
if err := sales().WriteParquet(ctx, &file, ursus.WithRowGroupRows(4)); err != nil {
log.Fatal(err)
}
q := ursus.ScanParquetBytes(file.Bytes(), "sales.parquet").
Filter(ursus.Col("order_id").Gt(6)).
Select(ursus.Col("order_id"), ursus.Col("product"))
plan, err := q.Explain(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(plan)
show(q)
Output: FILTER [(col("order_id") > lit(6))] PARQUET SCAN sales.parquet projection: [order_id, product] (2/6 cols) predicate: [(col("order_id") > lit(6))] shape: (2, 2) ┌──────────┬─────────┐ │ order_id │ product │ │ Int64 │ String │ ├──────────┼─────────┤ │ 7 │ "fig" │ │ 8 │ "pear" │ └──────────┴─────────┘
Example (IoParquetFrom) ¶
ctx := context.Background()
var file bytes.Buffer
if err := sales().WriteParquet(ctx, &file); err != nil {
log.Fatal(err)
}
stored := file.Bytes() // standing in for an object in a bucket
lf := ursus.ScanParquetFrom([]ursus.ParquetFile{{
Name: "s3://shop/sales.parquet",
Open: func(ctx context.Context) (io.ReaderAt, int64, error) {
return bytes.NewReader(stored), int64(len(stored)), nil
},
}})
n, err := lf.Filter(ursus.Col("region").Eq("south")).Count(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(n, "orders from the south")
Output: 3 orders from the south
Example (JoinAnti) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(customers().Join(orders(), on, ursus.JoinHow(ursus.JoinAnti)))
}
Output: shape: (1, 2) ┌─────────────┬────────┐ │ customer_id │ name │ │ Int64 │ String │ ├─────────────┼────────┤ │ 2 │ "Ben" │ └─────────────┴────────┘
Example (JoinAsOf) ¶
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/advenn/ursus"
)
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
at := func(s int) time.Time { return time.Date(2026, 1, 5, 9, 0, s, 0, time.UTC) }
trades := ursus.Frame(
ursus.Values("time", []time.Time{at(1), at(5), at(9)}),
ursus.Values("ticker", []string{"ACME", "BOLT", "ACME"}),
ursus.Values("qty", []int64{100, 50, 70}),
)
quotes := ursus.Frame(
ursus.Values("time", []time.Time{at(0), at(2), at(4), at(6)}),
ursus.Values("ticker", []string{"ACME", "BOLT", "ACME", "BOLT"}),
ursus.Values("bid", []float64{10.0, 20.0, 10.1, 20.2}),
)
show(trades.JoinAsOf(quotes,
ursus.AsOfOn(ursus.Col("time")),
ursus.AsOfBy(ursus.Col("ticker")),
ursus.AsOfTolerance(ursus.Every("3s")),
))
}
Output: shape: (3, 4) ┌────────────────────────────────┬────────┬───────┬─────────┐ │ time │ ticker │ qty │ bid │ │ Datetime(ns, UTC) │ String │ Int64 │ Float64 │ ├────────────────────────────────┼────────┼───────┼─────────┤ │ 2026-01-05T09:00:01.000000000Z │ "ACME" │ 100 │ 10 │ │ 2026-01-05T09:00:05.000000000Z │ "BOLT" │ 50 │ 20 │ │ 2026-01-05T09:00:09.000000000Z │ "ACME" │ 70 │ null │ └────────────────────────────────┴────────┴───────┴─────────┘
Example (JoinCoalesce) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(orders().Join(customers(), on,
ursus.JoinHow(ursus.JoinFull),
ursus.JoinCoalesce(true)))
}
Output: shape: (6, 4) ┌───────┬─────────────┬─────────┬────────┐ │ order │ customer_id │ amount │ name │ │ Int64 │ Int64 │ Float64 │ String │ ├───────┼─────────────┼─────────┼────────┤ │ 10 │ 1 │ 25 │ "Ada" │ │ 11 │ 3 │ 40 │ "Cai" │ │ 12 │ 1 │ 10 │ "Ada" │ │ 13 │ 5 │ 99 │ null │ │ 14 │ 4 │ 15 │ "Dee" │ │ null │ 2 │ null │ "Ben" │ └───────┴─────────────┴─────────┴────────┘
Example (JoinCross) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
sizes := ursus.Frame(ursus.Values("size", []string{"S", "M"}))
colours := ursus.Frame(ursus.Values("colour", []string{"red", "blue", "green"}))
show(sizes.Join(colours, ursus.JoinHow(ursus.JoinCross)))
}
Output: shape: (6, 2) ┌────────┬─────────┐ │ size │ colour │ │ String │ String │ ├────────┼─────────┤ │ "S" │ "red" │ │ "S" │ "blue" │ │ "S" │ "green" │ │ "M" │ "red" │ │ "M" │ "blue" │ │ "M" │ "green" │ └────────┴─────────┘
Example (JoinFull) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(orders().Join(customers(), on, ursus.JoinHow(ursus.JoinFull)))
}
Output: shape: (6, 5) ┌───────┬─────────────┬─────────┬───────────────────┬────────┐ │ order │ customer_id │ amount │ customer_id_right │ name │ │ Int64 │ Int64 │ Float64 │ Int64 │ String │ ├───────┼─────────────┼─────────┼───────────────────┼────────┤ │ 10 │ 1 │ 25 │ 1 │ "Ada" │ │ 11 │ 3 │ 40 │ 3 │ "Cai" │ │ 12 │ 1 │ 10 │ 1 │ "Ada" │ │ 13 │ 5 │ 99 │ null │ null │ │ 14 │ 4 │ 15 │ 4 │ "Dee" │ │ null │ null │ null │ 2 │ "Ben" │ └───────┴─────────────┴─────────┴───────────────────┴────────┘
Example (JoinInner) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(orders().Join(customers(), on, ursus.JoinMaintainOrder(ursus.JoinOrderLeft)))
}
Output: shape: (4, 4) ┌───────┬─────────────┬─────────┬────────┐ │ order │ customer_id │ amount │ name │ │ Int64 │ Int64 │ Float64 │ String │ ├───────┼─────────────┼─────────┼────────┤ │ 10 │ 1 │ 25 │ "Ada" │ │ 11 │ 3 │ 40 │ "Cai" │ │ 12 │ 1 │ 10 │ "Ada" │ │ 14 │ 4 │ 15 │ "Dee" │ └───────┴─────────────┴─────────┴────────┘
Example (JoinKeysByName) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
people := ursus.Frame(
ursus.Values("id", []int64{1, 3}),
ursus.Values("name", []string{"Ada", "Cai"}),
)
show(orders().
Join(people,
ursus.JoinLeftOn(ursus.Col("customer_id")),
ursus.JoinRightOn(ursus.Col("id"))).
Sort(ursus.Asc(ursus.Col("order"))))
}
Output: shape: (3, 5) ┌───────┬─────────────┬─────────┬───────┬────────┐ │ order │ customer_id │ amount │ id │ name │ │ Int64 │ Int64 │ Float64 │ Int64 │ String │ ├───────┼─────────────┼─────────┼───────┼────────┤ │ 10 │ 1 │ 25 │ 1 │ "Ada" │ │ 11 │ 3 │ 40 │ 3 │ "Cai" │ │ 12 │ 1 │ 10 │ 1 │ "Ada" │ └───────┴─────────────┴─────────┴───────┴────────┘
Example (JoinLeft) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(orders().Join(customers(), on, ursus.JoinHow(ursus.JoinLeft)))
}
Output: shape: (5, 4) ┌───────┬─────────────┬─────────┬────────┐ │ order │ customer_id │ amount │ name │ │ Int64 │ Int64 │ Float64 │ String │ ├───────┼─────────────┼─────────┼────────┤ │ 10 │ 1 │ 25 │ "Ada" │ │ 11 │ 3 │ 40 │ "Cai" │ │ 12 │ 1 │ 10 │ "Ada" │ │ 13 │ 5 │ 99 │ null │ │ 14 │ 4 │ 15 │ "Dee" │ └───────┴─────────────┴─────────┴────────┘
Example (JoinNulls) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
key := ursus.ValuesNullable("k", []int64{1, 0}, []bool{true, false}) // 1 and null
left := ursus.Frame(key, ursus.Values("l", []string{"a", "b"}))
right := ursus.Frame(key, ursus.Values("r", []string{"x", "y"}))
on := ursus.JoinOn(ursus.Col("k"))
ordered := ursus.JoinMaintainOrder(ursus.JoinOrderLeft)
show(left.Join(right, on, ordered))
show(left.Join(right, on, ordered, ursus.JoinNullsEqual(true)))
}
Output: shape: (1, 3) ┌───────┬────────┬────────┐ │ k │ l │ r │ │ Int64 │ String │ String │ ├───────┼────────┼────────┤ │ 1 │ "a" │ "x" │ └───────┴────────┴────────┘ shape: (2, 3) ┌───────┬────────┬────────┐ │ k │ l │ r │ │ Int64 │ String │ String │ ├───────┼────────┼────────┤ │ 1 │ "a" │ "x" │ │ null │ "b" │ "y" │ └───────┴────────┴────────┘
Example (JoinRight) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(orders().Join(customers(), on, ursus.JoinHow(ursus.JoinRight)))
}
Output: shape: (5, 4) ┌───────┬─────────────┬─────────┬────────┐ │ order │ customer_id │ amount │ name │ │ Int64 │ Int64 │ Float64 │ String │ ├───────┼─────────────┼─────────┼────────┤ │ 10 │ 1 │ 25 │ "Ada" │ │ 11 │ 3 │ 40 │ "Cai" │ │ 12 │ 1 │ 10 │ "Ada" │ │ 14 │ 4 │ 15 │ "Dee" │ │ null │ 2 │ null │ "Ben" │ └───────┴─────────────┴─────────┴────────┘
Example (JoinSemi) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
on := ursus.JoinOn(ursus.Col("customer_id"))
show(customers().Join(orders(), on, ursus.JoinHow(ursus.JoinSemi)))
}
Output: shape: (3, 2) ┌─────────────┬────────┐ │ customer_id │ name │ │ Int64 │ String │ ├─────────────┼────────┤ │ 1 │ "Ada" │ │ 3 │ "Cai" │ │ 4 │ "Dee" │ └─────────────┴────────┘
Example (JoinSuffix) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
shipped := ursus.Frame(
ursus.Values("order", []int64{10, 11, 12}),
ursus.Values("amount", []float64{25, 38, 10}),
)
show(orders().
Join(shipped,
ursus.JoinOn(ursus.Col("order")),
ursus.JoinSuffix("_shipped"),
ursus.JoinMaintainOrder(ursus.JoinOrderLeft)).
Select(ursus.Col("order"), ursus.Col("amount"), ursus.Col("amount_shipped")))
}
Output: shape: (3, 3) ┌───────┬─────────┬────────────────┐ │ order │ amount │ amount_shipped │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼────────────────┤ │ 10 │ 25 │ 25 │ │ 11 │ 40 │ 38 │ │ 12 │ 10 │ 10 │ └───────┴─────────┴────────────────┘
Example (JoinUpdate) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
prices := ursus.Frame(
ursus.Values("sku", []string{"a", "b", "c"}),
ursus.ValuesNullable("price", []float64{9.5, 3, 0}, []bool{true, true, false}),
)
fixes := ursus.Frame(
ursus.Values("sku", []string{"c", "a"}),
ursus.Values("price", []float64{4.25, 9.75}),
)
show(prices.Update(fixes, ursus.UpdateOptions{On: []string{"sku"}}))
}
Output: shape: (3, 2) ┌────────┬─────────┐ │ sku │ price │ │ String │ Float64 │ ├────────┼─────────┤ │ "a" │ 9.75 │ │ "b" │ 3 │ │ "c" │ 4.25 │ └────────┴─────────┘
Example (JoinValidate) ¶
package main
import (
"context"
"fmt"
"github.com/advenn/ursus"
)
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
func main() {
twice := ursus.Frame(
ursus.Values("customer_id", []int64{1, 1}),
ursus.Values("name", []string{"Ada", "Ada Lovelace"}),
)
_, err := orders().
Join(twice,
ursus.JoinOn(ursus.Col("customer_id")),
ursus.JoinValidate(ursus.ValidateManyToOne)).
Collect(context.Background())
fmt.Println(err)
}
Output: ursus: join: validate=m:1 requires unique keys on the right side, but a key is duplicated first duplicate at right row 1 key: col("customer_id") each duplicate multiplies every matching row on the other side de-duplicate with .Unique(...), or pass JoinValidate(ursus.ValidateManyToMany)
Example (JoinWhere) ¶
promotions := ursus.Frame(
ursus.Values("promotion", []string{"new year", "mid week"}),
ursus.Values("from", []string{"2026-01-01", "2026-01-06"}),
ursus.Values("to", []string{"2026-01-04", "2026-01-07"}),
).WithColumns(ursus.Col("from").Str().ToDate(), ursus.Col("to").Str().ToDate())
show(sales().
Select(ursus.Col("order_id"), ursus.Col("date")).
JoinWhere(promotions,
ursus.Col("date").Ge(ursus.Col("from")),
ursus.Col("date").Le(ursus.Col("to"))).
Select(ursus.Col("order_id"), ursus.Col("date"), ursus.Col("promotion")).
Sort(ursus.Asc(ursus.Col("order_id"))))
Output: shape: (6, 3) ┌──────────┬────────────┬────────────┐ │ order_id │ date │ promotion │ │ Int64 │ Date │ String │ ├──────────┼────────────┼────────────┤ │ 1 │ 2026-01-03 │ "new year" │ │ 2 │ 2026-01-03 │ "new year" │ │ 3 │ 2026-01-04 │ "new year" │ │ 6 │ 2026-01-06 │ "mid week" │ │ 7 │ 2026-01-07 │ "mid week" │ │ 8 │ 2026-01-07 │ "mid week" │ └──────────┴────────────┴────────────┘
Example (LazyBatches) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
ctx := context.Background()
for batch, err := range sales().CollectBatches(ctx, ursus.WithBatchSize(3)) {
if err != nil {
log.Fatal(err)
}
fmt.Println("a batch of", batch.Height(), "rows")
}
}
Output: a batch of 3 rows a batch of 3 rows a batch of 2 rows
Example (LazyDeferredError) ¶
package main
import (
"context"
"fmt"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
lf := sales().
Select(ursus.Col("prodcut")). // a typo: nothing has run, so nothing fails yet
Filter(ursus.Col("qty").Gt(int64(3)))
_, err := lf.Collect(context.Background())
fmt.Println(err)
}
Output: ursus: select: unknown column "prodcut" did you mean: "product"? available: order_id, date, region, product, qty, price at Project
Example (LazyExplainUnoptimized) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
q := sales().
Filter(ursus.Col("qty").Gt(int64(3))).
Select(ursus.Col("product"), ursus.Col("qty"))
written, err := q.Explain(context.Background(), ursus.Optimized(false))
if err != nil {
log.Fatal(err)
}
fmt.Println(written)
}
Output: PROJECT [col("product"), col("qty")] FILTER [(col("qty") > lit(3))] CSV SCAN testdata/sales.csv projection: * (6 cols)
Example (ListBuild) ¶
show(baskets())
show(sales().
GroupBy(ursus.Col("region")).
Agg(ursus.Col("qty").Implode().Alias("qtys")).
Sort(ursus.Asc(ursus.Col("region"))))
Output: shape: (3, 3) ┌───────┬──────────────────────────┬────────────────┐ │ order │ items │ prices │ │ Int64 │ List(String) │ List(Float64) │ ├───────┼──────────────────────────┼────────────────┤ │ 1 │ ["pear", "apple", "fig"] │ [2.25, 1.5, 3] │ │ 2 │ ["fig"] │ [3] │ │ 3 │ ["apple", "pear"] │ [1.5, 2.25] │ └───────┴──────────────────────────┴────────────────┘ shape: (3, 2) ┌─────────┬─────────────┐ │ region │ qtys │ │ String │ List(Int64) │ ├─────────┼─────────────┤ │ "east" │ [2, 12] │ │ "north" │ [10, 7, 3] │ │ "south" │ [4, 9, 6] │ └─────────┴─────────────┘
Example (ListExplode) ¶
show(baskets().Explode("items", "prices"))
Output: shape: (6, 3) ┌───────┬─────────┬─────────┐ │ order │ items │ prices │ │ Int64 │ String │ Float64 │ ├───────┼─────────┼─────────┤ │ 1 │ "pear" │ 2.25 │ │ 1 │ "apple" │ 1.5 │ │ 1 │ "fig" │ 3 │ │ 2 │ "fig" │ 3 │ │ 3 │ "apple" │ 1.5 │ │ 3 │ "pear" │ 2.25 │ └───────┴─────────┴─────────┘
Example (ListFilterEval) ¶
prices := ursus.Col("prices").List()
show(baskets().Select(
ursus.Col("order"),
prices.Filter(ursus.Element().Ge(2.0)).Alias("from_2"),
prices.Eval(ursus.Element().Rank(ursus.RankDense, true)).Alias("rank"),
))
Output: shape: (3, 3) ┌───────┬───────────────┬──────────────┐ │ order │ from_2 │ rank │ │ Int64 │ List(Float64) │ List(Uint32) │ ├───────┼───────────────┼──────────────┤ │ 1 │ [2.25, 3] │ [2, 3, 1] │ │ 2 │ [3] │ [1] │ │ 3 │ [2.25] │ [2, 1] │ └───────┴───────────────┴──────────────┘
Example (ListQuestions) ¶
items, prices := ursus.Col("items").List(), ursus.Col("prices").List()
show(baskets().Select(
ursus.Col("order"),
items.Len().Alias("n"),
items.Get(0).Alias("first"),
items.Contains("fig").Alias("has_fig"),
prices.Sum().Alias("total"),
prices.Max().Alias("dearest"),
))
Output: shape: (3, 6) ┌───────┬────────┬─────────┬─────────┬─────────┬─────────┐ │ order │ n │ first │ has_fig │ total │ dearest │ │ Int64 │ Uint32 │ String │ Bool │ Float64 │ Float64 │ ├───────┼────────┼─────────┼─────────┼─────────┼─────────┤ │ 1 │ 3 │ "pear" │ true │ 6.75 │ 3 │ │ 2 │ 1 │ "fig" │ true │ 3 │ 3 │ │ 3 │ 2 │ "apple" │ false │ 3.75 │ 2.25 │ └───────┴────────┴─────────┴─────────┴─────────┴─────────┘
Example (ListSets) ¶
items := ursus.Col("items")
fruit := ursus.Lit([]string{"apple", "pear"})
show(baskets().Select(
ursus.Col("order"),
items.List().SetIntersection(fruit).Alias("in_both"),
items.List().SetDifference(fruit).Alias("only_here"),
))
Output: shape: (3, 3) ┌───────┬───────────────────┬──────────────┐ │ order │ in_both │ only_here │ │ Int64 │ List(String) │ List(String) │ ├───────┼───────────────────┼──────────────┤ │ 1 │ ["pear", "apple"] │ ["fig"] │ │ 2 │ [] │ ["fig"] │ │ 3 │ ["apple", "pear"] │ [] │ └───────┴───────────────────┴──────────────┘
Example (ListTransform) ¶
items := ursus.Col("items").List()
show(baskets().Select(
ursus.Col("order"),
items.Sort().Alias("sorted"),
items.Join(" + ").Alias("joined"),
ursus.Col("prices").List().Eval(ursus.Element().Mul(2)).Alias("doubled"),
))
Output: shape: (3, 4) ┌───────┬──────────────────────────┬──────────────────────┬───────────────┐ │ order │ sorted │ joined │ doubled │ │ Int64 │ List(String) │ String │ List(Float64) │ ├───────┼──────────────────────────┼──────────────────────┼───────────────┤ │ 1 │ ["apple", "fig", "pear"] │ "pear + apple + fig" │ [4.5, 3, 6] │ │ 2 │ ["fig"] │ "fig" │ [6] │ │ 3 │ ["apple", "pear"] │ "apple + pear" │ [3, 4.5] │ └───────┴──────────────────────────┴──────────────────────┴───────────────┘
Example (MemoryRefusal) ¶
package main
import (
"context"
"fmt"
"os"
"github.com/advenn/ursus"
)
func main() {
keys := make([]int64, 100_000)
_, err := ursus.Frame(ursus.Values("k", keys)).
Select(ursus.Col("k").Implode()).
Collect(context.Background(),
ursus.WithMemoryLimit(64<<10),
ursus.WithSpillDir(os.TempDir()))
fmt.Println(err)
}
Output: ursus: group_by: memory limit of 64.0KiB exceeded: the query is holding 105.2KiB, 105.2KiB of it in this operator group_by holds one entry per distinct key, and implode holds every VALUE as its answer — which partitioning to disk cannot divide, because it divides across keys (quantile, median, n_unique, mode and corr_spearman spill their values); raise the limit with WithMemoryLimit sort, group_by, join, unique, over, reverse and tail spill to disk; join_asof, merge_sorted, hstack, rolling and group_by_dynamic stream their input; an over computing a rolling window by time one of whose periods holds more than the limit fails rather than exceed it, and so does implode over one group larger than it
Example (MemorySink) ¶
Compiled, not run: it reads files the tests do not have.
package main
import (
"context"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
err := ursus.ScanParquet("events/*.parquet").
Sort(ursus.Desc(ursus.Col("ts"))).
SinkParquet(ctx, "sorted.parquet",
ursus.WithMemoryLimit(512<<20),
ursus.WithSpillDir("/var/tmp/ursus"))
if err != nil {
log.Fatal(err)
}
}
Output:
Example (MemorySpill) ¶
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/advenn/ursus"
)
func main() {
keys := make([]int64, 100_000)
for i := range keys {
keys[i] = int64(i * 7919 % 25_000)
}
var stats ursus.MemoryStats
df, err := ursus.Frame(ursus.Values("k", keys)).
GroupBy(ursus.Col("k")).Agg(ursus.Len().Alias("n")).
Select(ursus.Len().Alias("groups"), ursus.Col("n").Max().Alias("largest")).
Collect(context.Background(),
ursus.WithMemoryLimit(256<<10),
ursus.WithSpillDir(os.TempDir()),
ursus.WithMemoryStats(&stats))
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
fmt.Println("spilled:", stats.Spills > 0)
}
Output: shape: (1, 2) ┌────────┬─────────┐ │ groups │ largest │ │ Uint64 │ Uint64 │ ├────────┼─────────┤ │ 25000 │ 4 │ └────────┴─────────┘ spilled: true
Example (MissingCount) ¶
show(readings().Select(ursus.All().NullCount()))
Output: shape: (1, 3) ┌────────┬────────┬────────┐ │ hour │ temp │ backup │ │ Uint64 │ Uint64 │ Uint64 │ ├────────┼────────┼────────┤ │ 0 │ 3 │ 3 │ └────────┴────────┴────────┘
Example (MissingDrop) ¶
show(readings().DropNulls("temp"))
show(readings().DropNulls())
Output: shape: (3, 3) ┌───────┬─────────┬─────────┐ │ hour │ temp │ backup │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┤ │ 0 │ 10 │ 9 │ │ 3 │ 13 │ null │ │ 4 │ 12 │ null │ └───────┴─────────┴─────────┘ shape: (1, 3) ┌───────┬─────────┬─────────┐ │ hour │ temp │ backup │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┤ │ 0 │ 10 │ 9 │ └───────┴─────────┴─────────┘
Example (MissingDropNans) ¶
nan := math.NaN()
present := []bool{true, true, false, true} // the third is null
ratios := ursus.Frame(
ursus.Values("id", []int64{1, 2, 3, 4}),
ursus.ValuesNullable("ratio", []float64{0.5, nan, 0, 2}, present),
)
show(ratios.DropNans())
Output: shape: (3, 2) ┌───────┬─────────┐ │ id │ ratio │ │ Int64 │ Float64 │ ├───────┼─────────┤ │ 1 │ 0.5 │ │ 3 │ null │ │ 4 │ 2 │ └───────┴─────────┘
Example (MissingFillNeighbours) ¶
temp := ursus.Col("temp")
show(readings().Select(
ursus.Col("hour"),
temp,
temp.FillNull(ursus.FillForward).Alias("forward"),
temp.ForwardFill(1).Alias("forward_1"),
temp.FillNull(ursus.FillBackward).Alias("backward"),
temp.Interpolate().Alias("interpolated"),
))
Output: shape: (6, 6) ┌───────┬─────────┬─────────┬───────────┬──────────┬──────────────┐ │ hour │ temp │ forward │ forward_1 │ backward │ interpolated │ │ Int64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┼───────────┼──────────┼──────────────┤ │ 0 │ 10 │ 10 │ 10 │ 10 │ 10 │ │ 1 │ null │ 10 │ 10 │ 13 │ 11 │ │ 2 │ null │ 10 │ null │ 13 │ 12 │ │ 3 │ 13 │ 13 │ 13 │ 13 │ 13 │ │ 4 │ 12 │ 12 │ 12 │ 12 │ 12 │ │ 5 │ null │ 12 │ 12 │ null │ null │ └───────┴─────────┴─────────┴───────────┴──────────┴──────────────┘
Example (MissingFillValue) ¶
temp := ursus.Col("temp")
show(readings().Select(
ursus.Col("hour"),
temp,
temp.FillNullWith(0.0).Alias("zero"),
temp.FillNull(ursus.FillMean).Alias("mean"),
ursus.Coalesce(temp, ursus.Col("backup"), ursus.Lit(-1.0)).Alias("coalesced"),
))
Output: shape: (6, 5) ┌───────┬─────────┬─────────┬────────────────────┬───────────┐ │ hour │ temp │ zero │ mean │ coalesced │ │ Int64 │ Float64 │ Float64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┼────────────────────┼───────────┤ │ 0 │ 10 │ 10 │ 10 │ 10 │ │ 1 │ null │ 0 │ 11.666666666666666 │ 11 │ │ 2 │ null │ 0 │ 11.666666666666666 │ -1 │ │ 3 │ 13 │ 13 │ 13 │ 13 │ │ 4 │ 12 │ 12 │ 12 │ 12 │ │ 5 │ null │ 0 │ 11.666666666666666 │ 14 │ └───────┴─────────┴─────────┴────────────────────┴───────────┘
Example (MissingFrameFill) ¶
show(readings().FillNull(0.0))
Output: shape: (6, 3) ┌───────┬─────────┬─────────┐ │ hour │ temp │ backup │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┤ │ 0 │ 10 │ 9 │ │ 1 │ 0 │ 11 │ │ 2 │ 0 │ 0 │ │ 3 │ 13 │ 0 │ │ 4 │ 12 │ 0 │ │ 5 │ 0 │ 14 │ └───────┴─────────┴─────────┘
Example (MissingInterpolateFrame) ¶
day := func(d int) time.Time { return time.Date(2026, 1, d, 0, 0, 0, 0, time.UTC) }
ends := []bool{true, false, false, true} // two rows missing between
gappy := ursus.Frame(
ursus.ValuesNullable("day", []time.Time{day(1), {}, {}, day(7)}, ends),
ursus.ValuesNullable("level", []int64{10, 0, 0, 40}, ends),
ursus.ValuesNullable("note", []string{"start", "", "", "end"}, ends),
).WithColumns(ursus.Col("day").Cast(ursus.Date))
show(gappy.Interpolate())
Output: shape: (4, 3) ┌────────────┬─────────┬─────────┐ │ day │ level │ note │ │ Date │ Float64 │ String │ ├────────────┼─────────┼─────────┤ │ 2026-01-01 │ 10 │ "start" │ │ 2026-01-03 │ 20 │ null │ │ 2026-01-05 │ 30 │ null │ │ 2026-01-07 │ 40 │ "end" │ └────────────┴─────────┴─────────┘
Example (MissingLimit) ¶
show(readings().FillNull(ursus.FillForward.Limit(1)))
Output: shape: (6, 3) ┌───────┬─────────┬─────────┐ │ hour │ temp │ backup │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┤ │ 0 │ 10 │ 9 │ │ 1 │ 10 │ 11 │ │ 2 │ null │ 11 │ │ 3 │ 13 │ null │ │ 4 │ 12 │ null │ │ 5 │ 12 │ 14 │ └───────┴─────────┴─────────┘
Example (QuickstartExplain) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
plan, err := ursus.ScanCSV("testdata/sales.csv").
Filter(ursus.Col("qty").Gt(int64(3))).
Select(ursus.Col("product"), ursus.Col("qty")).
Explain(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(plan)
}
Output: FILTER [(col("qty") > lit(3))] CSV SCAN testdata/sales.csv projection: [product, qty] (2/6 cols)
Example (QuickstartFrame) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.Values("city", []string{"Oslo", "Lima", "Pune"}),
ursus.Values("population", []int64{709_000, 10_151_000, 7_764_000}),
ursus.Values("coastal", []bool{true, true, false}),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 3) ┌────────┬────────────┬─────────┐ │ city │ population │ coastal │ │ String │ Int64 │ Bool │ ├────────┼────────────┼─────────┤ │ "Oslo" │ 709000 │ true │ │ "Lima" │ 10151000 │ true │ │ "Pune" │ 7764000 │ false │ └────────┴────────────┴─────────┘
Example (QuickstartGroupBy) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.ScanCSV("testdata/sales.csv").
GroupBy(ursus.Col("product")).
Agg(
ursus.Col("qty").Sum().Alias("qty"),
ursus.Col("price").Max().Alias("price"),
ursus.Col("region").NUnique().Alias("regions"),
).
Sort(ursus.Asc(ursus.Col("product"))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 4) ┌─────────┬────────┬─────────┬─────────┐ │ product │ qty │ price │ regions │ │ String │ Int128 │ Float64 │ Uint64 │ ├─────────┼────────┼─────────┼─────────┤ │ "apple" │ 26 │ 1.5 │ 3 │ │ "fig" │ 12 │ 3 │ 2 │ │ "pear" │ 15 │ 2.25 │ 3 │ └─────────┴────────┴─────────┴─────────┘
Example (QuickstartJoin) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
managers := ursus.Frame(
ursus.Values("region", []string{"north", "south"}),
ursus.Values("manager", []string{"Ada", "Grace"}),
)
df, err := ursus.ScanCSV("testdata/sales.csv").
Join(managers,
ursus.JoinOn(ursus.Col("region")),
ursus.JoinHow(ursus.JoinLeft)).
Select(ursus.Col("order_id"), ursus.Col("region"), ursus.Col("manager")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (8, 3) ┌──────────┬─────────┬─────────┐ │ order_id │ region │ manager │ │ Int64 │ String │ String │ ├──────────┼─────────┼─────────┤ │ 1 │ "north" │ "Ada" │ │ 2 │ "south" │ "Grace" │ │ 3 │ "north" │ "Ada" │ │ 4 │ "east" │ null │ │ 5 │ "south" │ "Grace" │ │ 6 │ "east" │ null │ │ 7 │ "north" │ "Ada" │ │ 8 │ "south" │ "Grace" │ └──────────┴─────────┴─────────┘
Example (QuickstartRows) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
type sale struct {
ID int64 `ursus:"order_id"`
Product string `ursus:"product"`
Qty int64 `ursus:"qty"`
}
df, err := ursus.ScanCSV("testdata/sales.csv").
Filter(ursus.Col("qty").Ge(int64(9))).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
sales, err := df.Rows[sale]()
if err != nil {
log.Fatal(err)
}
for _, s := range sales {
fmt.Printf("%+v\n", s)
}
}
Output: {ID:1 Product:apple Qty:10} {ID:5 Product:fig Qty:9} {ID:6 Product:apple Qty:12}
Example (QuickstartScan) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (8, 6) ┌──────────┬────────────┬─────────┬─────────┬───────┬─────────┐ │ order_id │ date │ region │ product │ qty │ price │ │ Int64 │ Date │ String │ String │ Int64 │ Float64 │ ├──────────┼────────────┼─────────┼─────────┼───────┼─────────┤ │ 1 │ 2026-01-03 │ "north" │ "apple" │ 10 │ 1.5 │ │ 2 │ 2026-01-03 │ "south" │ "apple" │ 4 │ 1.5 │ │ 3 │ 2026-01-04 │ "north" │ "pear" │ 7 │ 2.25 │ │ 4 │ 2026-01-05 │ "east" │ "pear" │ 2 │ 2.25 │ │ 5 │ 2026-01-05 │ "south" │ "fig" │ 9 │ 3 │ │ 6 │ 2026-01-06 │ "east" │ "apple" │ 12 │ 1.5 │ │ 7 │ 2026-01-07 │ "north" │ "fig" │ 3 │ 3 │ │ 8 │ 2026-01-07 │ "south" │ "pear" │ 6 │ 2.25 │ └──────────┴────────────┴─────────┴─────────┴───────┴─────────┘
Example (QuickstartSelect) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.ScanCSV("testdata/sales.csv").
Filter(ursus.Col("region").Eq("north")).
Select(ursus.Col("product"), ursus.Col("qty")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 2) ┌─────────┬───────┐ │ product │ qty │ │ String │ Int64 │ ├─────────┼───────┤ │ "apple" │ 10 │ │ "pear" │ 7 │ │ "fig" │ 3 │ └─────────┴───────┘
Example (QuickstartWithColumns) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.ScanCSV("testdata/sales.csv").
WithColumns(
ursus.Col("qty").Mul(ursus.Col("price")).Alias("revenue"),
ursus.When(ursus.Col("qty").Ge(int64(8))).
Then("bulk").
Otherwise("single").
Alias("kind"),
).
Select(ursus.Col("order_id"), ursus.Col("revenue"), ursus.Col("kind")).
Head(4).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (4, 3) ┌──────────┬─────────┬──────────┐ │ order_id │ revenue │ kind │ │ Int64 │ Float64 │ String │ ├──────────┼─────────┼──────────┤ │ 1 │ 15 │ "bulk" │ │ 2 │ 6 │ "single" │ │ 3 │ 15.75 │ "single" │ │ 4 │ 4.5 │ "single" │ └──────────┴─────────┴──────────┘
Example (ReshapeConcat) ¶
january := ursus.Frame(
ursus.Values("day", []int64{30, 31}),
ursus.Values("qty", []int64{4, 6}),
)
february := ursus.Frame(
ursus.Values("day", []int64{1, 2}),
ursus.Values("qty", []int64{3, 8}),
)
show(ursus.Concat([]*ursus.LazyFrame{january, february}))
Output: shape: (4, 2) ┌───────┬───────┐ │ day │ qty │ │ Int64 │ Int64 │ ├───────┼───────┤ │ 30 │ 4 │ │ 31 │ 6 │ │ 1 │ 3 │ │ 2 │ 8 │ └───────┴───────┘
Example (ReshapeConcatAlign) ¶
prices := ursus.Frame(
ursus.Values("day", []int64{3, 1, 2}),
ursus.Values("close", []float64{10.5, 10.0, 11.0}),
)
volumes := ursus.Frame(
ursus.Values("day", []int64{2, 4, 1}),
ursus.Values("volume", []int64{700, 900, 500}),
)
show(ursus.Concat([]*ursus.LazyFrame{prices, volumes},
ursus.WithConcatMode(ursus.ConcatAlign)))
Output: shape: (4, 3) ┌───────┬─────────┬────────┐ │ day │ close │ volume │ │ Int64 │ Float64 │ Int64 │ ├───────┼─────────┼────────┤ │ 1 │ 10 │ 500 │ │ 2 │ 11 │ 700 │ │ 3 │ 10.5 │ null │ │ 4 │ null │ 900 │ └───────┴─────────┴────────┘
Example (ReshapeConcatDiagonal) ¶
old := ursus.Frame(
ursus.Values("id", []int64{1, 2}),
ursus.Values("name", []string{"Ada", "Ben"}),
)
recent := ursus.Frame(
ursus.Values("id", []int64{3}),
ursus.Values("email", []string{"cai@example.com"}),
)
show(ursus.Concat([]*ursus.LazyFrame{old, recent},
ursus.WithConcatMode(ursus.ConcatDiagonal)))
Output: shape: (3, 3) ┌───────┬────────┬───────────────────┐ │ id │ name │ email │ │ Int64 │ String │ String │ ├───────┼────────┼───────────────────┤ │ 1 │ "Ada" │ null │ │ 2 │ "Ben" │ null │ │ 3 │ null │ "cai@example.com" │ └───────┴────────┴───────────────────┘
Example (ReshapeConcatRelaxed) ¶
counted := ursus.Frame(ursus.Values("qty", []int64{4, 6}))
weighed := ursus.Frame(ursus.Values("qty", []float64{2.5}))
show(ursus.Concat([]*ursus.LazyFrame{counted, weighed},
ursus.WithConcatMode(ursus.ConcatRelaxed)))
Output: shape: (3, 1) ┌─────────┐ │ qty │ │ Float64 │ ├─────────┤ │ 4 │ │ 6 │ │ 2.5 │ └─────────┘
Example (ReshapeDummies) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
df, err := ursus.Frame(
ursus.Values("id", []int64{1, 2, 3, 4}),
ursus.ValuesNullable("size", []int64{10, 2, 0, 10},
[]bool{true, true, false, true}),
).Collect(ctx)
if err != nil {
log.Fatal(err)
}
d, err := df.ToDummies(ctx, ursus.DummiesOptions{Columns: []string{"size"}})
if err != nil {
log.Fatal(err)
}
fmt.Println(d)
}
Output: shape: (4, 4) ┌───────┬─────────┬────────┬───────────┐ │ id │ size_10 │ size_2 │ size_null │ │ Int64 │ Uint8 │ Uint8 │ Uint8 │ ├───────┼─────────┼────────┼───────────┤ │ 1 │ 1 │ 0 │ 0 │ │ 2 │ 0 │ 1 │ 0 │ │ 3 │ 0 │ 0 │ 1 │ │ 4 │ 1 │ 0 │ 0 │ └───────┴─────────┴────────┴───────────┘
Example (ReshapeExplode) ¶
posts := ursus.Frame(
ursus.Values("post", []int64{1, 2, 3}),
ursus.Values("tags", []string{"go,data", "go", ""}),
).WithColumns(ursus.Col("tags").Str().Split(","))
show(posts)
show(posts.Explode("tags"))
Output: shape: (3, 2) ┌───────┬────────────────┐ │ post │ tags │ │ Int64 │ List(String) │ ├───────┼────────────────┤ │ 1 │ ["go", "data"] │ │ 2 │ ["go"] │ │ 3 │ [""] │ └───────┴────────────────┘ shape: (4, 2) ┌───────┬────────┐ │ post │ tags │ │ Int64 │ String │ ├───────┼────────┤ │ 1 │ "go" │ │ 1 │ "data" │ │ 2 │ "go" │ │ 3 │ "" │ └───────┴────────┘
Example (ReshapeHStack) ¶
names := ursus.Frame(ursus.Values("name", []string{"Ada", "Ben"}))
scores := ursus.Frame(ursus.Values("score", []int64{90, 75}))
show(names.HStack(scores))
Output: shape: (2, 2) ┌────────┬───────┐ │ name │ score │ │ String │ Int64 │ ├────────┼───────┤ │ "Ada" │ 90 │ │ "Ben" │ 75 │ └────────┴───────┘
Example (ReshapePartitionBy) ¶
ctx := context.Background()
df, err := sales().Collect(ctx)
if err != nil {
log.Fatal(err)
}
parts, err := df.PartitionBy(ctx, ursus.PartitionOptions{
By: []string{"region"},
DropKey: true,
})
if err != nil {
log.Fatal(err)
}
for _, p := range parts {
region, _, _ := p.Key.At[string](0, "region")
fmt.Println(region, p.Frame.Height())
}
fmt.Println(parts[0].Frame)
Output: north 3 south 3 east 2 shape: (3, 5) ┌──────────┬────────────┬─────────┬───────┬─────────┐ │ order_id │ date │ product │ qty │ price │ │ Int64 │ Date │ String │ Int64 │ Float64 │ ├──────────┼────────────┼─────────┼───────┼─────────┤ │ 1 │ 2026-01-03 │ "apple" │ 10 │ 1.5 │ │ 3 │ 2026-01-04 │ "pear" │ 7 │ 2.25 │ │ 7 │ 2026-01-07 │ "fig" │ 3 │ 3 │ └──────────┴────────────┴─────────┴───────┴─────────┘
Example (ReshapePivot) ¶
ctx := context.Background()
df, err := sales().Collect(ctx)
if err != nil {
log.Fatal(err)
}
wide, err := df.Pivot(ctx, ursus.PivotOptions{
On: []string{"product"},
Index: []string{"region"},
Values: []string{"qty"},
Agg: ursus.Expr.Sum,
SortColumns: true,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(wide)
Output: shape: (3, 4) ┌─────────┬────────┬────────┬────────┐ │ region │ apple │ fig │ pear │ │ String │ Int128 │ Int128 │ Int128 │ ├─────────┼────────┼────────┼────────┤ │ "north" │ 10 │ 3 │ 7 │ │ "south" │ 4 │ 9 │ 6 │ │ "east" │ 12 │ null │ 2 │ └─────────┴────────┴────────┴────────┘
Example (ReshapePivotLazy) ¶
products := ursus.Values("product", []string{"apple", "pear", "plum"})
wide := sales().Pivot(ursus.PivotOptions{
On: []string{"product"},
OnColumns: []*ursus.Column{products},
Index: []string{"region"},
Values: []string{"qty"},
Agg: ursus.Expr.Sum,
})
show(wide)
Output: shape: (3, 4) ┌─────────┬────────┬────────┬────────┐ │ region │ apple │ pear │ plum │ │ String │ Int128 │ Int128 │ Int128 │ ├─────────┼────────┼────────┼────────┤ │ "north" │ 10 │ 7 │ null │ │ "south" │ 4 │ 6 │ null │ │ "east" │ 12 │ 2 │ null │ └─────────┴────────┴────────┴────────┘
Example (ReshapePivotSeveral) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
df, err := ursus.Frame(
ursus.Values("shop", []string{"a", "a", "b", "b"}),
ursus.Values("quarter", []string{"q1", "q2", "q1", "q1"}),
ursus.Values("channel", []string{"web", "web", "store", "web"}),
ursus.Values("sales", []int64{10, 12, 7, 3}),
).Collect(ctx)
if err != nil {
log.Fatal(err)
}
wide, err := df.Pivot(ctx, ursus.PivotOptions{
On: []string{"quarter", "channel"},
Index: []string{"shop"},
Values: []string{"sales"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(wide)
}
Output: shape: (2, 4) ┌────────┬──────────────┬──────────────┬────────────────┐ │ shop │ {"q1","web"} │ {"q2","web"} │ {"q1","store"} │ │ String │ Int64 │ Int64 │ Int64 │ ├────────┼──────────────┼──────────────┼────────────────┤ │ "a" │ 10 │ 12 │ null │ │ "b" │ 3 │ null │ 7 │ └────────┴──────────────┴──────────────┴────────────────┘
Example (ReshapeTranspose) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
df, err := ursus.Frame(
ursus.Values("metric", []string{"orders", "revenue"}),
ursus.Values("north", []float64{3, 39.75}),
ursus.Values("south", []float64{3, 46.5}),
).Collect(ctx)
if err != nil {
log.Fatal(err)
}
t, err := df.Transpose(ctx, ursus.TransposeOptions{
IncludeHeader: true,
HeaderName: "region",
ColumnNamesFrom: "metric",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(t)
}
Output: shape: (2, 3) ┌─────────┬─────────┬─────────┐ │ region │ orders │ revenue │ │ String │ Float64 │ Float64 │ ├─────────┼─────────┼─────────┤ │ "north" │ 3 │ 39.75 │ │ "south" │ 3 │ 46.5 │ └─────────┴─────────┴─────────┘
Example (ReshapeUnnest) ¶
points := ursus.Frame(
ursus.Values("id", []int64{1, 2}),
ursus.Values("x", []float64{0.5, 2}),
ursus.Values("y", []float64{1, -1}),
).Select(
ursus.Col("id"),
ursus.Struct(ursus.Col("x"), ursus.Col("y")).Alias("point"),
)
show(points)
show(points.Unnest("point"))
Output: shape: (2, 2) ┌───────┬────────────────────────────────┐ │ id │ point │ │ Int64 │ Struct(x: Float64, y: Float64) │ ├───────┼────────────────────────────────┤ │ 1 │ {x: 0.5, y: 1} │ │ 2 │ {x: 2, y: -1} │ └───────┴────────────────────────────────┘ shape: (2, 3) ┌───────┬─────────┬─────────┐ │ id │ x │ y │ │ Int64 │ Float64 │ Float64 │ ├───────┼─────────┼─────────┤ │ 1 │ 0.5 │ 1 │ │ 2 │ 2 │ -1 │ └───────┴─────────┴─────────┘
Example (ReshapeUnpivot) ¶
quarters := ursus.Frame(
ursus.Values("region", []string{"north", "south"}),
ursus.Values("q1", []int64{120, 80}),
ursus.Values("q2", []int64{135, 95}),
)
show(quarters.Unpivot(ursus.UnpivotOptions{
On: []string{"q1", "q2"},
Index: []string{"region"},
VariableName: "quarter",
ValueName: "sales",
}))
Output: shape: (4, 3) ┌─────────┬─────────┬───────┐ │ region │ quarter │ sales │ │ String │ String │ Int64 │ ├─────────┼─────────┼───────┤ │ "north" │ "q1" │ 120 │ │ "north" │ "q2" │ 135 │ │ "south" │ "q1" │ 80 │ │ "south" │ "q2" │ 95 │ └─────────┴─────────┴───────┘
Example (ReshapeUnpivotRest) ¶
quarters := ursus.Frame(
ursus.Values("region", []string{"north", "south"}),
ursus.Values("q1", []int64{120, 80}),
ursus.Values("q2", []int64{135, 95}),
ursus.Values("q3", []int32{150, 90}),
)
show(quarters.Unpivot(ursus.UnpivotOptions{Index: []string{"region"}}))
Output: shape: (6, 3) ┌─────────┬──────────┬───────┐ │ region │ variable │ value │ │ String │ String │ Int64 │ ├─────────┼──────────┼───────┤ │ "north" │ "q1" │ 120 │ │ "north" │ "q2" │ 135 │ │ "north" │ "q3" │ 150 │ │ "south" │ "q1" │ 80 │ │ "south" │ "q2" │ 95 │ │ "south" │ "q3" │ 90 │ └─────────┴──────────┴───────┘
Example (ReshapeUnstack) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
df, err := ursus.Frame(
ursus.Values("reading", []float64{1.5, 2, 2.5, 3, 3.5, 4, 4.5}),
).Collect(ctx)
if err != nil {
log.Fatal(err)
}
g, err := df.Unstack(ctx, ursus.UnstackOptions{Step: 3})
if err != nil {
log.Fatal(err)
}
fmt.Println(g)
}
Output: shape: (3, 3) ┌───────────┬───────────┬───────────┐ │ reading_0 │ reading_1 │ reading_2 │ │ Float64 │ Float64 │ Float64 │ ├───────────┼───────────┼───────────┤ │ 1.5 │ 3 │ 4.5 │ │ 2 │ 3.5 │ null │ │ 2.5 │ 4 │ null │ └───────────┴───────────┴───────────┘
Example (SelectByName) ¶
df, err := sales().
Select(
ursus.Col("order_id"),
ursus.ColRegex("^(qty|price)$"),
ursus.ColDType(ursus.String),
).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 5) ┌──────────┬───────┬─────────┬─────────┬─────────┐ │ order_id │ qty │ price │ region │ product │ │ Int64 │ Int64 │ Float64 │ String │ String │ ├──────────┼───────┼─────────┼─────────┼─────────┤ │ 1 │ 10 │ 1.5 │ "north" │ "apple" │ │ 2 │ 4 │ 1.5 │ "south" │ "apple" │ │ 3 │ 7 │ 2.25 │ "north" │ "pear" │ └──────────┴───────┴─────────┴─────────┴─────────┘
Example (SelectDropRename) ¶
df, err := sales().
Drop("order_id", "date").
Rename(map[string]string{"qty": "quantity", "price": "unit_price"}).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 4) ┌─────────┬─────────┬──────────┬────────────┐ │ region │ product │ quantity │ unit_price │ │ String │ String │ Int64 │ Float64 │ ├─────────┼─────────┼──────────┼────────────┤ │ "north" │ "apple" │ 10 │ 1.5 │ │ "south" │ "apple" │ 4 │ 1.5 │ │ "north" │ "pear" │ 7 │ 2.25 │ └─────────┴─────────┴──────────┴────────────┘
Example (SelectExclude) ¶
df, err := sales().
Select(ursus.Exclude("order_id", "date")).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 4) ┌─────────┬─────────┬───────┬─────────┐ │ region │ product │ qty │ price │ │ String │ String │ Int64 │ Float64 │ ├─────────┼─────────┼───────┼─────────┤ │ "north" │ "apple" │ 10 │ 1.5 │ │ "south" │ "apple" │ 4 │ 1.5 │ │ "north" │ "pear" │ 7 │ 2.25 │ └─────────┴─────────┴───────┴─────────┘
Example (SelectHashRows) ¶
visits := ursus.Frame(
ursus.Values("user", []string{"ada", "ben", "ada"}),
ursus.Values("page", []string{"/home", "/home", "/home"}),
)
show(visits.WithColumns(ursus.HashRows(0).Alias("hash")))
Output: shape: (3, 3) ┌────────┬─────────┬──────────────────────┐ │ user │ page │ hash │ │ String │ String │ Uint64 │ ├────────┼─────────┼──────────────────────┤ │ "ada" │ "/home" │ 15332602214641343754 │ │ "ben" │ "/home" │ 17635480945181825081 │ │ "ada" │ "/home" │ 15332602214641343754 │ └────────┴─────────┴──────────────────────┘
Example (SelectInsertColumn) ¶
lines := sales().
Select(ursus.Col("order_id"), ursus.Col("qty"), ursus.Col("price")).
Head(3)
revenue := ursus.Col("qty").Mul(ursus.Col("price")).Alias("revenue")
show(lines.InsertColumn(1, revenue))
show(lines.InsertColumn(-1, ursus.Values("note", []string{"gift", "", "rush"})))
Output: shape: (3, 4) ┌──────────┬─────────┬───────┬─────────┐ │ order_id │ revenue │ qty │ price │ │ Int64 │ Float64 │ Int64 │ Float64 │ ├──────────┼─────────┼───────┼─────────┤ │ 1 │ 15 │ 10 │ 1.5 │ │ 2 │ 6 │ 4 │ 1.5 │ │ 3 │ 15.75 │ 7 │ 2.25 │ └──────────┴─────────┴───────┴─────────┘ shape: (3, 4) ┌──────────┬───────┬────────┬─────────┐ │ order_id │ qty │ note │ price │ │ Int64 │ Int64 │ String │ Float64 │ ├──────────┼───────┼────────┼─────────┤ │ 1 │ 10 │ "gift" │ 1.5 │ │ 2 │ 4 │ "" │ 1.5 │ │ 3 │ 7 │ "rush" │ 2.25 │ └──────────┴───────┴────────┴─────────┘
Example (SelectNames) ¶
c := ursus.Col
df, err := sales().
Select(
c("qty", "price").Name().Suffix("_x"),
c("region").Name().ToUpper(),
c("qty").Mul(c("price")).Alias("total").Name().Keep(),
).
Head(3).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 4) ┌───────┬─────────┬─────────┬─────────┐ │ qty_x │ price_x │ REGION │ qty │ │ Int64 │ Float64 │ String │ Float64 │ ├───────┼─────────┼─────────┼─────────┤ │ 10 │ 1.5 │ "north" │ 15 │ │ 4 │ 1.5 │ "south" │ 6 │ │ 7 │ 2.25 │ "north" │ 15.75 │ └───────┴─────────┴─────────┴─────────┘
Example (SelectSelectors) ¶
every := selector.Numeric().Difference(selector.ByName("order_id"))
df, err := sales().Select(every.Expr()).Head(3).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 2) ┌───────┬─────────┐ │ qty │ price │ │ Int64 │ Float64 │ ├───────┼─────────┤ │ 10 │ 1.5 │ │ 4 │ 1.5 │ │ 7 │ 2.25 │ └───────┴─────────┘
Example (Slices) ¶
ctx := context.Background()
ids := func(lf *ursus.LazyFrame) []int64 {
df, err := lf.Collect(ctx)
if err != nil {
log.Fatal(err)
}
s, err := df.Column[int64]("order_id")
if err != nil {
log.Fatal(err)
}
return s.Values()
}
fmt.Println("head 3: ", ids(sales().Head(3)))
fmt.Println("tail 2: ", ids(sales().Tail(2)))
fmt.Println("slice 2, 3: ", ids(sales().Slice(2, 3)))
fmt.Println("slice -3, 2:", ids(sales().Slice(-3, 2)))
fmt.Println("reverse: ", ids(sales().Reverse()))
Output: head 3: [1 2 3] tail 2: [7 8] slice 2, 3: [3 4 5] slice -3, 2: [6 7] reverse: [8 7 6 5 4 3 2 1]
Example (SortKeys) ¶
df, err := sales().
Sort(ursus.Asc(ursus.Col("region")), ursus.Desc(ursus.Col("qty"))).
Select(ursus.Col("region"), ursus.Col("product"), ursus.Col("qty")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (8, 3) ┌─────────┬─────────┬───────┐ │ region │ product │ qty │ │ String │ String │ Int64 │ ├─────────┼─────────┼───────┤ │ "east" │ "apple" │ 12 │ │ "east" │ "pear" │ 2 │ │ "north" │ "apple" │ 10 │ │ "north" │ "pear" │ 7 │ │ "north" │ "fig" │ 3 │ │ "south" │ "fig" │ 9 │ │ "south" │ "pear" │ 6 │ │ "south" │ "apple" │ 4 │ └─────────┴─────────┴───────┘
Example (SortNulls) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.ValuesNullable("x", []int64{3, 0, 1, 2}, []bool{true, false, true, true}),
).Sort(ursus.Desc(ursus.Col("x")).NullsLast()).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (4, 1) ┌───────┐ │ x │ │ Int64 │ ├───────┤ │ 3 │ │ 2 │ │ 1 │ │ null │ └───────┘
Example (StrClean) ¶
name := ursus.Col("name").Str()
trimmed := name.StripChars(" ").Str() // a method gives an Expr: Str() again
show(people().Select(
trimmed.ToTitlecase().Alias("name"),
trimmed.ToLower().Alias("lower"),
name.LenChars().Alias("chars"),
name.LenBytes().Alias("bytes"),
))
Output: shape: (3, 4) ┌────────────────┬────────────────┬────────┬────────┐ │ name │ lower │ chars │ bytes │ │ String │ String │ Uint32 │ Uint32 │ ├────────────────┼────────────────┼────────┼────────┤ │ "Ada Lovelace" │ "ada lovelace" │ 14 │ 14 │ │ "Zoë Smith" │ "zoë smith" │ 10 │ 11 │ │ "Ben O'Brien" │ "ben o'brien" │ 11 │ 11 │ └────────────────┴────────────────┴────────┴────────┘
Example (StrCombine) ¶
show(sales().Head(3).Select(
ursus.ConcatStr("/", ursus.Col("region"), ursus.Col("product")).Alias("path"),
ursus.Format("{} x {}", ursus.Col("qty"), ursus.Col("product")).Alias("line"),
))
show(sales().
GroupBy(ursus.Col("region")).
Agg(ursus.Col("product").Str().Join(", ").Alias("products")).
Sort(ursus.Asc(ursus.Col("region"))))
Output: shape: (3, 2) ┌───────────────┬──────────────┐ │ path │ line │ │ String │ String │ ├───────────────┼──────────────┤ │ "north/apple" │ "10 x apple" │ │ "south/apple" │ "4 x apple" │ │ "north/pear" │ "7 x pear" │ └───────────────┴──────────────┘ shape: (3, 2) ┌─────────┬────────────────────┐ │ region │ products │ │ String │ String │ ├─────────┼────────────────────┤ │ "east" │ "pear, apple" │ │ "north" │ "apple, pear, fig" │ │ "south" │ "apple, fig, pear" │ └─────────┴────────────────────┘
Example (StrExtract) ¶
contact := ursus.Col("contact").Str()
show(people().Select(
contact.Extract(`([\w.]+)@([\w.]+)`, 2).Alias("domain"),
contact.ExtractAll(`\d{3}-\d{4}`).Alias("phones"),
))
Output: shape: (3, 2) ┌────────────────────┬──────────────────────────┐ │ domain │ phones │ │ String │ List(String) │ ├────────────────────┼──────────────────────────┤ │ "example.com" │ [] │ │ "mail.example.org" │ [] │ │ null │ ["555-0100", "555-0199"] │ └────────────────────┴──────────────────────────┘
Example (StrMatch) ¶
contact := ursus.Col("contact").Str()
show(people().Select(
ursus.Col("contact"),
contact.Contains("@", true).Alias("email"),
contact.Contains(`\d{3}-\d{4}`, false).Alias("us_phone"),
contact.EndsWith(".org").Alias("org"),
contact.CountMatches(`\d`, false).Alias("digits"),
))
Output: shape: (3, 5) ┌─────────────────────────────────────┬───────┬──────────┬───────┬────────┐ │ contact │ email │ us_phone │ org │ digits │ │ String │ Bool │ Bool │ Bool │ Uint32 │ ├─────────────────────────────────────┼───────┼──────────┼───────┼────────┤ │ "ada@example.com, +44 20 7946 0958" │ true │ false │ false │ 12 │ │ "zoe.smith@mail.example.org" │ true │ false │ true │ 0 │ │ "call 555-0100 or 555-0199" │ false │ true │ false │ 14 │ └─────────────────────────────────────┴───────┴──────────┴───────┴────────┘
Example (StrParse) ¶
joined := ursus.Col("joined").Str()
show(people().Select(
ursus.Col("joined"),
joined.Strptime(ursus.Date, "%Y-%m-%d", false).Alias("date"),
joined.Head(4).Str().ToInteger().Alias("year"),
))
Output: shape: (3, 3) ┌──────────────┬────────────┬───────┐ │ joined │ date │ year │ │ String │ Date │ Int64 │ ├──────────────┼────────────┼───────┤ │ "2024-03-01" │ 2024-03-01 │ 2024 │ │ "2025-11-17" │ 2025-11-17 │ 2025 │ │ "bad date" │ null │ null │ └──────────────┴────────────┴───────┘
Example (StrReplace) ¶
contact := ursus.Col("contact").Str()
show(people().Select(
contact.Replace(`\d`, "#", false).Alias("first_digit"),
contact.ReplaceAll(`\d`, "#", false).Alias("every_digit"),
))
Output: shape: (3, 2) ┌─────────────────────────────────────┬─────────────────────────────────────┐ │ first_digit │ every_digit │ │ String │ String │ ├─────────────────────────────────────┼─────────────────────────────────────┤ │ "ada@example.com, +#4 20 7946 0958" │ "ada@example.com, +## ## #### ####" │ │ "zoe.smith@mail.example.org" │ "zoe.smith@mail.example.org" │ │ "call #55-0100 or 555-0199" │ "call ###-#### or ###-####" │ └─────────────────────────────────────┴─────────────────────────────────────┘
Example (StrSlice) ¶
code := ursus.Frame(ursus.Values("code", []string{"7", "42", "1234"}))
c := ursus.Col("code").Str()
show(code.Select(
ursus.Col("code"),
c.ZFill(5).Alias("zfill"),
c.PadEnd(5, ".").Alias("pad_end"),
c.Head(2).Alias("head"),
c.Slice(1, 2).Alias("slice"),
c.Reverse().Alias("reverse"),
))
Output: shape: (3, 6) ┌────────┬─────────┬─────────┬────────┬────────┬─────────┐ │ code │ zfill │ pad_end │ head │ slice │ reverse │ │ String │ String │ String │ String │ String │ String │ ├────────┼─────────┼─────────┼────────┼────────┼─────────┤ │ "7" │ "00007" │ "7...." │ "7" │ "" │ "7" │ │ "42" │ "00042" │ "42..." │ "42" │ "2" │ "24" │ │ "1234" │ "01234" │ "1234." │ "12" │ "23" │ "4321" │ └────────┴─────────┴─────────┴────────┴────────┴─────────┘
Example (StrSplit) ¶
show(people().Select(
ursus.Col("name").Str().StripChars(" ").Str().Split(" ").Alias("words"),
))
show(people().
Select(ursus.Col("joined").Str().SplitExact("-", 2, false).Alias("parts")).
Unnest("parts"))
Output: shape: (3, 1) ┌─────────────────────┐ │ words │ │ List(String) │ ├─────────────────────┤ │ ["ada", "LOVELACE"] │ │ ["Zoë", "Smith"] │ │ ["ben", "o'brien"] │ └─────────────────────┘ shape: (3, 3) ┌────────────┬─────────┬─────────┐ │ field_0 │ field_1 │ field_2 │ │ String │ String │ String │ ├────────────┼─────────┼─────────┤ │ "2024" │ "03" │ "01" │ │ "2025" │ "11" │ "17" │ │ "bad date" │ null │ null │ └────────────┴─────────┴─────────┘
Example (StructBuild) ¶
show(sales().Head(3).Select(
ursus.Col("order_id"),
ursus.Struct(ursus.Col("product"), ursus.Col("qty")).Alias("line"),
))
Output: shape: (3, 2) ┌──────────┬─────────────────────────────────────┐ │ order_id │ line │ │ Int64 │ Struct(product: String, qty: Int64) │ ├──────────┼─────────────────────────────────────┤ │ 1 │ {product: "apple", qty: 10} │ │ 2 │ {product: "apple", qty: 4} │ │ 3 │ {product: "pear", qty: 7} │ └──────────┴─────────────────────────────────────┘
Example (StructFields) ¶
line := ursus.Struct(ursus.Col("product"), ursus.Col("qty")).Alias("line")
l := ursus.Col("line").Struct()
lines := sales().Head(2).Select(line)
show(lines.Select(
l.Field("product").Alias("product"),
l.WithFields(l.Field("qty").Mul(10).Alias("qty")).Alias("scaled"),
))
show(lines.Select(l.JsonEncode().Alias("json")))
Output: shape: (2, 2) ┌─────────┬─────────────────────────────────────┐ │ product │ scaled │ │ String │ Struct(product: String, qty: Int64) │ ├─────────┼─────────────────────────────────────┤ │ "apple" │ {product: "apple", qty: 100} │ │ "apple" │ {product: "apple", qty: 40} │ └─────────┴─────────────────────────────────────┘ shape: (2, 1) ┌──────────────────────────────────────┐ │ json │ │ String │ ├──────────────────────────────────────┤ │ "{\"product\":\"apple\",\"qty\":10}" │ │ "{\"product\":\"apple\",\"qty\":4}" │ └──────────────────────────────────────┘
Example (TimeArithmetic) ¶
invoices := ursus.Frame(
ursus.Values("issued", []string{"2026-01-31", "2026-02-10"}),
ursus.Values("paid", []string{"2026-02-14", "2026-02-11"}),
).Select(ursus.Col("issued").Str().ToDate(), ursus.Col("paid").Str().ToDate())
issued := ursus.Col("issued").Dt()
show(invoices.Select(
ursus.Col("issued"),
ursus.Col("paid").Sub(ursus.Col("issued")).Dt().TotalDays().
Alias("days_to_pay"),
issued.OffsetBy(ursus.Every("1mo")).Alias("plus_a_month"),
issued.MonthEnd().Alias("month_end"),
issued.AddBusinessDays(5, ursus.RollForward).Alias("plus_5_business"),
))
Output: shape: (2, 5) ┌────────────┬─────────────┬──────────────┬────────────┬─────────────────┐ │ issued │ days_to_pay │ plus_a_month │ month_end │ plus_5_business │ │ Date │ Int64 │ Date │ Date │ Date │ ├────────────┼─────────────┼──────────────┼────────────┼─────────────────┤ │ 2026-01-31 │ 14 │ 2026-02-28 │ 2026-01-31 │ 2026-02-09 │ │ 2026-02-10 │ 1 │ 2026-03-10 │ 2026-02-28 │ 2026-02-17 │ └────────────┴─────────────┴──────────────┴────────────┴─────────────────┘
Example (TimeDynamic) ¶
show(prices().
Filter(ursus.Col("ticker").Eq("ACME")).
GroupByDynamic(ursus.Col("date"),
ursus.DynamicOptions{Every: ursus.Every("1d")}).
Agg(ursus.Len().Alias("rows"), ursus.Col("close").Mean().Alias("close")))
Output: shape: (8, 3) ┌────────────┬────────┬─────────┐ │ date │ rows │ close │ │ Date │ Uint64 │ Float64 │ ├────────────┼────────┼─────────┤ │ 2026-01-05 │ 1 │ 10 │ │ 2026-01-06 │ 1 │ 11 │ │ 2026-01-07 │ 1 │ 10.5 │ │ 2026-01-08 │ 1 │ 12 │ │ 2026-01-09 │ 1 │ 12 │ │ 2026-01-10 │ 0 │ null │ │ 2026-01-11 │ 0 │ null │ │ 2026-01-12 │ 1 │ 13.5 │ └────────────┴────────┴─────────┘
Example (TimeDynamicWeeks) ¶
show(sales().
GroupByDynamic(ursus.Col("date"), ursus.DynamicOptions{
Every: ursus.Every("1w"),
GroupBy: []ursus.Expr{ursus.Col("region")},
}).
Agg(ursus.Col("qty").Sum().Alias("qty")).
Sort(ursus.Asc(ursus.Col("region")), ursus.Asc(ursus.Col("date"))))
Output: shape: (5, 3) ┌────────────┬─────────┬────────┐ │ date │ region │ qty │ │ Date │ String │ Int128 │ ├────────────┼─────────┼────────┤ │ 2026-01-05 │ "east" │ 14 │ │ 2025-12-29 │ "north" │ 17 │ │ 2026-01-05 │ "north" │ 3 │ │ 2025-12-29 │ "south" │ 4 │ │ 2026-01-05 │ "south" │ 15 │ └────────────┴─────────┴────────┘
Example (TimeIntegerIndex) ¶
readings := ursus.Frame(
ursus.Values("step", []int64{1, 2, 4, 7, 8, 12}),
ursus.Values("load", []float64{3, 5, 2, 6, 4, 7}),
)
fives := ursus.DynamicOptions{Every: ursus.Every("5i")}
show(readings.GroupByDynamic(ursus.Col("step"), fives).
Agg(ursus.Len().Alias("rows"), ursus.Col("load").Sum()))
Output: shape: (3, 3) ┌───────┬────────┬─────────┐ │ step │ rows │ load │ │ Int64 │ Uint64 │ Float64 │ ├───────┼────────┼─────────┤ │ 0 │ 3 │ 10 │ │ 5 │ 2 │ 10 │ │ 10 │ 1 │ 7 │ └───────┴────────┴─────────┘
Example (TimeParse) ¶
logs := ursus.Frame(
ursus.Values("at", []string{"2026-03-08 06:30", "2026-03-08 07:45", "oops"}),
)
utc := ursus.Datetime(ursus.Micro, "UTC")
show(logs.Select(
ursus.Col("at"),
ursus.Col("at").Str().Strptime(utc, "%Y-%m-%d %H:%M", false).Alias("instant"),
))
Output: shape: (3, 2) ┌────────────────────┬─────────────────────────────┐ │ at │ instant │ │ String │ Datetime(us, UTC) │ ├────────────────────┼─────────────────────────────┤ │ "2026-03-08 06:30" │ 2026-03-08T06:30:00.000000Z │ │ "2026-03-08 07:45" │ 2026-03-08T07:45:00.000000Z │ │ "oops" │ null │ └────────────────────┴─────────────────────────────┘
Example (TimeParts) ¶
d := ursus.Col("day").Dt()
show(days().Select(
ursus.Col("day"),
d.Year().Alias("year"),
d.Month().Alias("month"),
d.Weekday().Alias("weekday"),
d.Week().Alias("week"),
d.Quarter().Alias("quarter"),
d.OrdinalDay().Alias("day_of_year"),
d.IsLeapYear().Alias("leap"),
))
Output: shape: (3, 8) ┌────────────┬───────┬───────┬─────────┬───────┬─────────┬─────────────┬───────┐ │ day │ year │ month │ weekday │ week │ quarter │ day_of_year │ leap │ │ Date │ Int32 │ Int32 │ Int32 │ Int32 │ Int32 │ Int32 │ Bool │ ├────────────┼───────┼───────┼─────────┼───────┼─────────┼─────────────┼───────┤ │ 2024-02-29 │ 2024 │ 2 │ 4 │ 9 │ 1 │ 60 │ true │ │ 2026-01-03 │ 2026 │ 1 │ 6 │ 1 │ 1 │ 3 │ false │ │ 2026-12-31 │ 2026 │ 12 │ 4 │ 53 │ 4 │ 365 │ false │ └────────────┴───────┴───────┴─────────┴───────┴─────────┴─────────────┴───────┘
Example (TimeRanges) ¶
from := ursus.Lit(time.Date(2026, 1, 30, 0, 0, 0, 0, time.UTC)).Cast(ursus.Date)
to := ursus.Lit(time.Date(2026, 2, 2, 0, 0, 0, 0, time.UTC)).Cast(ursus.Date)
span := ursus.DateRange(from, to, ursus.Every("1d")).Alias("day")
show(ursus.Frame().Select(span))
Output: shape: (4, 1) ┌────────────┐ │ day │ │ Date │ ├────────────┤ │ 2026-01-30 │ │ 2026-01-31 │ │ 2026-02-01 │ │ 2026-02-02 │ └────────────┘
Example (TimeRolling) ¶
show(prices().
Filter(ursus.Col("ticker").Eq("ACME")).
Rolling(ursus.Col("date"), ursus.RollingOptions{Period: ursus.Every("3d")}).
Agg(ursus.Len().Alias("rows"), ursus.Col("close").Max().Alias("high_3d")))
Output: shape: (6, 3) ┌────────────┬────────┬─────────┐ │ date │ rows │ high_3d │ │ Date │ Uint64 │ Float64 │ ├────────────┼────────┼─────────┤ │ 2026-01-05 │ 1 │ 10 │ │ 2026-01-06 │ 2 │ 11 │ │ 2026-01-07 │ 3 │ 11 │ │ 2026-01-08 │ 3 │ 12 │ │ 2026-01-09 │ 3 │ 12 │ │ 2026-01-12 │ 1 │ 13.5 │ └────────────┴────────┴─────────┘
Example (TimeTruncate) ¶
date := ursus.Col("date").Dt()
show(sales().Select(
ursus.Col("date"),
date.Truncate(ursus.Every("1w")).Alias("week"),
date.Truncate(ursus.Every("1mo")).Alias("month"),
date.Strftime("%a %d %b").Alias("label"),
).Unique())
Output: shape: (5, 4) ┌────────────┬────────────┬────────────┬──────────────┐ │ date │ week │ month │ label │ │ Date │ Date │ Date │ String │ ├────────────┼────────────┼────────────┼──────────────┤ │ 2026-01-03 │ 2025-12-29 │ 2026-01-01 │ "Sat 03 Jan" │ │ 2026-01-04 │ 2025-12-29 │ 2026-01-01 │ "Sun 04 Jan" │ │ 2026-01-05 │ 2026-01-05 │ 2026-01-01 │ "Mon 05 Jan" │ │ 2026-01-06 │ 2026-01-05 │ 2026-01-01 │ "Tue 06 Jan" │ │ 2026-01-07 │ 2026-01-05 │ 2026-01-01 │ "Wed 07 Jan" │ └────────────┴────────────┴────────────┴──────────────┘
Example (TimeUpsample) ¶
show(prices().
Filter(ursus.Col("ticker").Eq("ACME")).
Upsample("date", ursus.Every("1d"), "ticker").
WithColumns(ursus.Col("close").FillNull(ursus.FillForward).Alias("filled")))
Output: shape: (8, 4) ┌────────────┬────────┬─────────┬─────────┐ │ date │ ticker │ close │ filled │ │ Date │ String │ Float64 │ Float64 │ ├────────────┼────────┼─────────┼─────────┤ │ 2026-01-05 │ "ACME" │ 10 │ 10 │ │ 2026-01-06 │ "ACME" │ 11 │ 11 │ │ 2026-01-07 │ "ACME" │ 10.5 │ 10.5 │ │ 2026-01-08 │ "ACME" │ 12 │ 12 │ │ 2026-01-09 │ "ACME" │ 12 │ 12 │ │ 2026-01-10 │ "ACME" │ null │ 12 │ │ 2026-01-11 │ "ACME" │ null │ 12 │ │ 2026-01-12 │ "ACME" │ 13.5 │ 13.5 │ └────────────┴────────┴─────────┴─────────┘
Example (TimeZones) ¶
at := []time.Time{
time.Date(2026, 3, 8, 6, 30, 0, 0, time.UTC),
time.Date(2026, 3, 8, 7, 30, 0, 0, time.UTC),
}
instants := ursus.Frame(ursus.Values("utc", at)).
Select(ursus.Col("utc").Cast(ursus.Datetime(ursus.Second, "UTC")))
show(instants.Select(
ursus.Col("utc"),
ursus.Col("utc").Dt().ConvertTimeZone("America/New_York").Alias("new_york"),
ursus.Col("utc").Dt().ReplaceTimeZone("Asia/Tokyo").Alias("same_wall_in_tokyo"),
))
Output: shape: (2, 3) ┌──────────────────────┬───────────────────────────────┬───────────────────────────┐ │ utc │ new_york │ same_wall_in_tokyo │ │ Datetime(s, UTC) │ Datetime(s, America/New_York) │ Datetime(s, Asia/Tokyo) │ ├──────────────────────┼───────────────────────────────┼───────────────────────────┤ │ 2026-03-08T06:30:00Z │ 2026-03-08T01:30:00-05:00 │ 2026-03-08T06:30:00+09:00 │ │ 2026-03-08T07:30:00Z │ 2026-03-08T03:30:00-04:00 │ 2026-03-08T07:30:00+09:00 │ └──────────────────────┴───────────────────────────────┴───────────────────────────┘
Example (TopK) ¶
df, err := sales().
TopK(3, ursus.Asc(ursus.Col("qty"))).
Select(ursus.Col("order_id"), ursus.Col("product"), ursus.Col("qty")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 3) ┌──────────┬─────────┬───────┐ │ order_id │ product │ qty │ │ Int64 │ String │ Int64 │ ├──────────┼─────────┼───────┤ │ 6 │ "apple" │ 12 │ │ 1 │ "apple" │ 10 │ │ 5 │ "fig" │ 9 │ └──────────┴─────────┴───────┘
Example (TypesCast) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
ctx := context.Background()
text := ursus.Frame(ursus.Values("n", []string{"12", "7", "seven"}))
_, err := text.Select(ursus.Col("n").Cast(ursus.Int64)).Collect(ctx)
fmt.Println(err)
df, err := text.Select(ursus.Col("n").CastLossy(ursus.Int64)).Collect(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: ursus: cast: cannot parse "seven" as Int64 at row 2 use CastLossy to turn unparseable values into nulls instead shape: (3, 1) ┌───────┐ │ n │ │ Int64 │ ├───────┤ │ 12 │ │ 7 │ │ null │ └───────┘
Example (TypesFrameCast) ¶
lines := sales().
Select(ursus.Col("order_id"), ursus.Col("qty"), ursus.Col("price")).
Head(2)
show(lines.Cast(map[string]ursus.DataType{
"qty": ursus.Int32,
"price": ursus.Float32,
}))
show(lines.CastTypes(map[ursus.DataType]ursus.DataType{ursus.Int64: ursus.Int16}))
show(lines.Select(ursus.Col("price").Truncate(0).Cast(ursus.Int64)))
Output: shape: (2, 3) ┌──────────┬───────┬─────────┐ │ order_id │ qty │ price │ │ Int64 │ Int32 │ Float32 │ ├──────────┼───────┼─────────┤ │ 1 │ 10 │ 1.5 │ │ 2 │ 4 │ 1.5 │ └──────────┴───────┴─────────┘ shape: (2, 3) ┌──────────┬───────┬─────────┐ │ order_id │ qty │ price │ │ Int16 │ Int16 │ Float64 │ ├──────────┼───────┼─────────┤ │ 1 │ 10 │ 1.5 │ │ 2 │ 4 │ 1.5 │ └──────────┴───────┴─────────┘ shape: (2, 1) ┌───────┐ │ price │ │ Int64 │ ├───────┤ │ 1 │ │ 1 │ └───────┘
Example (TypesMatchToSchema) ¶
want := ursus.MustSchema(
ursus.Of("order_id", ursus.Int64),
ursus.Of("qty", ursus.Int64),
ursus.Of("discount", ursus.Float64),
)
drifted := sales().Head(2).Select(
ursus.Col("qty").Cast(ursus.Int32), ursus.Col("order_id"), ursus.Col("product"))
_, err := drifted.
MatchToSchema(want, ursus.MatchOptions{}).
Collect(context.Background())
fmt.Println(err)
show(drifted.MatchToSchema(want, ursus.MatchOptions{
MissingColumns: ursus.MatchInsert,
ExtraColumns: ursus.MatchIgnore,
IntegerCast: ursus.MatchUpcast,
}))
Output: ursus: match_to_schema: qty is Int32, and the schema's is Int64 MatchOptions{IntegerCast: ursus.MatchUpcast} widens it shape: (2, 3) ┌──────────┬───────┬──────────┐ │ order_id │ qty │ discount │ │ Int64 │ Int64 │ Float64 │ ├──────────┼───────┼──────────┤ │ 1 │ 10 │ null │ │ 2 │ 4 │ null │ └──────────┴───────┴──────────┘
Example (TypesNaN) ¶
package main
import (
"context"
"fmt"
"log"
"math"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.ValuesNullable("x",
[]float64{1, math.NaN(), 0},
[]bool{true, true, false}),
).Select(
ursus.Col("x"),
ursus.Col("x").IsNull().Alias("is_null"),
ursus.Col("x").IsNan().Alias("is_nan"),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (3, 3) ┌─────────┬─────────┬────────┐ │ x │ is_null │ is_nan │ │ Float64 │ Bool │ Bool │ ├─────────┼─────────┼────────┤ │ 1 │ false │ false │ │ NaN │ false │ true │ │ null │ true │ null │ └─────────┴─────────┴────────┘
Example (TypesNulls) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
df, err := ursus.Frame(
ursus.ValuesNullable("score", []float64{4, 0, 8}, []bool{true, false, true}),
).Select(
ursus.Len().Alias("rows"),
ursus.Col("score").Count().Alias("count"),
ursus.Col("score").NullCount().Alias("nulls"),
ursus.Col("score").Mean().Alias("mean"),
ursus.Col("score").FillNullWith(0.0).Mean().Alias("mean_as_zero"),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (1, 5) ┌────────┬────────┬────────┬─────────┬──────────────┐ │ rows │ count │ nulls │ mean │ mean_as_zero │ │ Uint64 │ Uint64 │ Uint64 │ Float64 │ Float64 │ ├────────┼────────┼────────┼─────────┼──────────────┤ │ 3 │ 2 │ 1 │ 6 │ 4 │ └────────┴────────┴────────┴─────────┴──────────────┘
Example (TypesSchema) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// sales is the CSV the concept pages read, its date column a Date.
func sales() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/sales.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
df, err := sales().Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df.Schema())
}
Output: {order_id: Int64, date: Date, region: String, product: String, qty: Int64, price: Float64}
Example (UdfBatches) ¶
orZero := ursus.Col("temp").MapBatches("or_zero", ursus.Float64,
func(vals []float64, valid []bool) ([]float64, []bool, error) {
out, ok := make([]float64, len(vals)), make([]bool, len(vals))
for i := range vals {
if valid[i] {
out[i] = vals[i]
}
ok[i] = true // a null becomes 0, a value of its own
}
return out, ok, nil
})
show(readings().Select(ursus.Col("temp"), orZero.Alias("or_zero")))
Output: shape: (6, 2) ┌─────────┬─────────┐ │ temp │ or_zero │ │ Float64 │ Float64 │ ├─────────┼─────────┤ │ 10 │ 10 │ │ null │ 0 │ │ null │ 0 │ │ 13 │ 13 │ │ 12 │ 12 │ │ null │ 0 │ └─────────┴─────────┘
Example (UdfElements) ¶
slug := ursus.Col("product").MapElements("slug", ursus.String,
func(s string) (string, error) {
return strings.ToUpper(s[:1]) + "-" + fmt.Sprint(len(s)), nil
})
show(sales().Head(3).Select(ursus.Col("product"), slug.Alias("slug")))
Output: shape: (3, 2) ┌─────────┬────────┐ │ product │ slug │ │ String │ String │ ├─────────┼────────┤ │ "apple" │ "A-5" │ │ "apple" │ "A-5" │ │ "pear" │ "P-4" │ └─────────┴────────┘
Example (UdfError) ¶
dozens := ursus.Col("qty").MapElements("dozens", ursus.Float64,
func(q int64) (float64, error) {
if q > 10 {
return 0, errors.New("more than ten is a wholesale order")
}
return float64(q) / 12, nil
})
_, err := sales().Select(dozens).Collect(context.Background())
fmt.Println(err)
Output: ursus: map_elements: udf "dozens" failed on 12, row 5 of its batch of column "qty" caused by: more than ten is a wholesale order
Example (UdfExplain) ¶
slug := ursus.Col("product").MapElements("slug", ursus.String,
func(s string) (string, error) { return strings.ToUpper(s), nil })
plan, err := sales().
Filter(ursus.Col("qty").Gt(5)).
Select(slug).
Explain(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(plan)
Output: PROJECT [col("product").map_elements("slug" -> String)] FILTER [(col("qty") > lit(5))] CSV SCAN testdata/sales.csv projection: [product, qty] (2/6 cols)
Example (UdfNulls) ¶
var calls atomic.Int64
double := ursus.Col("temp").MapElements("double", ursus.Float64,
func(t float64) (float64, error) {
calls.Add(1)
return 2 * t, nil
})
show(readings().Select(ursus.Col("temp"), double.Alias("doubled")))
fmt.Println("calls:", calls.Load())
Output: shape: (6, 2) ┌─────────┬─────────┐ │ temp │ doubled │ │ Float64 │ Float64 │ ├─────────┼─────────┤ │ 10 │ 20 │ │ null │ null │ │ null │ null │ │ 13 │ 26 │ │ 12 │ 24 │ │ null │ null │ └─────────┴─────────┘ calls: 3
Example (UdfTypes) ¶
band := ursus.Col("qty").MapElements("band", ursus.String,
func(q int64) (string, error) {
switch {
case q >= 10:
return "large", nil
case q >= 5:
return "medium", nil
}
return "small", nil
})
show(sales().
GroupBy(band.Alias("band")).
Agg(ursus.Len().Alias("orders")).
Sort(ursus.Asc(ursus.Col("band"))))
Output: shape: (3, 2) ┌──────────┬────────┐ │ band │ orders │ │ String │ Uint64 │ ├──────────┼────────┤ │ "large" │ 2 │ │ "medium" │ 3 │ │ "small" │ 3 │ └──────────┴────────┘
Example (Unique) ¶
df, err := sales().
Unique("region").
Select(ursus.Col("region"), ursus.Col("order_id")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 2) ┌─────────┬──────────┐ │ region │ order_id │ │ String │ Int64 │ ├─────────┼──────────┤ │ "north" │ 1 │ │ "south" │ 2 │ │ "east" │ 4 │ └─────────┴──────────┘
Example (UniqueKeepLast) ¶
df, err := sales().
UniqueKeep(ursus.KeepLast, "region").
Select(ursus.Col("region"), ursus.Col("order_id")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 2) ┌─────────┬──────────┐ │ region │ order_id │ │ String │ Int64 │ ├─────────┼──────────┤ │ "east" │ 6 │ │ "north" │ 7 │ │ "south" │ 8 │ └─────────┴──────────┘
Example (WhereExists) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// customers and orders are the joins chapter's frames: customer 2 has no order, and
// order 13's customer, 5, is no customer.
func customers() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("customer_id", []int64{1, 2, 3, 4}),
ursus.Values("name", []string{"Ada", "Ben", "Cai", "Dee"}),
)
}
func orders() *ursus.LazyFrame {
return ursus.Frame(
ursus.Values("order", []int64{10, 11, 12, 13, 14}),
ursus.Values("customer_id", []int64{1, 3, 1, 5, 4}),
ursus.Values("amount", []float64{25, 40, 10, 99, 15}),
)
}
// show collects a query and prints it.
func show(lf *ursus.LazyFrame) {
df, err := lf.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
func main() {
show(customers().WhereExists(orders(),
ursus.Col("customer_id").Eq(ursus.Col("customer_id_right")),
ursus.Col("amount").Gt(20.0)))
}
Output: shape: (2, 2) ┌─────────────┬────────┐ │ customer_id │ name │ │ Int64 │ String │ ├─────────────┼────────┤ │ 1 │ "Ada" │ │ 3 │ "Cai" │ └─────────────┴────────┘
Example (WindowCumulative) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// prices is the windows chapter's series: two tickers' closes over six trading days,
// a weekend between the fifth and the sixth.
func prices() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/prices.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
byTicker := ursus.WindowSpec{
PartitionBy: []ursus.Expr{ursus.Col("ticker")},
OrderBy: []ursus.SortKey{ursus.Asc(ursus.Col("date"))},
}
df, err := prices().
WithColumns(
ursus.Col("close").CumMax(false).OverWith(byTicker).Alias("high"),
ursus.Col("close").CumCount(false).OverWith(byTicker).Alias("day"),
).
Filter(ursus.Col("ticker").Eq("ACME")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (6, 5) ┌────────────┬────────┬─────────┬─────────┬────────┐ │ date │ ticker │ close │ high │ day │ │ Date │ String │ Float64 │ Float64 │ Uint32 │ ├────────────┼────────┼─────────┼─────────┼────────┤ │ 2026-01-05 │ "ACME" │ 10 │ 10 │ 1 │ │ 2026-01-06 │ "ACME" │ 11 │ 11 │ 2 │ │ 2026-01-07 │ "ACME" │ 10.5 │ 11 │ 3 │ │ 2026-01-08 │ "ACME" │ 12 │ 12 │ 4 │ │ 2026-01-09 │ "ACME" │ 12 │ 12 │ 5 │ │ 2026-01-12 │ "ACME" │ 13.5 │ 13.5 │ 6 │ └────────────┴────────┴─────────┴─────────┴────────┘
Example (WindowEwm) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// prices is the windows chapter's series: two tickers' closes over six trading days,
// a weekend between the fifth and the sixth.
func prices() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/prices.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
t, c := ursus.Col("ticker"), ursus.Col("close")
df, err := prices().
WithColumns(
c.EwmMean(ursus.EwmAlpha(0.5)).Over(t).Round(4).Alias("ewm"),
c.EwmMean(ursus.EwmAlpha(0.5), ursus.EwmAdjust(false)).Over(t).Round(4).
Alias("ewm_unadjusted"),
).
Filter(t.Eq("ACME")).
Drop("ticker").
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (6, 4) ┌────────────┬─────────┬─────────┬────────────────┐ │ date │ close │ ewm │ ewm_unadjusted │ │ Date │ Float64 │ Float64 │ Float64 │ ├────────────┼─────────┼─────────┼────────────────┤ │ 2026-01-05 │ 10 │ 10 │ 10 │ │ 2026-01-06 │ 11 │ 10.6667 │ 10.5 │ │ 2026-01-07 │ 10.5 │ 10.5714 │ 10.5 │ │ 2026-01-08 │ 12 │ 11.3333 │ 11.25 │ │ 2026-01-09 │ 12 │ 11.6774 │ 11.625 │ │ 2026-01-12 │ 13.5 │ 12.6032 │ 12.5625 │ └────────────┴─────────┴─────────┴────────────────┘
Example (WindowOver) ¶
qty, region := ursus.Col("qty"), ursus.Col("region")
df, err := sales().
Select(
ursus.Col("order_id"),
region,
qty,
qty.Sum().Over(region).Alias("region_qty"),
qty.Div(qty.Sum().Over(region)).Round(2).Alias("share"),
qty.Sum().Over().Alias("all_qty"),
).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (8, 6) ┌──────────┬─────────┬───────┬────────────┬─────────┬─────────┐ │ order_id │ region │ qty │ region_qty │ share │ all_qty │ │ Int64 │ String │ Int64 │ Int128 │ Float64 │ Int128 │ ├──────────┼─────────┼───────┼────────────┼─────────┼─────────┤ │ 1 │ "north" │ 10 │ 20 │ 0.5 │ 53 │ │ 2 │ "south" │ 4 │ 19 │ 0.21 │ 53 │ │ 3 │ "north" │ 7 │ 20 │ 0.35 │ 53 │ │ 4 │ "east" │ 2 │ 14 │ 0.14 │ 53 │ │ 5 │ "south" │ 9 │ 19 │ 0.47 │ 53 │ │ 6 │ "east" │ 12 │ 14 │ 0.86 │ 53 │ │ 7 │ "north" │ 3 │ 20 │ 0.15 │ 53 │ │ 8 │ "south" │ 6 │ 19 │ 0.32 │ 53 │ └──────────┴─────────┴───────┴────────────┴─────────┴─────────┘
Example (WindowRank) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
func main() {
x := ursus.Col("points")
df, err := ursus.Frame(
ursus.Values("team", []string{"a", "b", "c", "d", "e"}),
ursus.Values("points", []int64{7, 9, 7, 3, 9}),
).WithColumns(
x.Rank(ursus.RankOrdinal, true).Alias("ordinal"),
x.Rank(ursus.RankMin, true).Alias("min"),
x.Rank(ursus.RankMax, true).Alias("max"),
x.Rank(ursus.RankDense, true).Alias("dense"),
x.Rank(ursus.RankAverage, true).Alias("average"),
).Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (5, 7) ┌────────┬────────┬─────────┬────────┬────────┬────────┬─────────┐ │ team │ points │ ordinal │ min │ max │ dense │ average │ │ String │ Int64 │ Uint32 │ Uint32 │ Uint32 │ Uint32 │ Float64 │ ├────────┼────────┼─────────┼────────┼────────┼────────┼─────────┤ │ "a" │ 7 │ 3 │ 3 │ 4 │ 2 │ 3.5 │ │ "b" │ 9 │ 1 │ 1 │ 2 │ 1 │ 1.5 │ │ "c" │ 7 │ 4 │ 3 │ 4 │ 2 │ 3.5 │ │ "d" │ 3 │ 5 │ 5 │ 5 │ 3 │ 5 │ │ "e" │ 9 │ 2 │ 1 │ 2 │ 1 │ 1.5 │ └────────┴────────┴─────────┴────────┴────────┴────────┴─────────┘
Example (WindowRolling) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// prices is the windows chapter's series: two tickers' closes over six trading days,
// a weekend between the fifth and the sixth.
func prices() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/prices.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
t, c := ursus.Col("ticker"), ursus.Col("close")
df, err := prices().
WithColumns(
c.RollingMean(3).Over(t).Alias("mean3"),
c.RollingMean(3, ursus.MinSamples(1)).Over(t).Alias("mean3_min1"),
c.RollingMax(3, ursus.RollingCenter()).Over(t).Alias("max3_centred"),
).
Filter(t.Eq("ACME")).
Drop("ticker").
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (6, 5) ┌────────────┬─────────┬────────────────────┬────────────────────┬──────────────┐ │ date │ close │ mean3 │ mean3_min1 │ max3_centred │ │ Date │ Float64 │ Float64 │ Float64 │ Float64 │ ├────────────┼─────────┼────────────────────┼────────────────────┼──────────────┤ │ 2026-01-05 │ 10 │ null │ 10 │ null │ │ 2026-01-06 │ 11 │ null │ 10.5 │ 11 │ │ 2026-01-07 │ 10.5 │ 10.5 │ 10.5 │ 12 │ │ 2026-01-08 │ 12 │ 11.166666666666666 │ 11.166666666666666 │ 12 │ │ 2026-01-09 │ 12 │ 11.5 │ 11.5 │ 13.5 │ │ 2026-01-12 │ 13.5 │ 12.5 │ 12.5 │ null │ └────────────┴─────────┴────────────────────┴────────────────────┴──────────────┘
Example (WindowRollingBy) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// prices is the windows chapter's series: two tickers' closes over six trading days,
// a weekend between the fifth and the sixth.
func prices() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/prices.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
t, c := ursus.Col("ticker"), ursus.Col("close")
df, err := prices().
WithColumns(
c.RollingSum(3, ursus.MinSamples(1)).Over(t).Alias("last_3_rows"),
c.RollingSumBy(ursus.Col("date"), ursus.Every("3d")).Over(t).
Alias("last_3_days"),
).
Filter(t.Eq("ACME")).
Drop("ticker").
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (6, 4) ┌────────────┬─────────┬─────────────┬─────────────┐ │ date │ close │ last_3_rows │ last_3_days │ │ Date │ Float64 │ Float64 │ Float64 │ ├────────────┼─────────┼─────────────┼─────────────┤ │ 2026-01-05 │ 10 │ 10 │ 10 │ │ 2026-01-06 │ 11 │ 21 │ 21 │ │ 2026-01-07 │ 10.5 │ 31.5 │ 31.5 │ │ 2026-01-08 │ 12 │ 33.5 │ 33.5 │ │ 2026-01-09 │ 12 │ 34.5 │ 34.5 │ │ 2026-01-12 │ 13.5 │ 37.5 │ 13.5 │ └────────────┴─────────┴─────────────┴─────────────┘
Example (WindowShift) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/advenn/ursus"
)
// prices is the windows chapter's series: two tickers' closes over six trading days,
// a weekend between the fifth and the sixth.
func prices() *ursus.LazyFrame {
return ursus.ScanCSV("testdata/prices.csv",
ursus.WithSchemaOverrides(map[string]ursus.DataType{"date": ursus.Date}))
}
func main() {
t := ursus.Col("ticker")
df, err := prices().
WithColumns(
ursus.Col("close").Shift(1).Over(t).Alias("previous"),
ursus.Col("close").Diff(1).Over(t).Alias("change"),
ursus.Col("close").PctChange(1).Over(t).Round(3).Alias("pct"),
).
Filter(t.Eq("BOLT")).
Drop("ticker").
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
}
Output: shape: (6, 5) ┌────────────┬─────────┬──────────┬─────────┬─────────┐ │ date │ close │ previous │ change │ pct │ │ Date │ Float64 │ Float64 │ Float64 │ Float64 │ ├────────────┼─────────┼──────────┼─────────┼─────────┤ │ 2026-01-05 │ 20 │ null │ null │ null │ │ 2026-01-06 │ 19 │ 20 │ -1 │ -0.05 │ │ 2026-01-07 │ 21 │ 19 │ 2 │ 0.105 │ │ 2026-01-08 │ 21 │ 21 │ 0 │ 0 │ │ 2026-01-09 │ 22 │ 21 │ 1 │ 0.048 │ │ 2026-01-12 │ 20 │ 22 │ -2 │ -0.091 │ └────────────┴─────────┴──────────┴─────────┴─────────┘
Example (WithRowIndex) ¶
df, err := sales().
Filter(ursus.Col("region").Eq("south")).
WithRowIndex("n", 1).
Select(ursus.Col("n"), ursus.Col("order_id"), ursus.Col("product")).
Collect(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(df)
Output: shape: (3, 3) ┌────────┬──────────┬─────────┐ │ n │ order_id │ product │ │ Uint32 │ Int64 │ String │ ├────────┼──────────┼─────────┤ │ 1 │ 2 │ "apple" │ │ 2 │ 5 │ "fig" │ │ 3 │ 8 │ "pear" │ └────────┴──────────┴─────────┘
Click to show internal directories.
Click to hide internal directories.