Esc
Start typing to search...

Table Module

Cross-tabulation and summary tables from DataFrames.

Inspired by Stata's table command, with idiomatic Keel syntax (pipes, data-last, builder pattern).

Quick forms

import Table
import DataFrame

let df = DataFrame.readCsv "data.csv"

-- One-way frequency table
df |> Table.freq "sex"

-- Two-way cross-tabulation
df |> Table.cross "sex" "highbp"

Builder pattern

df
    |> Table.create
    |> Table.rows ["sex"]
    |> Table.cols ["highbp"]
    |> Table.count
    |> Table.meanOf "age"
    |> Table.show

Nesting vs adjacency

  • Multiple vars in one call = nested hierarchy: Table.rows ["sex", "race"]
  • Multiple calls = adjacent sections: Table.cols ["sex"] |> Table.cols ["race"]

Statistics

FunctionDescription
countFrequency count (default if none specified)
percentPercentage of total
meanOf vMean of variable
stdOf vStandard deviation
medianOf vMedian
minOf v / maxOf vMin / Max
sumOf vSum

Layout

Tables separate data from layout. Use Table.relayout to rearrange dimensions without recomputing statistics. Use Table.toDataFrame to convert to a flat DataFrame for further analysis.

Functions

Table.cols

[DataFrameColumn] -> TableSpec -> TableSpec

Add column dimension variables.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", bp = "high" }, { sex = "F", bp = "low" }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.cols [@bp]
    |> Table.show
Try it

Notes: Multiple calls create adjacent column groups. Multiple vars in one call create nested hierarchy.

See also: Table.rows, Table.create

Table.count

TableSpec -> TableSpec

Add frequency count statistic.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M" }, { sex = "M" }, { sex = "F" }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.count
    |> Table.show
Try it

Notes: If no stat functions are called before Table.show, count is the default.

See also: Table.percent, Table.meanOf

Table.create

DataFrame -> TableSpec

Initialize a table specification builder from a DataFrame.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "F", age = 25 }]

df
    |> Table.create
Try it

Notes: Use Table.rows, Table.cols, and stat functions to configure the table, then Table.show to materialize it.

See also: Table.rows, Table.cols, Table.show

Table.cross

DataFrameColumn -> DataFrameColumn -> DataFrame -> Table

Create a two-way cross-tabulation. Accepts String, Symbol, or list thereof for each dimension.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", bp = "high" }, { sex = "F", bp = "low" }, { sex = "M", bp = "low" }]

df
    |> Table.cross @sex @bp
Try it

Notes: Shortcut for Table.create |> Table.rows rowVars |> Table.cols colVars |> Table.count |> Table.show.

See also: Table.freq, Table.create

Table.facetBy

DataFrameColumn -> TableSpec -> TableSpec

Split into separate sub-tables for each level of the given variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", race = "W", age = 30 }, { sex = "F", race = "B", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.facetBy @race
    |> Table.show
Try it

See also: Table.rows, Table.cols

Table.freq

DataFrameColumn -> DataFrame -> Table

Create a one-way frequency table. Accepts a String, Symbol, or list thereof.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M" }, { sex = "M" }, { sex = "F" }]

df
    |> Table.freq @sex
Try it

Notes: Shortcut for Table.create |> Table.rows vars |> Table.count |> Table.show.

See also: Table.cross, Table.create

Table.maxOf

DataFrameColumn -> TableSpec -> TableSpec

Add maximum of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.maxOf @age
    |> Table.show
Try it

See also: Table.minOf

Table.meanOf

DataFrameColumn -> TableSpec -> TableSpec

Add mean of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.meanOf @age
    |> Table.show
Try it

See also: Table.stdOf, Table.medianOf

Table.medianOf

DataFrameColumn -> TableSpec -> TableSpec

Add median of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.medianOf @age
    |> Table.show
Try it

See also: Table.meanOf, Table.minOf, Table.maxOf

Table.minOf

DataFrameColumn -> TableSpec -> TableSpec

Add minimum of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.minOf @age
    |> Table.show
Try it

See also: Table.maxOf

Table.noTotals

TableSpec -> TableSpec

Suppress row and column totals.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M" }, { sex = "M" }, { sex = "F" }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.noTotals
    |> Table.show
Try it

Table.percent

TableSpec -> TableSpec

Add percentage of total statistic.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M" }, { sex = "M" }, { sex = "F" }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.percent
    |> Table.show
Try it

See also: Table.count

Table.relayout

[DataFrameColumn] -> [DataFrameColumn] -> Table -> Table

Re-layout an existing Table with new row and column dimensions.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", bp = "high" }, { sex = "F", bp = "low" }, { sex = "M", bp = "low" }]

let t =
    df |> Table.cross @sex @bp

t
    |> Table.relayout [@bp] [@sex]
Try it

Notes: First argument is new row variables, second is new column variables. No recomputation of statistics.

See also: Table.show

Table.rows

[DataFrameColumn] -> TableSpec -> TableSpec

Add row dimension variables.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.show
Try it

Notes: Multiple calls create adjacent row sections. Multiple vars in one call create nested hierarchy.

See also: Table.cols, Table.create

Table.setPValue

TableSpec -> TableSpec

Add p-value column with auto-selected test.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.count
    |> Table.setPValue
    |> Table.show
Try it

Notes: Selects t-test (Welch's) for continuous variables, chi-squared for categorical. ANOVA for >2 groups.

Table.show

TableSpec -> Table

Materialize the table specification into a displayable Table.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.count
    |> Table.show
Try it

Notes: Computes all statistics and creates the table with the current layout. Use Table.relayout to rearrange after.

See also: Table.relayout, Table.toDataFrame

Table.stdOf

DataFrameColumn -> TableSpec -> TableSpec

Add standard deviation of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.stdOf @age
    |> Table.show
Try it

See also: Table.meanOf

Table.sumOf

DataFrameColumn -> TableSpec -> TableSpec

Add sum of a variable.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M", age = 30 }, { sex = "M", age = 40 }, { sex = "F", age = 25 }]

df
    |> Table.create
    |> Table.rows [@sex]
    |> Table.sumOf @age
    |> Table.show
Try it

See also: Table.count, Table.meanOf

Table.toDataFrame

Table -> DataFrame

Convert a Table to a flat DataFrame.

Example:
import Table
import DataFrame

let df =
    DataFrame.fromRecords [{ sex = "M" }, { sex = "F" }, { sex = "M" }]

let t =
    df |> Table.freq @sex

t
    |> Table.toDataFrame
Try it

Notes: Returns the raw aggregated data as a DataFrame for further manipulation.

See also: Table.show