postgres的线性回归

时间:2013-12-10 09:36:57

标签: postgresql datetime regression linear

我使用 Postgres ,我有大量的行,每个站点的值和日期。 (日期可以隔开几天。)

id      | value | idstation | udate
--------+-------+-----------+-----
1       |  5    | 12        | 1984-02-11 00:00:00
2       |  7    | 12        | 1984-02-17 00:00:00
3       |  8    | 12        | 1984-02-21 00:00:00
4       |  9    | 12        | 1984-02-23 00:00:00
5       |  4    | 12        | 1984-02-24 00:00:00
6       |  8    | 12        | 1984-02-28 00:00:00
7       |  9    | 14        | 1984-02-21 00:00:00
8       |  15   | 15        | 1984-02-21 00:00:00
9       |  14   | 18        | 1984-02-21 00:00:00
10      |  200  | 19        | 1984-02-21 00:00:00

原谅可能是一个愚蠢的问题,但我不是一个数据库专家。

是否可以直接输入一个SQL查询,该查询将为每个日期计算每个日期的线性回归,因为知道回归必须仅使用实际ID日期,之前的id日期和下一个id日期来计算?

例如,id 2 的线性回归必须使用值7(实际),5(上一个),8(下一个)计算日期1984-02-17,1984-02 -11和1984-02-21

编辑:我必须使用 regr_intercept(value,udate),但如果我只使用实际的,之前和之后我真的不知道怎么做每行的下一个值/日期。

Edit2 :将3行添加到idstation(12); ID和日期编号已更改

希望你能帮帮我,谢谢!

4 个答案:

答案 0 :(得分:10)

这是Joop的统计数据和Denis的窗口函数的组合:

WITH num AS (
        SELECT id, idstation
        , (udate - '1984-01-01'::date) as idate -- count in dayse since jan 1984
        , value AS value
        FROM thedata
        )
        -- id + the ids of the {prev,next} records
        --  within the same idstation group
, drag AS (
        SELECT id AS center
                , LAG(id) OVER www AS prev
                , LEAD(id) OVER www AS next
        FROM thedata
        WINDOW www AS (partition by idstation ORDER BY id)
        )
        -- junction CTE between ID and its three feeders
, tri AS (
                  SELECT center AS this, center AS that FROM drag
        UNION ALL SELECT center AS this , prev AS that FROM drag
        UNION ALL SELECT center AS this , next AS that FROM drag
        )
SELECT  t.this, n.idstation
        , regr_intercept(value,idate) AS intercept
        , regr_slope(value,idate) AS slope
        , regr_r2(value,idate) AS rsq
        , regr_avgx(value,idate) AS avgx
        , regr_avgy(value,idate) AS avgy
FROM num n
JOIN tri t ON t.that = n.id
GROUP BY t.this, n.idstation
        ;

结果:

INSERT 0 7
 this | idstation |     intercept     |       slope       |        rsq        |       avgx       |       avgy       
------+-----------+-------------------+-------------------+-------------------+------------------+------------------
    1 |        12 |               -46 |                 1 |                 1 |               52 |                6
    2 |        12 | -24.2105263157895 | 0.578947368421053 | 0.909774436090226 | 53.3333333333333 | 6.66666666666667
    3 |        12 | -10.6666666666667 | 0.333333333333333 |                 1 |             54.5 |              7.5
    4 |        14 |                   |                   |                   |               51 |                9
    5 |        15 |                   |                   |                   |               51 |               15
    6 |        18 |                   |                   |                   |               51 |               14
    7 |        19 |                   |                   |                   |               51 |              200
(7 rows)

使用rank()或row_number()函数可以更优雅地完成 group of of three 的聚类,这也可以使用更大的滑动窗口。

答案 1 :(得分:1)

DROP SCHEMA zzz CASCADE;
CREATE SCHEMA zzz ;
SET search_path=zzz;

CREATE TABLE  thedata
        ( id      INTEGER NOT NULL PRIMARY KEY
        , value INTEGER NOT NULL
        , idstation  INTEGER NOT NULL
        , udate DATE NOT NULL
        );
INSERT INTO thedata(id,value,idstation,udate) VALUES
 (1      ,5   ,12       ,'1984-02-21' )
,(2      ,7   ,12       ,'1984-02-23' )
,(3      ,8   ,12       ,'1984-02-26' )
,(4      ,9   ,14       ,'1984-02-21' )
,(5      ,15  ,15       ,'1984-02-21' )
,(6      ,14  ,18       ,'1984-02-21' )
,(7      ,200 ,19       ,'1984-02-21' )
        ;

WITH a AS (
        SELECT idstation
        , (udate - '1984-01-01'::date) as idate -- count in dayse since jan 1984
        , value AS value
        FROM thedata
        )
SELECT  idstation
        , regr_intercept(value,idate)  AS intercept
        , regr_slope(value,idate)  AS slope
        , regr_r2(value,idate)  AS rsq
        , regr_avgx(value,idate)  AS avgx
        , regr_avgy(value,idate)  AS avgy
FROM a
GROUP BY idstation
        ;

输出:

 idstation |     intercept     |       slope       |        rsq        |       avgx       |       avgy       
-----------+-------------------+-------------------+-------------------+------------------+------------------
        15 |                   |                   |                   |               51 |               15
        14 |                   |                   |                   |               51 |                9
        19 |                   |                   |                   |               51 |              200
        12 | -24.2105263157895 | 0.578947368421053 | 0.909774436090226 | 53.3333333333333 | 6.66666666666667
        18 |                   |                   |                   |               51 |               14
(5 rows)

注意:如果你想要类似样条曲线的回归,你也应该使用lag()和lead()窗口函数,就像Denis的回答一样。

答案 2 :(得分:0)

如果平均值适合你,你可以使用avg build in ...像

这样的东西
SELECT avg("value") FROM "my_table" WHERE "idstation" = 3;

应该这样做。对于更复杂的事情,你需要编写一些pl / SQL函数,我担心或检查PostgreSQL上的插件。

答案 3 :(得分:0)

查看窗口功能。如果我正确地回答了您的问题,lead()lag()可能会准确地为您提供所需内容。用法示例:

select idstation as idstation,
       id as curr_id,
       udate as curr_date,
       lag(id) over w as prev_id,
       lag(udate) over w as prev_date,
       lead(id) over w as next_id,
       lead(udate) over w as next_date
from dates
window w as (
partition by idstation order by udate, id
)
order by idstation, udate, id

http://www.postgresql.org/docs/current/static/tutorial-window.html