A statistical computing toolkit for DuckDB, with descriptive statistics, hypothesis tests, R-style distribution functions (d/p/q/r), linear and generalized linear models with robust and cluster-robust standard errors, linear hypotheses and estimated marginal means, grammar-of-graphics charts (VISUALIZE to Vega-Lite), and readers and writers for SAS, SPSS and Stata files, all in SQL.
Compatibility Matrix
This table covers all DuckDB releases that have not reached end-of-life, including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 |
|---|---|---|---|---|---|
| Linux AMD64 | |||||
| Linux ARM64 | |||||
| macOS AMD64 | |||||
| macOS ARM64 | |||||
| Windows AMD64 | |||||
| Windows ARM64 | |||||
| WebAssembly |
Installing and Loading
INSTALL stats_duck FROM community;
LOAD stats_duck;
Example
-- R-style distribution functions (d/p/q/r for 15+ families):
D SELECT pnorm(1.96) AS p, qt(0.975, 30) AS t_crit, dpois(3, 2.5) AS pmf;
┌────────────────────┬────────────────────┬─────────────────────┐
│ p │ t_crit │ pmf │
│ double │ double │ double │
├────────────────────┼────────────────────┼─────────────────────┤
│ 0.9750021048517796 │ 2.0422724563012373 │ 0.21376301724973648 │
└────────────────────┴────────────────────┴─────────────────────┘
-- OLS regression as an aggregate (one model per GROUP BY), with robust SEs.
-- vcov: 'const' | 'HC0'..'HC3' | 'CR0'/'CR1' (cluster-robust, + a cluster key).
D SELECT (c).term, (c).estimate, (c).std_error
FROM (
SELECT unnest((lm_fit(y, [x1, x2], 'HC1')).coefficients) AS c
FROM my_data
);
-- A generalized linear model as an aggregate: poisson with a log link.
-- Families: gaussian, binomial, poisson, gamma. Options (link, vcov,
-- intercept, weights, offset, cluster) go in a trailing STRUCT.
D SELECT (c).term, (c).estimate, (c).std_error
FROM (
SELECT unnest((glm_fit(events, [x1, x2], 'poisson', {'vcov': 'HC1'})).coefficients) AS c
FROM my_data
);
-- A clinical "Table 1" over mixed variable types, with between-group tests:
D SELECT * FROM table_one('patients', variables := ['age', 'sex', 'bmi'], by := ['arm']);
-- Grammar-of-graphics: turn a query into a Vega-Lite spec (+ the SQL to feed it):
D VISUALIZE wt AS x, mpg AS y FROM cars DRAW point;
About stats_duck
The Stats Duck
A statistical computing toolkit that brings common statistical work into
DuckDB SQL. Every function is a streaming aggregate or a scalar function,
so it runs inside GROUP BY and window frames over large tables, and the
same build runs in DuckDB-WASM in the browser.
What is included
-
Descriptive statistics:
summary_stats,table_one(the clinical "Table 1"),corr_matrix,meta. - Hypothesis tests: one-sample, two-sample and paired t-tests, one-way ANOVA, chi-square, Mann-Whitney, Wilcoxon signed-rank, Kolmogorov-Smirnov, Shapiro-Wilk, Anderson-Darling, Jarque-Bera, and correlation tests (Pearson, Spearman, Kendall).
-
Distribution functions: R-style
d/p/q/rquartets for 15+ families (normal, t, chi-square, F, gamma, beta, exponential, Weibull, log-normal, Poisson, negative binomial, hypergeometric, and more), plusptukeyandqtukeyfor the studentized range. -
Regression: the
lmandlm_summarytable functions and thelm_fitaggregate (one model perGROUP BY) with classical, HC0 to HC3 heteroskedasticity-consistent, and CR0/CR1 cluster-robust standard errors. A rank-deficient design is fitted with the aliased columns reported NULL, as R does.glm_fitfits generalized linear models by iteratively reweighted least squares for the gaussian, binomial, poisson and gamma families and their links, with the same covariance options. -
Inference after a fit:
lin_hyptests a general linear hypothesis L·β = 0 on any fit's coefficients and covariance (contrasts, joint tests, Type III sums of squares).emmeanscomputes estimated marginal means and their pairwise differences, with Tukey, Bonferroni, Holm, Hochberg, BH or BY adjustment. -
Grammar of graphics:
VISUALIZE … DRAW <mark>returns a Vega-Lite v5 spec plus the SQL needed to feed it. -
Statistical file formats: readers and writers for SAS
(
.sas7bdat,.xpt), SPSS (.sav,.por) and Stata files, via ReadStat. -
Resampling and correction:
bootstrap, andadjust_pwith the Bonferroni, Holm, Hochberg, BH, BY or no correction.
Full function reference: https://github.com/KoliStat/the-stats-duck.
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| adjust_p | scalar | Multiple-testing correction over a list of p-values (bonferroni, holm, hochberg, BH/fdr, BY, or none). | NULL | [SELECT adjust_p([0.01, 0.04, 0.20], 'holm')] |
| anderson_darling | aggregate | Anderson-Darling normality test against the fitted normal (n >= 8). | NULL | [SELECT anderson_darling(x) FROM samples] |
| anova_oneway | aggregate | One-way ANOVA across the groups of a categorical column. | NULL | [SELECT anova_oneway(yield, variety) FROM crops] |
| bin_edges | aggregate | Automatic histogram bin edges — sturges (default), fd, scott, sqrt, rice, or auto. | NULL | [SELECT bin_edges(price) FROM sales] |
| bin_label | scalar | Label of the bin containing x, given an edge vector (typically from bin_edges). | NULL | [SELECT bin_label(7.5, [0.0, 5.0, 10.0])] |
| bootstrap | aggregate | With-replacement bootstrap of a statistic (mean, median, sum, stddev, variance, min, max); returns a LIST of n_iters resampled values. | NULL | [SELECT bootstrap(revenue, 'mean', 1000, 42) FROM sales] |
| chisq_goodness_of_fit | aggregate | Chi-square goodness-of-fit against a uniform distribution over the observed categories. | NULL | [SELECT chisq_goodness_of_fit(die_face) FROM rolls] |
| chisq_independence | aggregate | Chi-square test of independence between two categorical columns. | NULL | [SELECT chisq_independence(sex, outcome) FROM patients] |
| corr_matrix | table | Long-format pairwise correlation matrix over a table's numeric columns (pearson, spearman, or kendall). | NULL | [SELECT * FROM corr_matrix('iris', variables := ['sepal_length', 'petal_length'])] |
| dbeta | scalar | Beta distribution PDF on [0, 1]. | NULL | [SELECT dbeta(0.5, 2.0, 3.0)] |
| dchisq | scalar | Chi-square distribution PDF. | NULL | [SELECT dchisq(3.0, 2)] |
| dexp | scalar | Exponential distribution PDF; rate defaults to 1. | NULL | [SELECT dexp(1.0)] |
| df | scalar | F distribution PDF. | NULL | [SELECT df(1.0, 3, 12)] |
| dgamma | scalar | Gamma distribution PDF; rate defaults to 1. | NULL | [SELECT dgamma(2.0, 3.0)] |
| dhyper | scalar | Hypergeometric PMF (m successes, n failures, k draws). | NULL | [SELECT dhyper(1, 5, 10, 4)] |
| dlnorm | scalar | Log-normal distribution PDF; defaults meanlog = 0, sdlog = 1. | NULL | [SELECT dlnorm(1.0)] |
| dnbinom | scalar | Negative-binomial PMF: failures before size successes. | NULL | [SELECT dnbinom(2, 5, 0.5)] |
| dnorm | scalar | Normal distribution PDF; defaults mean = 0, sd = 1. | NULL | [SELECT dnorm(0.0)] |
| dpois | scalar | Poisson PMF (discrete). | NULL | [SELECT dpois(3, 2.5)] |
| dt | scalar | Student's t distribution PDF. | NULL | [SELECT dt(0.5, 10)] |
| dweibull | scalar | Weibull distribution PDF; scale defaults to 1. | NULL | [SELECT dweibull(1.0, 2.0)] |
| emmeans | scalar | Estimated marginal means of a fit: each grid row's mean L·β with its standard error, t, p and confidence limits, every pairwise difference, and a multiplicity adjustment over that family ('tukey', 'bonferroni', 'holm', 'hochberg', 'BH' or 'fdr', 'BY', 'none'). alpha defaults to 0.05 and adjust to 'tukey'. Under 'tukey' a df that is not an integer and is below 4 makes the adjustment accurate to about 1e-5 rather than 1e-12. Nothing else about the function is affected by that limit. | NULL | [SELECT emmeans([[1, 0, 0], [0, 1, 0], [0, 0, 1]], [2.0, 6.0, 6.0], [0.8889,0,0, 0,0.8889,0, 0,0,0.8889], 6.0)] |
| glm_fit | aggregate | Generalized linear model aggregate — one model per group, fitted by iteratively reweighted least squares over the gaussian, binomial, poisson and gamma families. The binomial response is a proportion and the weights option is the trial count, so 7 of 10 is y = 0.7 with weight 10. Options go in one trailing STRUCT read by field name: 'link', 'vcov' ('const', 'HC0'–'HC3', 'CR0'/'CR1'), 'intercept', 'weights', 'offset' and 'cluster'. z_statistic uses a normal reference for every family, including gaussian and gamma where R uses a t. |
NULL | [SELECT glm_fit(y, [x1, x2], 'binomial', {'vcov': 'HC1'}) FROM data] |
| jarque_bera | aggregate | Jarque-Bera normality test (skewness + kurtosis). | NULL | [SELECT jarque_bera(returns) FROM prices] |
| kendall_test | aggregate | Kendall's tau-b rank correlation (tie-corrected, normal approximation). | NULL | [SELECT kendall_test(x, y) FROM pairs] |
| ks_test_1samp | aggregate | One-sample Kolmogorov-Smirnov normality test against the fitted normal. | NULL | [SELECT ks_test_1samp(x) FROM samples] |
| ks_test_2samp | aggregate | Two-sample Kolmogorov-Smirnov test for equality of distributions. | NULL | [SELECT ks_test_2samp(a, b) FROM t] |
| lin_hyp | scalar | General linear hypothesis L·β = 0 against a fit: per-constraint estimates with standard errors, plus the joint sum of squares, F and chi-square. | NULL | [SELECT lin_hyp([[0, 1, -1]], [10.0, 2.0, -1.0], [4.3,-0.14,-0.52, -0.14,0.017,0.0023, -0.52,0.0023,0.101], 7.46, 9.0)] |
| lm | table | OLS regression over a table: per-term coefficient estimates for y ~ x (or a formula). | NULL | [SELECT * FROM lm('cars', y := 'mpg', x := ['wt', 'hp'])] |
| lm_fit | aggregate | OLS regression aggregate — one model per group; vcov 'const', 'HC0'..'HC3', or 'CR0'/'CR1' with a VARCHAR cluster key. | NULL | [SELECT lm_fit(y, [x1, x2], 'HC1') FROM data] |
| lm_summary | table | OLS model-level summary (R-squared, F, sigma) for y ~ x over a table. | NULL | [SELECT * FROM lm_summary('cars', y := 'mpg', x := ['wt', 'hp'])] |
| mann_whitney_u | aggregate | Mann-Whitney U test (Wilcoxon rank-sum) for two independent samples. | NULL | [SELECT mann_whitney_u(treatment, control) FROM outcomes] |
| meta | table | Column-level profile of a table: one row per column with a kind classification and light statistics. | NULL | [SELECT * FROM meta('patients')] |
| pbeta | scalar | Beta distribution CDF. | NULL | [SELECT pbeta(0.5, 2.0, 3.0)] |
| pchisq | scalar | Chi-square distribution CDF. | NULL | [SELECT pchisq(3.84, 1)] |
| pearson_test | aggregate | Pearson correlation with significance test and confidence interval. | NULL | [SELECT pearson_test(height, weight) FROM people] |
| pexp | scalar | Exponential distribution CDF; rate defaults to 1. | NULL | [SELECT pexp(1.0)] |
| pf | scalar | F distribution CDF. | NULL | [SELECT pf(4.47, 3, 12)] |
| pgamma | scalar | Gamma distribution CDF; rate defaults to 1. | NULL | [SELECT pgamma(2.0, 3.0)] |
| phyper | scalar | Hypergeometric CDF. | NULL | [SELECT phyper(1, 5, 10, 4)] |
| plnorm | scalar | Log-normal distribution CDF; defaults meanlog = 0, sdlog = 1. | NULL | [SELECT plnorm(1.0)] |
| pnbinom | scalar | Negative-binomial CDF. | NULL | [SELECT pnbinom(2, 5, 0.5)] |
| pnorm | scalar | Normal distribution CDF; defaults mean = 0, sd = 1. | NULL | [SELECT pnorm(1.96)] |
| poibin_cdf | scalar | Poisson-binomial CDF: P(X <= k) for a sum of independent Bernoulli trials with the given success probabilities. | NULL | [SELECT poibin_cdf([0.2, 0.5, 0.9], 2)] |
| ppois | scalar | Poisson CDF. | NULL | [SELECT ppois(3, 2.5)] |
| pt | scalar | Student's t distribution CDF. | NULL | [SELECT pt(2.04, 30)] |
| ptukey | scalar | Studentized range distribution CDF for k means on df degrees of freedom. A df that is not an integer and is below 4 is accurate to about 1e-5 rather than 1e-12. | NULL | [SELECT ptukey(3.0, 3, 10)] |
| pweibull | scalar | Weibull distribution CDF; scale defaults to 1. | NULL | [SELECT pweibull(1.0, 2.0)] |
| qbeta | scalar | Beta distribution quantile. | NULL | [SELECT qbeta(0.95, 2.0, 3.0)] |
| qchisq | scalar | Chi-square distribution quantile. | NULL | [SELECT qchisq(0.95, 1)] |
| qexp | scalar | Exponential distribution quantile (closed form); rate defaults to 1. | NULL | [SELECT qexp(0.95)] |
| qf | scalar | F distribution quantile. | NULL | [SELECT qf(0.95, 3, 12)] |
| qgamma | scalar | Gamma distribution quantile; rate defaults to 1. | NULL | [SELECT qgamma(0.95, 3.0)] |
| qhyper | scalar | Hypergeometric quantile. | NULL | [SELECT qhyper(0.95, 5, 10, 4)] |
| qlnorm | scalar | Log-normal distribution quantile; defaults meanlog = 0, sdlog = 1. | NULL | [SELECT qlnorm(0.95)] |
| qnbinom | scalar | Negative-binomial quantile (integer search). | NULL | [SELECT qnbinom(0.95, 5, 0.5)] |
| qnorm | scalar | Normal distribution quantile; defaults mean = 0, sd = 1. | NULL | [SELECT qnorm(0.975)] |
| qpois | scalar | Poisson quantile (integer search). | NULL | [SELECT qpois(0.95, 2.5)] |
| qt | scalar | Student's t distribution quantile. | NULL | [SELECT qt(0.975, 30)] |
| qtukey | scalar | Studentized range distribution quantile, the Tukey HSD critical value, for k means on df degrees of freedom. A df that is not an integer and is below 4 is accurate to about 1e-5 rather than 1e-12. | NULL | [SELECT qtukey(0.95, 3, 10)] |
| qweibull | scalar | Weibull distribution quantile (closed form); scale defaults to 1. | NULL | [SELECT qweibull(0.95, 2.0)] |
| rbeta | scalar | Random beta sample per row (volatile). | NULL | [SELECT rbeta(2.0, 3.0) FROM range(5)] |
| rchisq | scalar | Random chi-square sample per row (volatile). | NULL | [SELECT rchisq(2.0) FROM range(5)] |
| read_stat | table | Read SAS (.sas7bdat/.xpt), SPSS (.sav/.por), or Stata (.dta) files as a table. | NULL | [SELECT * FROM read_stat('data.sav')] |
| read_stat_metadata | table | Variable-level metadata (labels, formats, value labels) of a SAS/SPSS/Stata file. | NULL | [SELECT * FROM read_stat_metadata('data.sav')] |
| rexp | scalar | Random exponential sample per row (volatile); rate defaults to 1. | NULL | [SELECT rexp() FROM range(5)] |
| rf | scalar | Random F-distribution sample per row (volatile). | NULL | [SELECT rf(3.0, 12.0) FROM range(5)] |
| rgamma | scalar | Random gamma sample per row (volatile); rate defaults to 1. | NULL | [SELECT rgamma(2.0) FROM range(5)] |
| rhyper | scalar | Random hypergeometric sample per row (volatile). | NULL | [SELECT rhyper(5.0, 10.0, 4.0) FROM range(5)] |
| rlnorm | scalar | Random log-normal sample per row (volatile); defaults meanlog = 0, sdlog = 1. | NULL | [SELECT rlnorm() FROM range(5)] |
| rnbinom | scalar | Random negative-binomial sample per row (volatile). | NULL | [SELECT rnbinom(5.0, 0.5) FROM range(5)] |
| rnorm | scalar | Random normal sample per row (volatile); defaults mean = 0, sd = 1. | NULL | [SELECT rnorm() FROM range(5)] |
| rpois | scalar | Random Poisson sample per row (volatile). | NULL | [SELECT rpois(2.5) FROM range(5)] |
| rt | scalar | Random Student's t sample per row (volatile). | NULL | [SELECT rt(10.0) FROM range(5)] |
| rweibull | scalar | Random Weibull sample per row (volatile); scale defaults to 1. | NULL | [SELECT rweibull(1.5) FROM range(5)] |
| shapiro_wilk | aggregate | Shapiro-Wilk normality test (Royston AS R94; n in [3, 5000]). | NULL | [SELECT shapiro_wilk(residual) FROM fits] |
| sign_test_1samp | aggregate | Sign test of the median against a hypothesized value (default 0). | NULL | [SELECT sign_test_1samp(delta, 0.0) FROM changes] |
| sign_test_paired | aggregate | Paired sign test on per-row differences. | NULL | [SELECT sign_test_paired(before, after) FROM measurements] |
| spearman_test | aggregate | Spearman rank correlation with significance test. | NULL | [SELECT spearman_test(rank_a, rank_b) FROM scores] |
| summary_stats | aggregate | Descriptive summary: n, missing, mean, sd, variance, quartiles, skewness, kurtosis, mode. | NULL | [SELECT summary_stats(age) FROM patients] |
| table_one | table | Clinical 'Table 1': long-format descriptives for mixed variable types, optionally stratified with between-group tests. | NULL | [SELECT * FROM table_one('patients', variables := ['age', 'sex'], by := ['arm'])] |
| ttest_1samp | aggregate | One-sample t-test of the column mean against a hypothesized value (default mu = 0). | NULL | [SELECT ttest_1samp(reaction_ms, 250.0) FROM trials] |
| ttest_2samp | aggregate | Two-sample t-test — Welch's by default, Student's pooled with equal_var := true. | NULL | [SELECT ttest_2samp(score_a, score_b) FROM results] |
| ttest_paired | aggregate | Paired t-test on per-row differences. | NULL | [SELECT ttest_paired(before, after) FROM measurements] |
| visualize_mark_v1_area | scalar | Internal VISUALIZE support function: mark registry entry for DRAW area. Not intended for direct use. | NULL | |
| visualize_mark_v1_bar | scalar | Internal VISUALIZE support function: mark registry entry for DRAW bar. Not intended for direct use. | NULL | |
| visualize_mark_v1_boxplot | scalar | Internal VISUALIZE support function: mark registry entry for DRAW boxplot. Not intended for direct use. | NULL | |
| visualize_mark_v1_density | scalar | Internal VISUALIZE support function: mark registry entry for DRAW density. Not intended for direct use. | NULL | |
| visualize_mark_v1_errorband | scalar | Internal VISUALIZE support function: mark registry entry for DRAW errorband. Not intended for direct use. | NULL | |
| visualize_mark_v1_errorbar | scalar | Internal VISUALIZE support function: mark registry entry for DRAW errorbar. Not intended for direct use. | NULL | |
| visualize_mark_v1_heatmap | scalar | Internal VISUALIZE support function: mark registry entry for DRAW heatmap. Not intended for direct use. | NULL | |
| visualize_mark_v1_histogram | scalar | Internal VISUALIZE support function: mark registry entry for DRAW histogram. Not intended for direct use. | NULL | |
| visualize_mark_v1_line | scalar | Internal VISUALIZE support function: mark registry entry for DRAW line. Not intended for direct use. | NULL | |
| visualize_mark_v1_point | scalar | Internal VISUALIZE support function: mark registry entry for DRAW point. Not intended for direct use. | NULL | |
| visualize_mark_v1_regression | scalar | Internal VISUALIZE support function: mark registry entry for DRAW regression. Not intended for direct use. | NULL | |
| visualize_mark_v1_rule | scalar | Internal VISUALIZE support function: mark registry entry for DRAW rule. Not intended for direct use. | NULL | |
| visualize_mark_v1_text | scalar | Internal VISUALIZE support function: mark registry entry for DRAW text. Not intended for direct use. | NULL | |
| visualize_mark_v1_tick | scalar | Internal VISUALIZE support function: mark registry entry for DRAW tick. Not intended for direct use. | NULL | |
| visualize_mark_v1_violin | scalar | Internal VISUALIZE support function: mark registry entry for DRAW violin. Not intended for direct use. | NULL | |
| wilcoxon_signed_rank | aggregate | Wilcoxon signed-rank test on paired differences. | NULL | [SELECT wilcoxon_signed_rank(before, after) FROM measurements] |
Overloaded Functions
This extension does not add any function overloads.
Added Types
This extension does not add any types.
Added Settings
| name | description | input_type | scope | aliases | typed_value |
|---|---|---|---|---|---|
| temp_directory | Set the directory to which temporary files are written. | VARCHAR | GLOBAL | [] | post.db.tmp |