Oracleの線形回帰関数と同様に、SQL Server 2005/2008に線形回帰関数はありますか?
8 に答える
私の知る限り、何もありません。ただし、作成するのは非常に簡単です。以下は、y=アルファ+ベータ*x+イプシロンの定数アルファと勾配ベータを示します。
-- test data (GroupIDs 1, 2 normal regressions, 3, 4 = no variance)
WITH some_table(GroupID, x, y) AS
( SELECT 1, 1, 1 UNION SELECT 1, 2, 2 UNION SELECT 1, 3, 1.3
UNION SELECT 1, 4, 3.75 UNION SELECT 1, 5, 2.25 UNION SELECT 2, 95, 85
UNION SELECT 2, 85, 95 UNION SELECT 2, 80, 70 UNION SELECT 2, 70, 65
UNION SELECT 2, 60, 70 UNION SELECT 3, 1, 2 UNION SELECT 3, 1, 3
UNION SELECT 4, 1, 2 UNION SELECT 4, 2, 2),
-- linear regression query
/*WITH*/ mean_estimates AS
( SELECT GroupID
,AVG(x * 1.) AS xmean
,AVG(y * 1.) AS ymean
FROM some_table
GROUP BY GroupID
),
stdev_estimates AS
( SELECT pd.GroupID
-- T-SQL STDEV() implementation is not numerically stable
,CASE SUM(SQUARE(x - xmean)) WHEN 0 THEN 1
ELSE SQRT(SUM(SQUARE(x - xmean)) / (COUNT(*) - 1)) END AS xstdev
, SQRT(SUM(SQUARE(y - ymean)) / (COUNT(*) - 1)) AS ystdev
FROM some_table pd
INNER JOIN mean_estimates pm ON pm.GroupID = pd.GroupID
GROUP BY pd.GroupID, pm.xmean, pm.ymean
),
standardized_data AS -- increases numerical stability
( SELECT pd.GroupID
,(x - xmean) / xstdev AS xstd
,CASE ystdev WHEN 0 THEN 0 ELSE (y - ymean) / ystdev END AS ystd
FROM some_table pd
INNER JOIN stdev_estimates ps ON ps.GroupID = pd.GroupID
INNER JOIN mean_estimates pm ON pm.GroupID = pd.GroupID
),
standardized_beta_estimates AS
( SELECT GroupID
,CASE WHEN SUM(xstd * xstd) = 0 THEN 0
ELSE SUM(xstd * ystd) / (COUNT(*) - 1) END AS betastd
FROM standardized_data pd
GROUP BY GroupID
)
SELECT pb.GroupID
,ymean - xmean * betastd * ystdev / xstdev AS Alpha
,betastd * ystdev / xstdev AS Beta
FROM standardized_beta_estimates pb
INNER JOIN stdev_estimates ps ON ps.GroupID = pb.GroupID
INNER JOIN mean_estimates pm ON pm.GroupID = pb.GroupID
GroupID
これは、ソースデータテーブルの値でグループ化する方法を示すために使用されます。テーブル内のすべてのデータ(特定のサブグループではない)の統計が必要な場合は、それと結合を削除できます。WITH
わかりやすくするために、このステートメントを使用しました。別の方法として、代わりにサブクエリを使用できます。データに対して精度が十分に高くないと、数値の安定性が急速に低下する可能性があるため、テーブルで使用されるデータ型の精度に注意してください。
編集:(コメントのR2のような追加の統計に関するPeterの質問への回答)
同じ手法を使用して、追加の統計を簡単に計算できます。これは、R2、相関、およびサンプル共分散を含むバージョンです。
-- test data (GroupIDs 1, 2 normal regressions, 3, 4 = no variance)
WITH some_table(GroupID, x, y) AS
( SELECT 1, 1, 1 UNION SELECT 1, 2, 2 UNION SELECT 1, 3, 1.3
UNION SELECT 1, 4, 3.75 UNION SELECT 1, 5, 2.25 UNION SELECT 2, 95, 85
UNION SELECT 2, 85, 95 UNION SELECT 2, 80, 70 UNION SELECT 2, 70, 65
UNION SELECT 2, 60, 70 UNION SELECT 3, 1, 2 UNION SELECT 3, 1, 3
UNION SELECT 4, 1, 2 UNION SELECT 4, 2, 2),
-- linear regression query
/*WITH*/ mean_estimates AS
( SELECT GroupID
,AVG(x * 1.) AS xmean
,AVG(y * 1.) AS ymean
FROM some_table pd
GROUP BY GroupID
),
stdev_estimates AS
( SELECT pd.GroupID
-- T-SQL STDEV() implementation is not numerically stable
,CASE SUM(SQUARE(x - xmean)) WHEN 0 THEN 1
ELSE SQRT(SUM(SQUARE(x - xmean)) / (COUNT(*) - 1)) END AS xstdev
, SQRT(SUM(SQUARE(y - ymean)) / (COUNT(*) - 1)) AS ystdev
FROM some_table pd
INNER JOIN mean_estimates pm ON pm.GroupID = pd.GroupID
GROUP BY pd.GroupID, pm.xmean, pm.ymean
),
standardized_data AS -- increases numerical stability
( SELECT pd.GroupID
,(x - xmean) / xstdev AS xstd
,CASE ystdev WHEN 0 THEN 0 ELSE (y - ymean) / ystdev END AS ystd
FROM some_table pd
INNER JOIN stdev_estimates ps ON ps.GroupID = pd.GroupID
INNER JOIN mean_estimates pm ON pm.GroupID = pd.GroupID
),
standardized_beta_estimates AS
( SELECT GroupID
,CASE WHEN SUM(xstd * xstd) = 0 THEN 0
ELSE SUM(xstd * ystd) / (COUNT(*) - 1) END AS betastd
FROM standardized_data
GROUP BY GroupID
)
SELECT pb.GroupID
,ymean - xmean * betastd * ystdev / xstdev AS Alpha
,betastd * ystdev / xstdev AS Beta
,CASE ystdev WHEN 0 THEN 1 ELSE betastd * betastd END AS R2
,betastd AS Correl
,betastd * xstdev * ystdev AS Covar
FROM standardized_beta_estimates pb
INNER JOIN stdev_estimates ps ON ps.GroupID = pb.GroupID
INNER JOIN mean_estimates pm ON pm.GroupID = pb.GroupID
EDIT 2は、データを(中央揃えだけでなく)標準化し、数値安定性の問題のために置き換えるSTDEV
ことにより、数値安定性を向上させます。私には、現在の実装が安定性と複雑さの間の最良のトレードオフのように思われます。標準偏差を数値的に安定したオンラインアルゴリズムに置き換えることで安定性を向上させることができますが、これは実装を実質的に複雑にします(そしてそれを遅くします)。同様に、たとえばKahan(-Babuška-Neumaier)補正を使用した実装は、限られたテストで適度にパフォーマンスが向上するようSUM
にAVG
見えますが、クエリははるかに複雑になります。そして、T-SQLがどのように実装されているかわからない限りSUM
、AVG
(たとえば、すでにペアワイズ合計を使用している可能性があります)、そのような変更が常に精度を向上させることを保証することはできません。
これは、 T-SQLの線形回帰に関するブログ投稿に基づく代替方法であり、次の方程式を使用します。
ただし、ブログのSQLの提案ではカーソルを使用しています。これが私が使用したフォーラムの回答のきれいなバージョンです:
table
-----
X (numeric)
Y (numeric)
/**
* m = (nSxy - SxSy) / (nSxx - SxSx)
* b = Ay - (Ax * m)
* N.B. S = Sum, A = Mean
*/
DECLARE @n INT
SELECT @n = COUNT(*) FROM table
SELECT (@n * SUM(X*Y) - SUM(X) * SUM(Y)) / (@n * SUM(X*X) - SUM(X) * SUM(X)) AS M,
AVG(Y) - AVG(X) *
(@n * SUM(X*Y) - SUM(X) * SUM(Y)) / (@n * SUM(X*X) - SUM(X) * SUM(X)) AS B
FROM table
私は実際にグラムシュミットオルソガナリゼーションを使用してSQLルーチンを作成しました。これは、他の機械学習および予測ルーチンと同様に、sqldatamine.blogspot.comで入手できます。
Brad Larsonの提案で、ユーザーをブログに誘導するだけでなく、ここにコードを追加しました。これにより、Excelのlinet関数と同じ結果が得られます。私の主な情報源は、Hastie、Tibshirni、FriedmanによるElements of Statistics Learning(2008)です。
--Create a table of data
create table #rawdata (id int,area float, rooms float, odd float, price float)
insert into #rawdata select 1, 2201,3,1,400
insert into #rawdata select 2, 1600,3,0,330
insert into #rawdata select 3, 2400,3,1,369
insert into #rawdata select 4, 1416,2,1,232
insert into #rawdata select 5, 3000,4,0,540
--Insert the data into x & y vectors
select id xid, 0 xn,1 xv into #x from #rawdata
union all
select id, 1,rooms from #rawdata
union all
select id, 2,area from #rawdata
union all
select id, 3,odd from #rawdata
select id yid, 0 yn, price yv into #y from #rawdata
--create a residuals table and insert the intercept (1)
create table #z (zid int, zn int, zv float)
insert into #z select id , 0 zn,1 zv from #rawdata
--create a table for the orthoganal (#c) & regression(#b) parameters
create table #c(cxn int, czn int, cv float)
create table #b(bn int, bv float)
--@p is the number of independent variables including the intercept (@p = 0)
declare @p int
set @p = 1
--Loop through each independent variable and estimate the orthagonal parameter (#c)
-- then estimate the residuals and insert into the residuals table (#z)
while @p <= (select max(xn) from #x)
begin
insert into #c
select xn cxn, zn czn, sum(xv*zv)/sum(zv*zv) cv
from #x join #z on xid = zid where zn = @p-1 and xn>zn group by xn, zn
insert into #z
select zid, xn,xv- sum(cv*zv)
from #x join #z on xid = zid join #c on czn = zn and cxn = xn where xn = @p and zn<xn group by zid, xn,xv
set @p = @p +1
end
--Loop through each independent variable and estimate the regression parameter by regressing the orthoganal
-- resiuduals on the dependent variable y
while @p>=0
begin
insert into #b
select zn, sum(yv*zv)/ sum(zv*zv)
from #z join
(select yid, yv-isnull(sum(bv*xv),0) yv from #x join #y on xid = yid left join #b on xn=bn group by yid, yv) y
on zid = yid where zn = @p group by zn
set @p = @p-1
end
--The regression parameters
select * from #b
--Actual vs. fit with error
select yid, yv, fit, yv-fit err from #y join
(select xid, sum(xv*bv) fit from #x join #b on xn = bn group by xid) f
on yid = xid
--R Squared
select 1-sum(power(err,2))/sum(power(yv,2)) from
(select yid, yv, fit, yv-fit err from #y join
(select xid, sum(xv*bv) fit from #x join #b on xn = bn group by xid) f
on yid = xid) d
SQLServerには線形回帰関数はありません。ただし、データポイントx、yのペア間の単純線形回帰(Y'= bX + A)を計算するには、相関係数、決定係数(R ^ 2)、および標準偏差の推定(標準偏差)の計算を含みます。以下をせよ:
regression_data
数値列x
とy
:を含むテーブルの場合
declare @total_points int
declare @intercept DECIMAL(38, 10)
declare @slope DECIMAL(38, 10)
declare @r_squared DECIMAL(38, 10)
declare @standard_estimate_error DECIMAL(38, 10)
declare @correlation_coefficient DECIMAL(38, 10)
declare @average_x DECIMAL(38, 10)
declare @average_y DECIMAL(38, 10)
declare @sumX DECIMAL(38, 10)
declare @sumY DECIMAL(38, 10)
declare @sumXX DECIMAL(38, 10)
declare @sumYY DECIMAL(38, 10)
declare @sumXY DECIMAL(38, 10)
declare @Sxx DECIMAL(38, 10)
declare @Syy DECIMAL(38, 10)
declare @Sxy DECIMAL(38, 10)
Select
@total_points = count(*),
@average_x = avg(x),
@average_y = avg(y),
@sumX = sum(x),
@sumY = sum(y),
@sumXX = sum(x*x),
@sumYY = sum(y*y),
@sumXY = sum(x*y)
from regression_data
set @Sxx = @sumXX - (@sumX * @sumX) / @total_points
set @Syy = @sumYY - (@sumY * @sumY) / @total_points
set @Sxy = @sumXY - (@sumX * @sumY) / @total_points
set @correlation_coefficient = @Sxy / SQRT(@Sxx * @Syy)
set @slope = (@total_points * @sumXY - @sumX * @sumY) / (@total_points * @sumXX - power(@sumX,2))
set @intercept = @average_y - (@total_points * @sumXY - @sumX * @sumY) / (@total_points * @sumXX - power(@sumX,2)) * @average_x
set @r_squared = (@intercept * @sumY + @slope * @sumXY - power(@sumY,2) / @total_points) / (@sumYY - power(@sumY,2) / @total_points)
-- calculate standard_estimate_error (standard deviation)
Select
@standard_estimate_error = sqrt(sum(power(y - (@slope * x + @intercept),2)) / @total_points)
From regression_data
これは、次のタイプのテーブルタイプをとる関数です。XYDoubleTypeと呼ばれるtable(Y float、X double)であり、線形関数はAX+Bの形式であると想定しています。万が一の場合に備えてAとBにTable列を返します。あなたはそれを結合か何かに入れたい
CREATE FUNCTION FN_GetABForData(
@XYData as XYDoubleType READONLY
) RETURNS @ABData TABLE(
A FLOAT,
B FLOAT,
Rsquare FLOAT )
AS
BEGIN
DECLARE @sx FLOAT, @sy FLOAT
DECLARE @sxx FLOAT,@syy FLOAT, @sxy FLOAT,@sxsy FLOAT, @sxsx FLOAT, @sysy FLOAT
DECLARE @n FLOAT, @A FLOAT, @B FLOAT, @Rsq FLOAT
SELECT @sx =SUM(D.X) ,@sy =SUM(D.Y), @sxx=SUM(D.X*D.X),@syy=SUM(D.Y*D.Y),
@sxy =SUM(D.X*D.Y),@n =COUNT(*)
From @XYData D
SET @sxsx =@sx*@sx
SET @sxsy =@sx*@sy
SET @sysy = @sy*@sy
SET @A = (@n*@sxy -@sxsy)/(@n*@sxx -@sxsx)
SET @B = @sy/@n - @A*@sx/@n
SET @Rsq = POWER((@n*@sxy -@sxsy),2)/((@n*@sxx-@sxsx)*(@n*@syy -@sysy))
INSERT INTO @ABData (A,B,Rsquare) VALUES(@A,@B,@Rsq)
RETURN
END
@ icc97の回答に追加するために、勾配と切片の加重バージョンを含めました。値がすべて一定の場合、勾配は(適切な設定でSET ARITHABORT OFF; SET ANSI_WARNINGS OFF;
)NULLになり、coalesce()を介して0に置き換える必要があります。
SQLで記述されたソリューションは次のとおりです。
with d as (select segment,w,x,y from somedatasource)
select segment,
avg(y) - avg(x) *
((count(*) * sum(x*y)) - (sum(x)*sum(y)))/
((count(*) * sum(x*x)) - (Sum(x)*Sum(x))) as intercept,
((count(*) * sum(x*y)) - (sum(x)*sum(y)))/
((count(*) * sum(x*x)) - (sum(x)*sum(x))) AS slope,
avg(y) - ((avg(x*y) - avg(x)*avg(y))/var_samp(X)) * avg(x) as interceptUnstable,
(avg(x*y) - avg(x)*avg(y))/var_samp(X) as slopeUnstable,
(Avg(x * y) - Avg(x) * Avg(y)) / (stddev_pop(x) * stddev_pop(y)) as correlationUnstable,
(sum(y*w)/sum(w)) - (sum(w*x)/sum(w)) *
((sum(w)*sum(x*y*w)) - (sum(x*w)*sum(y*w)))/
((sum(w)*sum(x*x*w)) - (sum(x*w)*sum(x*w))) as wIntercept,
((sum(w)*sum(x*y*w)) - (sum(x*w)*sum(y*w)))/
((sum(w)*sum(x*x*w)) - (sum(x*w)*sum(x*w))) as wSlope,
(count(*) * sum(x * y) - sum(x) * sum(y)) / (sqrt(count(*) * sum(x * x) - sum(x) * sum(x))
* sqrt(count(*) * sum(y * y) - sum(y) * sum(y))) as correlation,
(sum(w) * sum(x*y*w) - sum(x*w) * sum(y*w)) /
(sqrt(sum(w) * sum(x*x*w) - sum(x*w) * sum(x*w)) * sqrt(sum(w) * sum(y*y*w)
- sum(y*w) * sum(y*w))) as wCorrelation,
count(*) as n
from d where x is not null and y is not null group by segment
ここで、wは重量です。結果を確認するために、これをRに対して再確認しました。somedatasourceから浮動小数点にデータをキャストする必要があるかもしれません。それらに対して警告するために、不安定なバージョンを含めました。(別の回答でステファンに特に感謝します。)
更新:加重相関を追加
Excelの関数Forecastで使用される線形回帰関数を翻訳し、a、b、およびForecastを返すSQL関数を作成しました。完全な理論的説明は、FORECAST機能のExcelヘルプで確認できます。すべての最初に、テーブルデータ型XYFloatTypeを作成する必要があります。
CREATE TYPE [dbo].[XYFloatType]
AS TABLE(
[X] FLOAT,
[Y] FLOAT)
次に、次の関数を記述します。
/*
-- =============================================
-- Author: Me :)
-- Create date: Today :)
-- Description: (Copied Excel help):
--Calculates, or predicts, a future value by using existing values.
The predicted value is a y-value for a given x-value.
The known values are existing x-values and y-values, and the new value is predicted by using linear regression.
You can use this function to predict future sales, inventory requirements, or consumer trends.
-- =============================================
*/
CREATE FUNCTION dbo.FN_GetLinearRegressionForcast
(@PtXYData as XYFloatType READONLY ,@PnFuturePointint)
RETURNS @ABDData TABLE( a FLOAT, b FLOAT, Forecast FLOAT)
AS
BEGIN
DECLARE @LnAvX Float
,@LnAvY Float
,@LnB Float
,@LnA Float
,@LnForeCast Float
Select @LnAvX = AVG([X])
,@LnAvY = AVG([Y])
FROM @PtXYData;
SELECT @LnB = SUM ( ([X]-@LnAvX)*([Y]-@LnAvY) ) / SUM (POWER([X]-@LnAvX,2))
FROM @PtXYData;
SET @LnA = @LnAvY - @LnB * @LnAvX;
SET @LnForeCast = @LnA + @LnB * @PnFuturePoint;
INSERT INTO @ABDData ([A],[B],[Forecast]) VALUES (@LnA,@LnB,@LnForeCast)
RETURN
END
/*
your tests:
(I used the same values that are in the excel help)
DECLARE @t XYFloatType
INSERT @t VALUES(20,6),(28,7),(31,9),(38,15),(40,21) -- x and y values
SELECT *, A+B*30 [Prueba]FROM dbo.FN_GetLinearRegressionForcast@t,30);
*/
次の答えが、いくつかの解決策がどこから来ているのかを理解するのに役立つことを願っています。簡単な例で説明しますが、添字表記や行列の使い方を知っている限り、多くの変数への一般化は理論的には簡単です。3つの変数を超えるもののソリューションを実装するには、グラムシュミット(上記のColin Campbellの回答を参照)または別の行列反転アルゴリズムを使用します。
必要な関数はすべて分散、共分散、平均、合計などがSQLの集計関数であるため、ソリューションを簡単に実装できます。ロジスティックモデルのスコアの線形キャリブレーションを行うためにHIVEでこれを行いました。多くの利点の中で、1つは、スクリプト言語に出入りすることなく、HIVE内で完全に機能できることです。
データポイントがiによってインデックス付けされているデータ(x_1、x_2、y)のモデルは次のとおりです。
y(x_1、x_2)= m_1 * x_1 + m_2 * x_2 + c
モデルは「線形」に見えますが、そうである必要はありません。たとえば、x_2は、x_2 = Sinh(3 *(x_1)^ 2 +など)に自由パラメーターがない限り、x_1の任意の非線形関数にすることができます。 42)。x_2が「ちょうど」x_2であり、モデルが線形であっても、回帰問題はそうではありません。問題がL2エラーを最小化するようにパラメーターm_1、m_2、cを見つけることであると判断した場合にのみ、線形回帰の問題が発生します。
L2エラーはsum_i((y [i] --f(x_1 [i]、x_2 [i]))^ 2)です。これを3つのパラメーターで最小化すると(各パラメーター= 0で偏導関数を設定)、3つの未知数に対して3つの線形方程式が得られます。これらの方程式はパラメーターが線形であり(これが線形回帰になります)、分析的に解くことができます。単純なモデル(1つの変数、線形モデル、したがって2つのパラメーター)に対してこれを行うことは、簡単で有益です。エラーベクトル空間の非ユークリッド計量ノルムへの一般化は簡単で、対角線の特殊なケースは「重み」を使用することになります。
2つの変数でモデルに戻ります。
y = m_1 * x_1 + m_2 * x_2 + c
期待値を取る=>
= m_1 * + m_2 * + c(0)
ここで、共分散wrt x_1とx_2を取得し、cov(x、x)= var(x)を使用します。
cov(y、x_1)= m_1 * var(x_1)+ m_2 * covar(x_2、x_1)(1)
cov(y、x_2)= m_1 * covar(x_1、x_2)+ m_2 * var(x_2)(2)
これらは2つの未知数の2つの方程式であり、2X2行列を反転することで解くことができます。
行列形式の場合:...これを反転して...を生成できます。
det = var(x_1)* var(x_2)-covar(x_1、x_2)^ 2
(ああ、バーフ、「評判のポイント」とは一体何ですか?方程式を見たい場合は、ちょっと待ってください。)
いずれにせよ、m1とm2が閉じた形になっているので、cについて(0)を解くことができます。
上記の分析ソリューションをExcelのソルバーでチェックして、ガウスノイズのある二次関数を探しました。残差誤差は有効数字6桁に一致します。
SQLで離散フーリエ変換を約20行で実行したい場合は、私に連絡してください。