Có ai có chức năng hồi quy Theil-Sen được viết bằng T-SQL không?
Tôi đã tìm thấy một bản viết bằng Perl , nhưng tôi không thể mã hóa lại thành SQL.
Có ai có chức năng hồi quy Theil-Sen được viết bằng T-SQL không?
Tôi đã tìm thấy một bản viết bằng Perl , nhưng tôi không thể mã hóa lại thành SQL.
Câu trả lời:
Tôi đã nói dối khi tôi nói, tôi không thể mã hóa lại thành SQL. Tôi đã quá lười biếng. Đây là mã với một ví dụ về việc sử dụng.
Mã được dựa trên thư viện TheiSen perl, sử dụng QuickMedian . Hãy xác định một loại bảng mới để dễ dàng chuyển dữ liệu của chúng tôi đến quy trình.
CREATE TYPE dbo.TheilSenInputDataTableType AS TABLE
(
ID INT IDENTITY(1,1),
x REAL,
y REAL
)
Vui lòng lưu ý cột ID, điều quan trọng ở đây vì giải pháp của chúng tôi sử dụng câu lệnh CROSS ỨNG DỤNG để đạt được giải thích chính xác về vòng lặp bên trong được tìm thấy trong 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];
Chúng ta cũng sẽ cần một kiểu dữ liệu mới để lưu trữ một mảng các giá trị kiểu thực.
CREATE TYPE [dbo].[RealArray] AS TABLE(
[val] [real] NULL
)
Đây là hàm f_QuickMedian , trả về trung vị cho mảng đã cho. Tín dụng cho điều này đi đến 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
Và Công cụ ước tính 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
Thí dụ:
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
Trả về:
m = 52.7079
c = -448.4853
Chỉ để so sánh, phiên bản perl trả về các giá trị sau cho cùng một tập dữ liệu:
m = 52.7078651685394
c = -448.484943820225
Tôi sử dụng công cụ ước tính TheilSen để tính toán số liệu DaysToFill cho các hệ thống tập tin. Thưởng thức!
Điều này rất có thể sẽ phù hợp để thực hiện điều gì đó trong SQLCLR, tương tự như Câu hỏi / Trả lời sau (cũng ở đây trên DBA.SE):
Có một SQL Server thực hiện vấn đề Chuỗi con chung dài nhất không?
Khi tôi có thời gian sau đó, tôi sẽ thấy điều này khả thi đến mức nào.
Tôi cũng đã kiểm tra, đối với T-SQL, Oracle và các máy chủ nói chung (quá phức tạp để được viết bằng SQL thuần túy).
Tuy nhiên, bạn có thể quan tâm đến điều này (gói khoa học / thống kê cho Python). Thuật toán được thực hiện ở đó và trong Python. Python là ngôn ngữ mà con người có ít nhất một số cơ hội để có thể hiểu, không giống như Perl.
Câu hỏi của bạn hấp dẫn tôi và tôi đã đào xung quanh. Có các thư viện C và C ++ chứa thuật toán này - và nó cũng có sẵn trong một vài gói R. Và bài đăng của @srutzky cũng có vẻ thú vị.
+1 cho một câu hỏi thú vị BTW - và chào mừng bạn đến với diễn đàn :-)