Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Czy w SQL Server jest jakaś funkcja regresji liniowej?

Według mojej najlepszej wiedzy nie ma żadnego. Napisanie jednego jest jednak dość proste. Poniżej przedstawiono stałą alfa i nachylenie beta dla y =Alpha + Beta * x + epsilon:

-- 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

Tutaj GroupID służy do pokazania, jak grupować według jakiejś wartości w tabeli danych źródłowych. Jeśli chcesz tylko statystyki dla wszystkich danych w tabeli (a nie określonych podgrup), możesz je usunąć i sprzężenia. Użyłem WITH oświadczenie dla jasności. Alternatywnie możesz użyć podzapytań. Należy pamiętać o precyzji typu danych używanego w tabelach, ponieważ stabilność liczbowa może się szybko pogorszyć, jeśli precyzja nie jest wystarczająco wysoka w stosunku do danych.

EDYTUJ: (w odpowiedzi na pytanie Petera o dodatkowe statystyki, takie jak R2 w komentarzach)

Możesz łatwo obliczyć dodatkowe statystyki przy użyciu tej samej techniki. Oto wersja z R2, korelacją i kowariancją próbki:

-- 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

EDYTUJ 2 poprawia stabilność numeryczną poprzez standaryzację danych (zamiast tylko centrowanie) i zastąpienie STDEV z powodu problemy ze stabilnością numeryczną . Wydaje mi się, że obecna implementacja jest najlepszym kompromisem między stabilnością a złożonością. Mógłbym poprawić stabilność, zastępując moje odchylenie standardowe liczbowo stabilnym algorytmem online, ale to znacznie skomplikowałoby implementację (i spowolniłoby ją). Podobnie implementacje wykorzystujące m.in. Odszkodowania Kahan(-Babuška-Neumaier) za SUM i AVG wydają się działać nieco lepiej w ograniczonych testach, ale sprawiają, że zapytanie jest znacznie bardziej złożone. I tak długo, jak nie wiem, jak T-SQL implementuje SUM i AVG (np. może już używać sumowania parami), nie mogę zagwarantować, że takie modyfikacje zawsze poprawiają dokładność.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy możliwa jest synchronizacja w czasie rzeczywistym 2 baz danych SQL Server?

  2. Obsługuj wiele aktualizacji bazy danych z c# w SQL Server 2008

  3. SQL Jak zaktualizować SUMA kolumny nad grupą w tej samej tabeli

  4. Wydajność serwera SQL:co jest szybsze, procedura składowana czy widok?

  5. czy możemy mieć klucz obcy, który nie jest kluczem podstawowym w żadnej innej tabeli?