Logo

SQL Server COVM Function

Updated 2024-03-04 21:11:59.947000

Description

Use the table-valued function COVM to calculate a sample covariance matrix. The sample covariance of a matrix (A) is calculated by subtracting the column mean (µ) from each element in a column, calculating XTX and then dividing the result by n-1, where n is the number of rows. For example:

A=\begin{bmatrix}a_{11}&a_{12}&a_{13}&a_{14}\\a_{21}&a_{22}&a_{23}&a_{24}\\a_{31}&a_{32}&_{33}&a_{34}\end{bmatrix}
X=\begin{bmatrix}a_{11}&a_{12}&a_{13}&a_{14}\\a_{21}&a_{22}&a_{23}&a_{24}\\a_{31}&a_{32}&_{33}&a_{34}\end{bmatrix}-\begin{bmatrix}1&1&1\\1&1&1\\1&1&1\\1&1&1\\\end{bmatrix}\begin{bmatrix}a_{11}&a_{12}&a_{13}&a_{14}\\a_{21}&a_{22}&a_{23}&a_{24}\\a_{31}&a_{32}&_{33}&a_{34}\end{bmatrix}*\frac{1}{n}
\mathrm{Cov(A)=(X^TX)/(n-1)}

Syntax

SELECT * FROM [westclintech].[wct].[COVM](
  <@Matrix_RangeQuery, nvarchar(max),>
 ,<@Is3N, bit,>)

Arguments

@Matrix_RangeQuery

the SELECT statement, as text, used to return the input matrix for this function. The SELECT statement specifies the column names from the table or view or can be used to enter the matrix values directly. Data returned from the @Matrix_RangeQuery select must be of the type float or of a type that implicitly converts to float.

@Is3N

a bit value identifying the form for the resultant table returned by @Matrix_RangeQuery. Enter 'True' for a resultant table in 3rd normal form. Enter 'False' for a de-normalized table in 'spreadsheet' form.

Return Type

table

colNamecolDatatypecolDesc
RowNumintThe zero-based row index for the matrix
ColNumintThe zero-based column index for the matrix
ItemValuefloatThe value at RowNum, ColNum

Remarks

If @Is3N is NULL then @Is3N = 'False'.

Use MCOV for a matrix stored as a string.

If @Is3N is 'True' then the resultant table should be returned as row, column, and value.

If the array contains NULL, then NULL will be returned.

The function returns an error if the array contains a non-numeric value.

If the supplied input is a vector, then result will be the (sample) variance.

Examples

In this example @Matrix_RangeQuery returns the matrix from a derived table embodied in the statement. The matrix is in spreadsheet form.

SELECT *
FROM wct.COVM(
                 'SELECT
          x1,x2,x3,x4,x5,x6,x7,x8
        FROM (VALUES
           (1,1,1,1,1,1,1,1)
          ,(2,3,4,5,6,7,8,9)
          ,(4,9,16,25,36,49,64,81)
        )n(x1,x2,x3,x4,x5,x6,x7,x8)',
                 'False'
             );

This produces the following result.

RowNumColNumItemValue
002.33333333333333
016.33333333333333
0212
0319.3333333333333
0428.3333333333333
0539
0651.3333333333333
0765.3333333333333
106.33333333333333
1117.3333333333333
1233
1353.3333333333333
1478.3333333333333
15108
16142.333333333333
17181.333333333333
2012
2133
2263
23102
24150
25207
26273
27348
3019.3333333333333
3153.3333333333333
32102
33165.333333333333
34243.333333333333
35336
36443.333333333333
37565.333333333333
4028.3333333333333
4178.3333333333333
42150
43243.333333333333
44358.333333333333
45495
46653.333333333333
47833.333333333333
5039
51108
52207
53336
54495
55684
56903
571152
6051.3333333333333
61142.333333333333
62273
63443.333333333333
64653.333333333333
65903
661192.33333333333
671521.33333333333
7065.3333333333333
71181.333333333333
72348
73565.333333333333
74833.333333333333
751152
761521.33333333333
771941.33333333333

Note that the results are returned in third-normal form. If we wanted to a more traditional (de-normalized) presentation of the results, we can us the PIVOT function. Also note that we can use * to select all the columns. We have rounded the results to 2 decimal place for ease of viewing.

SELECT ROUND([0], 2) as [0],
       ROUND([1], 2) as [1],
       ROUND([2], 2) as [2],
       ROUND([3], 2) as [3],
       ROUND([4], 2) as [4],
       ROUND([5], 2) as [5],
       ROUND([6], 2) as [6],
       ROUND([7], 2) as [7]
FROM
(
    SELECT *
    FROM wct.COVM(
                     'SELECT
          *
        FROM (VALUES
           (1,1,1,1,1,1,1,1)
          ,(2,3,4,5,6,7,8,9)
          ,(4,9,16,25,36,49,64,81)
        )n(x1,x2,x3,x4,x5,x6,x7,x8)',
                     'False'
                 )
) d
PIVOT
(
    SUM(ItemValue)
    for ColNum in ([0], [1], [2], [3], [4], [5], [6], [7])
) as P;

This produces the following result.

01234567
2.336.331219.3328.333951.3365.33
6.3317.333353.3378.33108142.33181.33
123363102150207273348
19.3353.33102165.33243.33336443.33565.33
28.3378.33150243.33358.33495653.33833.33
391082073364956849031152
51.33142.33273443.33653.339031192.331521.33
65.33181.33348565.33833.3311521521.331941.33

Let's put several matrices into a table and calculate the covariance matrix for each. We will use CROSS APPLY to calculate to the covariance matrix for each matrix. Note that we have to convert the matrix identifier (which is defined as int) to a varchar to include it in the WHERE clause of @Matrix_RangeQuery.

CREATE TABLE #c
(
    Matrix int,
    rn int,
    x1 float,
    x2 float,
    x3 float,
    PRIMARY KEY (
                    Matrix,
                    rn
                )
);
INSERT INTO #c
VALUES
(100, 1, -11, -41, 36);
INSERT INTO #c
VALUES
(100, 2, -31, 41, -47);
INSERT INTO #c
VALUES
(100, 3, 48, -38, 33);
INSERT INTO #c
VALUES
(100, 4, 8, 44, -10);
INSERT INTO #c
VALUES
(101, 1, 39, 6, -7);
INSERT INTO #c
VALUES
(101, 2, 33, -49, 16);
INSERT INTO #c
VALUES
(101, 3, 14, 29, 13);
INSERT INTO #c
VALUES
(101, 4, 35, -38, -50);
INSERT INTO #c
VALUES
(101, 5, 9, -32, -25);
INSERT INTO #c
VALUES
(102, 1, 29, 49, -17);
INSERT INTO #c
VALUES
(102, 2, 35, 28, 28);
INSERT INTO #c
VALUES
(102, 3, -34, -29, -49);
INSERT INTO #c
VALUES
(102, 4, 0, -5, 0);
INSERT INTO #c
VALUES
(102, 5, -17, 14, 24);
INSERT INTO #c
VALUES
(102, 6, 44, 3, -23);
SELECT n.MATRIX,
       k.*
FROM
(SELECT DISTINCT MATRIX FROM #c) n
    CROSS APPLY wct.COVM('SELECT
          x1,x2,x3
        FROM
          #c
       WHERE MATRIX = ' + cast(n.Matrix as varchar(max)) + ' ORDER by rn', 'False')
                 k;

This produces the following result.

MATRIXRowNumColNumItemValue
100001133.66666666667
10001-771
10002841
10010-771
100112244.33333333333
10012-1705
10020841
10021-1705
100221552.66666666667
10100183
10101-102.75
10102-40
10110-102.75
101111083.7
10112340.15
10120-40
10121340.15
10122759.3
10200981.1
10201542.2
10202216.9
10210542.2
10211731.2
10212401.8
10220216.9
10221401.8
10222870.166666666667

In this example we calculate the covariance matrix from a derived table in 3rd normal form.

SELECT *
FROM wct.COVM(
                 'SELECT
          rownum,colnum,itemvalue
        FROM (VALUES
               (0,0,1),(0,1,1),(0,2,1),(0,3,1),(0,4,1),(0,5,1),(0,6,1),(0,7,1)
              ,(1,0,2),(1,1,3),(1,2,4),(1,3,5),(1,4,6),(1,5,7),(1,6,8),(1,7,9)
              ,(2,0,4),(2,1,9),(2,2,16),(2,3,25),(2,4,36),(2,5,49),(2,6,64),(2,7,
                        81)
        )n(rownum,colnum,itemvalue)',
                 'True'
             );

This produces the following result.

RowNumColNumItemValue
002.33333333333333
016.33333333333333
0212
0319.3333333333333
0428.3333333333333
0539
0651.3333333333333
0765.3333333333333
106.33333333333333
1117.3333333333333
1233
1353.3333333333333
1478.3333333333333
15108
16142.333333333333
17181.333333333333
2012
2133
2263
23102
24150
25207
26273
27348
3019.3333333333333
3153.3333333333333
32102
33165.333333333333
34243.333333333333
35336
36443.333333333333
37565.333333333333
4028.3333333333333
4178.3333333333333
42150
43243.333333333333
44358.333333333333
45495
46653.333333333333
47833.333333333333
5039
51108
52207
53336
54495
55684
56903
571152
6051.3333333333333
61142.333333333333
62273
63443.333333333333
64653.333333333333
65903
661192.33333333333
671521.33333333333
7065.3333333333333
71181.333333333333
72348
73565.333333333333
74833.333333333333
751152
761521.33333333333
771941.33333333333

See Also

MCOV - Calculate a sample covariance matrix.

CORRM - Table-valued function to calculate the correlation matrix

COVARIANCE_S - Aggregate function to calculate the sample covariance

COVARIANCE_P - Aggregate function to calculate the population covariance