The GroupBy engine lets you split a DataFrame (or Series)
into groups, apply an aggregation or transformation to each group, and
combine the results — mirroring
pandas.DataFrame.groupby().
Edit any code block below and press ▶ Run
(or Ctrl+Enter) to execute it live in your browser.
Group by a single column and aggregate with a built-in function. sum() only includes numeric columns.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, 5],
});
const result = df.groupby("dept").sum();
console.log(result.toString());
Click ▶ Run to execute
Built-in aggregation shorthands. mean() only includes numeric columns; min()/max() work on all value columns.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
team: ["X", "X", "Y", "Y", "Z"],
points: [10, 20, 30, 40, 50],
fouls: [2, 4, 1, 3, 5],
});
console.log("=== mean() ===");
console.log(df.groupby("team").mean().toString());
console.log("\n=== min() ===");
console.log(df.groupby("team").min().toString());
console.log("\n=== max() ===");
console.log(df.groupby("team").max().toString());
Click ▶ Run to execute
Count non-null values per group and column. Missing values are excluded from the count.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "B"],
score: [90, null, 80, 70, null],
rating: [5, 4, null, 3, 2],
});
const counts = df.groupby("dept").count();
console.log(counts.toString());
Click ▶ Run to execute
Sample standard deviation per group — numeric columns only (like pandas). Groups with fewer than 2 values return NaN.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
group: ["A", "A", "A", "B", "B", "C"],
value: [10, 20, 30, 100, 200, 42],
});
const result = df.groupby("group").std();
console.log(result.toString());
// Group C has only 1 row → std is NaN
Click ▶ Run to execute
Return the first or last non-null value per group for each column.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "A", "B", "B"],
sales: [null, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, null],
});
console.log("=== first() ===");
console.log(df.groupby("dept").first().toString());
console.log("\n=== last() ===");
console.log(df.groupby("dept").last().toString());
Click ▶ Run to execute
Inspect the structure of the groups. size() returns a Series with the count of rows per group (including nulls).
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
});
const gb = df.groupby("dept");
console.log("ngroups:", gb.ngroups);
console.log("groupKeys:", gb.groupKeys);
console.log("\nsize():");
console.log(gb.size().toString());
Click ▶ Run to execute
Apply different aggregation functions to different columns using an object spec, or pass a custom function.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, 5],
});
// Per-column named specs
console.log("=== per-column specs ===");
const result = df.groupby("dept").agg({
sales: "sum",
bonus: "mean",
});
console.log(result.toString());
// Custom function: range = max − min
console.log("\n=== custom agg (range) ===");
const range = df.groupby("dept").agg((vals) => {
const nums = vals.filter((v) => typeof v === "number");
if (nums.length === 0) return 0;
return Math.max(...nums) - Math.min(...nums);
});
console.log(range.toString());
Click ▶ Run to execute
Unlike agg(), transform() returns a same-shape DataFrame.
Useful for broadcasting group statistics back to the original rows.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, 5],
});
// Subtract group mean (demeaning)
const demeaned = df.groupby("dept").transform((vals, col) => {
if (col === "dept") return vals;
const nums = vals.filter((v) => typeof v === "number");
const mean = nums.reduce((a, b) => a + b, 0) / nums.length;
return vals.map((v) => (typeof v === "number" ? v - mean : v));
});
console.log(demeaned.toString());
Click ▶ Run to execute
Run arbitrary logic on each sub-DataFrame and concatenate the results vertically.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, 5],
});
// Keep only the top-sales row from each dept
const topRows = df.groupby("dept").apply((sub) =>
sub.sortValues("sales", false).head(1),
);
console.log(topRows.toString());
Click ▶ Run to execute
Keep only the rows belonging to groups that pass a predicate.
import { DataFrame } from "tsb";
const df = DataFrame.fromColumns({
dept: ["A", "A", "B", "B", "C"],
sales: [10, 20, 30, 40, 50],
bonus: [1, 2, 3, 4, 5],
});
// Keep only groups with more than 1 row
const big = df.groupby("dept").filter((sub) => sub.shape[0] > 1);
console.log("Groups with > 1 row (C dropped):");
console.log(big.toString());
Click ▶ Run to execute
Write your own GroupBy code below. All exports from tsb are available:
DataFrame, Series, Index, and more.
import { DataFrame, Series } from "tsb";
// Try it! Build a DataFrame and explore the GroupBy API.
const sales = DataFrame.fromColumns({
region: ["East", "East", "West", "West", "East"],
quarter: [1, 2, 1, 2, 1],
revenue: [100, 150, 200, 250, 120],
});
console.log("Revenue by region:");
console.log(sales.groupby("region").sum().toString());
console.log("\nAverage revenue by region:");
console.log(sales.groupby("region").mean().toString());
console.log("\nGroup sizes:");
console.log(sales.groupby("region").size().toString());
Click ▶ Run to execute