Adakah yang memiliki fungsi regresi Theil-Sen yang ditulis dalam T-SQL?
Saya menemukan satu yang ditulis dalam Perl , tetapi saya tidak dapat mengode ulangnya menjadi SQL.
Adakah yang memiliki fungsi regresi Theil-Sen yang ditulis dalam T-SQL?
Saya menemukan satu yang ditulis dalam Perl , tetapi saya tidak dapat mengode ulangnya menjadi SQL.
Jawaban:
Saya berbohong ketika saya berkata, saya tidak dapat mengode ulangnya menjadi SQL. Aku terlalu malas. Berikut adalah kode dengan contoh penggunaan.
Kode ini didasarkan pada perpustakaan perl TheiSen , menggunakan QuickMedian . Mari kita tentukan jenis tabel baru untuk dengan mudah mengirimkan data kami ke prosedur.
CREATE TYPE dbo.TheilSenInputDataTableType AS TABLE
(
ID INT IDENTITY(1,1),
x REAL,
y REAL
)
Harap perhatikan kolom ID, yang penting di sini karena solusi kami menggunakan pernyataan CROSS APPLY untuk mencapai interpretasi yang benar dari loop dalam yang ditemukan di TheilSen.pm.
my ($x1,$x2,$y1,$y2);
foreach my $i(0 .. $n-2){
$y1 = $y->[$i];
$x1 = $x->[$i];
foreach my $j($i+1 .. $n-1){
$y2 = $y->[$j];
$x2 = $x->[$j];
Kami juga akan membutuhkan tipe data baru untuk menyimpan array nilai tipe nyata.
CREATE TYPE [dbo].[RealArray] AS TABLE(
[val] [real] NULL
)
Ini adalah fungsi f_QuickMedian , mengembalikan median untuk array yang diberikan. Penghargaan untuk yang satu ini jatuh ke Itzik Ben-Gan .
CREATE FUNCTION [dbo].[f_QuickMedian](@RealArray RealArray READONLY)
RETURNS REAL
AS
BEGIN
DECLARE @Median REAL;
DECLARE @QMedian REAL;
SELECT @Median = AVG(1.0 * val)
FROM
(
SELECT o.val, rn = ROW_NUMBER() OVER (ORDER BY o.val), c.c
FROM @RealArray AS o
CROSS JOIN (SELECT c = COUNT(*) FROM @RealArray) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2);
SELECT TOP 1 @QMedian = val FROM @RealArray
ORDER BY ABS(val - @Median) ASC, val DESC
RETURN @QMedian
END
Dan Penaksir p_TheilSen :
CREATE PROCEDURE [dbo].[p_TheilSen](
@TheilSenInput TheilSenInputDataTableType READONLY
, @m Real OUTPUT
, @c Real OUTPUT
)
AS
BEGIN
DECLARE
@m_arr RealArray
, @c_arr RealArray;
INSERT INTO @m_arr
SELECT m
FROM
(
SELECT
t1.x as x1
, t1.y as y1
, t2o.x as x2
, t2o.y as y2
, t2o.y-t1.y as [y2 - y1]
, t2o.x-t1.x as [x2 - x1]
, CASE WHEN (t2o.x <> t1.x) THEN CAST((t2o.y-t1.y) AS Real)/(t2o.x-t1.x) ELSE NULL END AS [($y2-$y1)/($x2-$x1)]
, CASE WHEN t1.y = t2o.y THEN 0
ELSE
CASE WHEN t1.x = t2o.x THEN NULL
ELSE
-- push @M, ($y2-$y1)/($x2-$x1);
CAST((t2o.y-t1.y) AS Real)/(t2o.x-t1.x)
END
END as m
FROM @TheilSenInput t1
CROSS APPLY
(
SELECT t2.x, t2.y
FROM @TheilSenInput t2
WHERE t2.ID > t1.ID
) t2o
) t
WHERE m IS NOT NULL
SELECT @m = dbo.f_QuickMedian(@m_arr)
INSERT INTO @c_arr
SELECT y - (@m * x)
FROM @TheilSenInput
SELECT @c = dbo.f_QuickMedian(@c_arr)
END
Contoh:
DECLARE
@in TheilSenInputDataTableType
, @m Real
, @c Real
INSERT INTO @in(x,y) VALUES (10.79,118.99)
INSERT INTO @in(x,y) VALUES (10.8,120.76)
INSERT INTO @in(x,y) VALUES (10.86,122.71)
INSERT INTO @in(x,y) VALUES (10.93,125.48)
INSERT INTO @in(x,y) VALUES (10.99,127.31)
INSERT INTO @in(x,y) VALUES (10.96,130.06)
INSERT INTO @in(x,y) VALUES (10.98,132.41)
INSERT INTO @in(x,y) VALUES (11.03,135.89)
INSERT INTO @in(x,y) VALUES (11.08,139.02)
INSERT INTO @in(x,y) VALUES (11.1,140.25)
INSERT INTO @in(x,y) VALUES (11.19,145.61)
INSERT INTO @in(x,y) VALUES (11.25,153.45)
INSERT INTO @in(x,y) VALUES (11.4,158.03)
INSERT INTO @in(x,y) VALUES (11.61,162.72)
INSERT INTO @in(x,y) VALUES (11.69,167.67)
INSERT INTO @in(x,y) VALUES (11.91,172.86)
INSERT INTO @in(x,y) VALUES (12.07,177.52)
INSERT INTO @in(x,y) VALUES (12.32,182.09)
EXEC p_TheilSen @in, @m = @m OUTPUT, @c = @c OUTPUT
SELECT @m
SELECT @c
Pengembalian:
m = 52.7079
c = -448.4853
Hanya untuk perbandingan, versi perl mengembalikan nilai berikut untuk kumpulan data yang sama:
m = 52.7078651685394
c = -448.484943820225
Saya menggunakan estimator TheilSen untuk menghitung metrik DaysToFill untuk sistem file. Nikmati!
Ini kemungkinan besar akan cocok untuk melakukan sesuatu di SQLCLR, mirip dengan Pertanyaan / Jawaban berikut (juga di sini di DBA.SE):
Apakah ada implementasi SQL Server dari masalah Substring Umum Terpanjang?
Ketika saya punya waktu nanti, saya akan melihat betapa layaknya ini.
Saya memeriksa juga, untuk T-SQL, Oracle dan server secara umum (terlalu rumit untuk ditulis dalam SQL murni).
Namun, Anda mungkin tertarik pada ini (paket ilmiah / statistik untuk Python). Algoritma diimplementasikan di sana juga dan di Python. Python adalah bahasa yang manusia setidaknya memiliki sedikit kesempatan untuk bisa mengerti, tidak seperti Perl.
Pertanyaan Anda membuat saya penasaran dan saya menggali. Ada pustaka C dan C ++ yang berisi algoritma ini - dan itu juga tersedia dalam beberapa paket R. Dan postingan @srutzky juga terlihat menarik.
+1 untuk pertanyaan menarik BTW - dan selamat datang di forum :-)