Project: YugabyteDB (App Definition and Development / Database)
File: regr.md

title: regr_%() linkTitle: regr_%() headerTitle: regr_%() description: Describes the functionality of the regr_%() YSQL aggregate functions for linear regression analysis menu: v2.18: identifier: regr parent: linear-regression weight: 20 type: docs This section describes these aggregate functions for linear regression analysis: , , , , , , , , . Make sure that you have read the parent section before reading this section. You will need the same data that the parent section shows you how to create. You will also need the function `approx_equal()` that was used in the section. Create it like this. ```plpgsql drop function if exists approx_equal(double precision, double precision) cascade; create function approx_equal( n1 in double precision, n2 in double precision) returns boolean language sql as $body$ select 2.0::double precision*abs(n1 - n2)/(n1 + n2) < (2e-15)::double precision; $body$; ``` Purpose: `regravgy()` returns the average of the first argument for those rows where both arguments are `NOT NULL`. `regravgx()` returns the average of the second argument for those rows where both arguments are `NOT NULL`. Purpose: returns the number of rows where both arguments are `NOT NULL`. Do this: ```plpgsql create or replace view v as select x, y from t; create or replace view test as with a as ( select regravgy(y, x) as ravgy, regravgx(y, x) as ravgx, regrcount(y, x) as rcount, avg(y) filter (where x is not null) as avgy, avg(x) filter (where y is not null) as avgx, count(y) filter (where x is not null) as county, count(x) filter (where y is not null) as countx from v) select approxequal(ravgy, avgy)::text as "r_avgy = avgy", approxequal(ravgx, avgx)::text as "r_avgx = avgx", approxequal(rcount, county)::text as "r_count = county", approxequal(rcount, countx)::text as "r_count = countx" from a; ``` Test it like this on the noise-free data: ```plpgsql create or replace view v as select x, y from t; select * from test; ``` This is the result: ``` ravgy = avgy | ravgx = avgx | rcount = county | rcount = countx +++ true | true | true | true ``` Now test it on the noisy data: ```plpgsql create or replace view v as select x, (y + delta) as y from t; select * from test; ``` The result is the same. Purpose: `regrslope()` returns the slope of the straight line that linear regression analysis has determined best fits the "(y, x)" pairs. And `regrintercept()` returns the point at which this line intercepts the "y"-axis. Try this: ```plpgsql select tochar(regrslope(y, x), '0.99999999') as "noise-free slope", tochar(regrintercept(y, x), '0.99999999') as "noise-free intercept", tochar(regrslope((y + delta), x), '0.99999999') as "noisy slope", tochar(regrintercept((y + delta), x), '0.99999999') as "noisy intercept" from t; ``` This is a typical result: ``` noise-free slope | noise-free intercept | noisy slope | noisy intercept +-+-+-- 5.00000000 | 3.00000000 | 4.99778685 | 3.70820546 ``` Recall (see the section) that the table was populated using this parameterization: ```plpgsql \set noofrows 100 call populate_t( noofrows => :noofrows, mean => 0.0, stddev => 20.0, slope => 5.0, intercept => 3.0); ``` The results from `regrslope()` and `regrintercept()` line up well with what you'd

The section shows a scatter plot of the data in table "t" (created with actual arguments for procedure "populatet()" which that section specifies) with the straight line whose slope and y-axis intercept, as returned by `regrslope()` and `regr_intercept()`, superimposed. Purpose: Returns the square of the correlation coefficient, . Try this: ```plpgsql select approxequal(regrr2(y, x), corr(y, x)^2 )::text as "test for noise-free data", approxequal(regrr2((y + delta), x), corr((y + delta), x)^2)::text as "test for noisy data" from t; ``` This is the result: ``` test for noise-free data | test for noisy data --+ true | true ``` Purpose: These three measures are clearly defined in terms of other statistical aggregate functions described in this overall section. Statisticians will know when they need them. `regr_syy(y, x)` returns `*` for `NOT NULL` pairs. `regr_sxx(y, x)` returns `*` for `NOT NULL` pairs. `regr_sxy(y, x)` returns `*` for `NOT NULL` pairs. Try this first: ```plpgsql create or replace view v as select x, y from t; create or replace view test as with a as ( select x, y from v where x is not null and y is not null) select approxequal( regrsyy(y, x), (regrcount(y, x)*varpop(y)) ) ::text as "regr_syy() test", approxequal( regrsxx(y, x), (regrcount(y, x)*varpop(x)) ) ::text as "regr_sxx() test", approxequal( regrsxy(y, x), (regrcount(y, x)*covarpop(y, x)) )::text as "regr_sxy() test" from a; ``` Now do this to test the semantics on the noise-free data: ```plpgsql create or replace view v as select x, y from t; select * from test; ``` This is the result: ``` regrsyy() test | regrsxx() test | regr_sxy() test --+--+-- true | true | true ``` Now do this to test the semantics on the noisy data: ```plpgsql create or replace view v as select x, (y + delta) as y from t; select * from test; ``` The result is the same as the result for the noise-free data. Now try this: ```plpgsql create or replace view v as select x, y from t; drop function if exists f() cascade; create function f() returns table(t text) language plpgsql as $body$ declare regr_syy constant double precision not null := ( select regr_syy(y, x) from v); regr_sxx constant double precision not null := ( select regr_sxx(y, x) from v); regr_sxy constant double precision not null := ( select regr_sxy(y, x) from v); count double precision not null := 0; sum_yy double precision not null := 0; sum_xx double precision not null := 0; sum_xy double precision not null := 0; sum_y double precision not null := 0; sum_x double precision not null := 0; begin with a as ( select x, y from v where x is not null and y is not null) select count(), sum(y^2), sum(x^2), sum(xy), sum(y), sum(x) into count, sumyy, sumxx, sumxy, sumy, sum_x from a; assert approxequal(regrsyy, (sumyy - sumy^2)/count), 'unexpected'; assert approxequal(regrsxx, (sumxx - sumx^2)/count), 'unexpected'; assert approxequal(regrsxy, (sumxy - sumy*sum_x)/count), 'unexpected'; t := 'regrsyy: '||tochar(regr_syy, '99999990.99999999'); return next; t := 'regrsxx: '||tochar(regr_sxx, '99999990.99999999'); return next; t := 'regrsxy: '||tochar(regr_sxy, '99999990.99999999'); return next; end; $body$; create or replace view v as select x, y from t; select t as "noise-free data" from f(); create or replace view v as select x, (y + delta) as y from t; select t as "noisy data" from f(); ``` This is a typical result: ``` noise-free data regr_syy: 2083125.00000000 regr_sxx: 83325.00000000 regr_sxy: 416625.00000000 noisy data regr_syy: 2121737.65951556 regr_sxx: 83325.00000000 regr_sxy: 416440.58954855 ```