Initializing playground…
← Back to roadmap

🔀 GroupBy — Interactive Playground

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.

1 · Basic groupby + sum()

Group by a single column and aggregate with a built-in function. sum() only includes numeric columns.

TypeScript
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
Ctrl+Enter to run

2 · mean(), min(), max()

Built-in aggregation shorthands. mean() only includes numeric columns; min()/max() work on all value columns.

TypeScript
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
Ctrl+Enter to run

3 · count()

Count non-null values per group and column. Missing values are excluded from the count.

TypeScript
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
Ctrl+Enter to run

4 · std()

Sample standard deviation per group — numeric columns only (like pandas). Groups with fewer than 2 values return NaN.

TypeScript
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
Ctrl+Enter to run

5 · first() / last()

Return the first or last non-null value per group for each column.

TypeScript
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
Ctrl+Enter to run

6 · size(), ngroups, groupKeys

Inspect the structure of the groups. size() returns a Series with the count of rows per group (including nulls).

TypeScript
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
Ctrl+Enter to run

7 · agg() with named specs

Apply different aggregation functions to different columns using an object spec, or pass a custom function.

TypeScript
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
Ctrl+Enter to run

8 · transform()

Unlike agg(), transform() returns a same-shape DataFrame. Useful for broadcasting group statistics back to the original rows.

TypeScript
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
Ctrl+Enter to run

9 · apply()

Run arbitrary logic on each sub-DataFrame and concatenate the results vertically.

TypeScript
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
Ctrl+Enter to run

10 · filter()

Keep only the rows belonging to groups that pass a predicate.

TypeScript
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
Ctrl+Enter to run

🧪 Scratch Pad

Write your own GroupBy code below. All exports from tsb are available: DataFrame, Series, Index, and more.

TypeScript — Scratch Pad
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
Ctrl+Enter to run