Shape / inspect · All operations

Build a correlation matrix

A variant of Measure correlation

Correlate every pair of chosen columns at once, giving a matrix of coefficients, covariances or mutual information.

Status

In arcform

Runs as a SQL step

arcform carries it as a sql: step today.

The DuckDB step

Correlate every pair of columns: coefficients, covariances and mutual information

SQL
CREATE TEMP TABLE measures AS SELECT * FROM (VALUES
  (1, 1.0, 3.0, -1.0, 2.0), (2, 2.0, 5.0, -2.0, 1.0), (3, 3.0, 7.0, -3.0, 4.0),
  (4, 4.0, 9.0, -4.0, 3.0), (5, 5.0, 11.0, -5.0, 6.0), (6, 6.0, 13.0, -6.0, 5.0)
) t(id, x, y, z, w);
-- y = 2x + 1 and z = -x; w wobbles around x
CREATE TEMP TABLE cells AS
SELECT id, c.col, c.v FROM measures, LATERAL (VALUES ('x', x), ('y', y), ('z', z), ('w', w)) c(col, v);
-- every ordered pair of columns, once: a correlation and a covariance for each
CREATE TEMP TABLE pairs AS
SELECT a.col AS col_a, b.col AS col_b, round(corr(a.v, b.v), 4) AS r, round(covar_samp(a.v, b.v), 4) AS covariance
FROM cells a JOIN cells b USING (id)
GROUP BY a.col, b.col;
-- the same, as a matrix with a row and a column for each measure
CREATE TEMP TABLE matrix AS
SELECT * FROM (PIVOT pairs ON col_b USING first(r) GROUP BY col_a) ORDER BY col_a;
-- mutual information between categorical columns, in nats: sum of p(a,b) * ln(p(a,b) / (p(a) * p(b)))
CREATE TEMP TABLE categories AS SELECT * FROM (VALUES
  (1, 'p', 'p', 'u'), (2, 'p', 'p', 'v'), (3, 'p', 'p', 'u'), (4, 'p', 'p', 'v'),
  (5, 'q', 'q', 'u'), (6, 'q', 'q', 'v'), (7, 'q', 'q', 'u'), (8, 'q', 'q', 'v')
) t(id, a, copy_of_a, independent);
CREATE TEMP TABLE labels AS
SELECT id, c.col, c.v FROM categories, LATERAL (VALUES ('a', a), ('copy_of_a', copy_of_a), ('independent', independent)) c(col, v);
CREATE TEMP TABLE joint AS
SELECT a.col AS col_a, b.col AS col_b, a.v AS va, b.v AS vb, count(*) AS n
FROM labels a JOIN labels b USING (id) GROUP BY ALL;
CREATE TEMP TABLE mutual_information AS
SELECT col_a, col_b, round(sum(n / total * ln((n / total) / ((na / total) * (nb / total)))), 6) AS mi
FROM (SELECT *, sum(n) OVER (PARTITION BY col_a, col_b) AS total,
             sum(n) OVER (PARTITION BY col_a, col_b, va) AS na,
             sum(n) OVER (PARTITION BY col_a, col_b, vb) AS nb FROM joint)
GROUP BY col_a, col_b;
SELECT * FROM matrix;
SELECT * FROM mutual_information ORDER BY col_a, col_b;
SELECT CASE WHEN ((SELECT count(*) FROM pairs) = 16 AND (SELECT r FROM pairs WHERE col_a = 'x' AND col_b = 'y') = 1.0 AND (SELECT r FROM pairs WHERE col_a = 'x' AND col_b = 'z') = -1.0 AND (SELECT r FROM pairs WHERE col_a = 'x' AND col_b = 'w') = 0.8286 AND (SELECT r FROM pairs WHERE col_a = 'w' AND col_b = 'x') = 0.8286 AND (SELECT r FROM pairs WHERE col_a = 'y' AND col_b = 'y') = 1.0 AND (SELECT covariance FROM pairs WHERE col_a = 'x' AND col_b = 'y') = 7.0 AND (SELECT covariance FROM pairs WHERE col_a = 'x' AND col_b = 'x') = 3.5 AND (SELECT list(col_a ORDER BY col_a) FROM matrix) = ['w', 'x', 'y', 'z'] AND (SELECT list(column_name) FROM (DESCRIBE matrix)) = ['col_a', 'w', 'x', 'y', 'z'] AND (SELECT mi FROM mutual_information WHERE col_a = 'a' AND col_b = 'copy_of_a') = 0.693147 AND (SELECT mi FROM mutual_information WHERE col_a = 'a' AND col_b = 'independent') = 0.0) THEN 'as expected' ELSE error('the correlation matrix, covariances or mutual information were not the expected values: x and y at 1, x and z at -1, a with a copy of itself at ln 2 and with an independent column at 0') END AS verdict;
  • The statement builds its own data.
  • It needs nothing installed beyond DuckDB itself.
  • The statement checks its own result and raises an error when it is wrong: “the correlation matrix, covariances or mutual information were not the expected values: x and y at 1, x and z at -1, a with a copy of itself at ln 2 and with an independent column at 0”.
  • It passed on DuckDB v2.0.0 (Cyanoptera) d54cbbe3df.

What other tools call it

Meridian's classification; an independent blind rating agreed on 95.7% of 324 rows (variant, version 3).

Alteryx Designer (1)
  • Association Analysisread 2026-09-27

    Measure bivariate association between fields: Pearson, Spearman or Hoeffding's D

KNIME Analytics Platform (2)
  • Linear Correlationread 2026-09-27

    Compute pairwise correlation coefficients for numeric and nominal columns

  • Rank Correlationread 2026-09-27

    Compute pairwise rank-based correlation (Spearman and related measures) between columns

Polars (1)
  • DataFrame.corrread 2026-09-27

    Pairwise Pearson correlation matrix of the columns

RapidMiner Studio (3)

Background

A correlation matrix of n variables is an n × n matrix whose entry in row i and column j is the correlation between the i-th and j-th variables.[1] The diagonal entries of a correlation matrix are all one.[1] A correlation matrix is symmetric, because the correlation between two variables is the same whichever is named first.[1]

When to use it

When many statistical tests are performed on the same dataset, the overall probability of at least one false positive increases as the number of tests grows.[2] Given a large enough pool of variables for the same time period, it is possible to find a pair of graphs that show a spurious correlation.[2] Read a correlation matrix as a map of pairs worth a closer look: one bright cell among dozens is a lead to check, not a finding. (Meridian's view)

In pandas, DataFrame.corr computes Pearson, Kendall and Spearman correlations using pairwise complete observations, excluding missing values.[3] In pandas, the min_periods argument of DataFrame.corr sets the minimum number of observations a pair of columns needs to have a valid result.[3] In pandas, a covariance matrix estimated from columns with missing data is not guaranteed to be positive semi-definite, which can give correlations with absolute values greater than one or a matrix that cannot be inverted.[4] On a table with gaps, check how many rows each cell rests on, and if the matrix will feed a model that needs a proper correlation matrix, compute it on complete rows or repair it afterwards. (Meridian's view)

In pandas, a matrix returned by DataFrame.corr with a custom callable has 1 along the diagonal and is symmetric regardless of what the callable returns.[3]

The method

A correlation matrix of product-moment coefficients is the same as the covariance matrix of the variables after each is standardised, for population and sample correlations alike.[1] A correlation matrix of product-moment coefficients is positive semi-definite, and strictly positive definite if no variable can have all its values exactly generated as a linear function of the others.[1]

Some applications, such as building data models from only partially observed data, need the nearest correlation matrix to an approximate one that lacks positive semi-definiteness.[1] In 2002, Higham formalised the notion of nearness for correlation matrices using the Frobenius norm and gave a method for computing the nearest one with Dykstra's projection algorithm.[1]

Compared with the alternatives

A correlation matrix appears in one formula for the coefficient of multiple determination, a measure of goodness of fit in multiple regression.[1] In exploratory data analysis, the iconography of correlations replaces a correlation matrix with a diagram that draws remarkable positive correlations as solid lines and negative ones as dotted lines.[1]