Tidy-TS Logo

Tidy-TS

Data analytics framework

Type-safe data analytics and statistics in TypeScript. Research shows that static typing can prevent 15–38% of production bugs1,2,3. Designed for modern data science workflows.

Type-Safe Data Operations
Perform DataFrame operations with full TypeScript support

Create, transform, filter, select, and sort data with chaining and automatic column typing for compile-time safety.

Learn More
Statistical Analysis
A comprehensive toolkit for statistical analysis

80+ functions across descriptive statistics, hypothesis testing, and probability distributions. All tests are rigorously validated against results from R.

Learn More

See Tidy-TS in Action

A complete data analysis workflow, broken into focused examples

Create DataFrames
Learn More
Create DataFrames from arrays of objects with automatic type inference
import { createDataFrame } from "@tidy-ts/dataframe";

// 🚀 Load character data from the galaxy
const characters = createDataFrame([
  { name: "Luke", species: "Human", mass_kg: 77, height_cm: 172 },
  { name: "Leia", species: "Human", mass_kg: 49, height_cm: 150 },
  { name: "C-3PO", species: "Droid", mass_kg: 75, height_cm: 167 },
  { name: "R2-D2", species: "Droid", mass_kg: 32, height_cm: 96 },
]);

characters.print();

// Output:
// ┌───────┬────────┬─────────┬───────────┐
// │ name  │ species│ mass_kg │ height_cm │
// ├───────┼────────┼─────────┼───────────┤
// │ Luke  │ Human  │ 77      │ 172       │
// │ Leia  │ Human  │ 49      │ 150       │
// │ C-3PO │ Droid  │ 75      │ 167       │
// │ R2-D2 │ Droid  │ 32      │ 96        │
// └───────┴────────┴─────────┴───────────┘
import { createDataFrame } from "@tidy-ts/dataframe";

// 🚀 Load character data from the galaxy
const characters = createDataFrame([
  { name: "Luke", species: "Human", mass_kg: 77, height_cm: 172 },
  { name: "Leia", species: "Human", mass_kg: 49, height_cm: 150 },
  { name: "C-3PO", species: "Droid", mass_kg: 75, height_cm: 167 },
  { name: "R2-D2", species: "Droid", mass_kg: 32, height_cm: 96 },
]);

characters.print();

// Output:
// ┌───────┬────────┬─────────┬───────────┐
// │ name  │ species│ mass_kg │ height_cm │
// ├───────┼────────┼─────────┼───────────┤
// │ Luke  │ Human  │ 77      │ 172       │
// │ Leia  │ Human  │ 49      │ 150       │
// │ C-3PO │ Droid  │ 75      │ 167       │
// │ R2-D2 │ Droid  │ 32      │ 96        │
// └───────┴────────┴─────────┴───────────┘
Transform Data
Learn More
Add calculated columns using `mutate()` with access to row values, index, and full DataFrame context
// 🔧 Transform data with calculated columns
const analysis = characters
  .mutate({
    mass_lbs: (row) => row.mass_kg * 2.20462,  // Convert to pounds
    height_in: (row) => row.height_cm / 2.54,  // Convert to inches
    bmi: (row) => row.mass_kg / ((row.height_cm / 100) ** 2),  // Body Mass Index
  })
  .select("name", "mass_lbs", "height_in", "bmi");

analysis.print("Character Analysis with Calculations");

// Output:
// Character Analysis with Calculations
// ┌───────┬──────────┬───────────┬─────────┐
// │ name  │ mass_lbs │ height_in │ bmi     │
// ├───────┼──────────┼───────────┼─────────┤
// │ Luke  │ 169.76   │ 67.72     │ 26.03   │
// │ Leia  │ 108.03   │ 59.06     │ 21.78   │
// │ C-3PO │ 165.35   │ 65.75     │ 26.89   │
// │ R2-D2 │ 70.55    │ 37.80     │ 34.72   │
// └───────┴──────────┴───────────┴─────────┘
// 🔧 Transform data with calculated columns
const analysis = characters
  .mutate({
    mass_lbs: (row) => row.mass_kg * 2.20462,  // Convert to pounds
    height_in: (row) => row.height_cm / 2.54,  // Convert to inches
    bmi: (row) => row.mass_kg / ((row.height_cm / 100) ** 2),  // Body Mass Index
  })
  .select("name", "mass_lbs", "height_in", "bmi");

analysis.print("Character Analysis with Calculations");

// Output:
// Character Analysis with Calculations
// ┌───────┬──────────┬───────────┬─────────┐
// │ name  │ mass_lbs │ height_in │ bmi     │
// ├───────┼──────────┼───────────┼─────────┤
// │ Luke  │ 169.76   │ 67.72     │ 26.03   │
// │ Leia  │ 108.03   │ 59.06     │ 21.78   │
// │ C-3PO │ 165.35   │ 65.75     │ 26.89   │
// │ R2-D2 │ 70.55    │ 37.80     │ 34.72   │
// └───────┴──────────┴───────────┴─────────┘
Group and Summarize
Learn More
Group data by categories and calculate summary statistics with groupBy() and summarize()
import { stats as s } from "@tidy-ts/dataframe";

// 📊 Group by species and calculate statistics
const summary = analysis
  .groupBy("species")
  .summarize({
    avg_mass_lbs: (group) => s.mean(group.mass_lbs),
    avg_height_in: (group) => s.mean(group.height_in),
    count: (group) => group.nrows(),
  })
  .arrange("avg_mass_lbs", "desc");

summary.print("Species Comparison Report");

// Output:
// Species Comparison Report
// ┌────────┬───────────────┬───────────────┬───────┐
// │ species│ avg_mass_lbs  │ avg_height_in │ count │
// ├────────┼───────────────┼───────────────┼───────┤
// │ Human  │ 138.90        │ 63.39         │ 2     │
// │ Droid  │ 117.95        │ 51.78         │ 2     │
// └────────┴───────────────┴───────────────┴───────┘
import { stats as s } from "@tidy-ts/dataframe";

// 📊 Group by species and calculate statistics
const summary = analysis
  .groupBy("species")
  .summarize({
    avg_mass_lbs: (group) => s.mean(group.mass_lbs),
    avg_height_in: (group) => s.mean(group.height_in),
    count: (group) => group.nrows(),
  })
  .arrange("avg_mass_lbs", "desc");

summary.print("Species Comparison Report");

// Output:
// Species Comparison Report
// ┌────────┬───────────────┬───────────────┬───────┐
// │ species│ avg_mass_lbs  │ avg_height_in │ count │
// ├────────┼───────────────┼───────────────┼───────┤
// │ Human  │ 138.90        │ 63.39         │ 2     │
// │ Droid  │ 117.95        │ 51.78         │ 2     │
// └────────┴───────────────┴───────────────┴───────┘
Statistical Tests
Learn More
Perform hypothesis testing and correlation analysis using the `stats` module
// Test 1: Are droid proportions (suspiciously?) similar to human proportions?
const humans = analysis.filter((r) => r.species === "Human");
const droids = analysis.filter((r) => r.species === "Droid");

const bmiTest = s.compare.twoGroups.centralTendency.toEachOther({
  x: humans.bmi,
  y: droids.bmi,
  parametric: "auto", // Auto-detects appropriate test
});

console.log(`Droid conspiracy? Test: ${bmiTest.test_name}, p-value: ${s.round(bmiTest.p_value, 3)}`);

// Output:
// Droid conspiracy? Test: Independent T-Test, p-value: 0.261

// Test 2: Are height and mass correlated among all characters?
const heightMassTest = s.compare.twoGroups.association.toEachOther({
  x: analysis.height_cm,
  y: analysis.mass_kg,
  method: "auto", // Selects best choice between Pearson, Spearman, or Kendall
});

console.log(`Height and mass correlation? 
Test: ${heightMassTest.test_name}
${heightMassTest.effect_size.name}: ${s.round(heightMassTest.effect_size.value, 3)}
p-value: ${s.round(heightMassTest.p_value, 3)}`);


// Output:
// Height and mass correlation? 
// Test: Kendall's rank correlation tau
// Kendall's Tau: 1
// p-value: 0.083
// Test 1: Are droid proportions (suspiciously?) similar to human proportions?
const humans = analysis.filter((r) => r.species === "Human");
const droids = analysis.filter((r) => r.species === "Droid");

const bmiTest = s.compare.twoGroups.centralTendency.toEachOther({
  x: humans.bmi,
  y: droids.bmi,
  parametric: "auto", // Auto-detects appropriate test
});

console.log(`Droid conspiracy? Test: ${bmiTest.test_name}, p-value: ${s.round(bmiTest.p_value, 3)}`);

// Output:
// Droid conspiracy? Test: Independent T-Test, p-value: 0.261

// Test 2: Are height and mass correlated among all characters?
const heightMassTest = s.compare.twoGroups.association.toEachOther({
  x: analysis.height_cm,
  y: analysis.mass_kg,
  method: "auto", // Selects best choice between Pearson, Spearman, or Kendall
});

console.log(`Height and mass correlation? 
Test: ${heightMassTest.test_name}
${heightMassTest.effect_size.name}: ${s.round(heightMassTest.effect_size.value, 3)}
p-value: ${s.round(heightMassTest.p_value, 3)}`);


// Output:
// Height and mass correlation? 
// Test: Kendall's rank correlation tau
// Kendall's Tau: 1
// p-value: 0.083

Proven Bug Prevention

Empirical research shows that static typing significantly reduces production bugs

38%
Production Bugs Preventable

Research-Backed Type Safety

Evidence suggests that static typing prevents 15-38% of bugs that would otherwise reach production. These are conservative estimates focusing on publicly visible, type-related defects.

Note: These figures represent lower bounds, excluding pre-commit logic issues and data validation bugs.

Ready to get started?

Start building data analytics workflows with type safety.