【问题标题】:Postgres regr_slope returning NULLPostgres regr_slope 返回 NULL
【发布时间】:2019-03-22 00:18:43
【问题描述】:

有人可以帮我理解regr_slope在数据集中有行的情况下返回NULL的情况吗?例如:

log=> select * from sb1 order by id, ts;
  id  | elapsed |       ts       
------+---------+----------------
 317e |      86 | 1552861322.627
 317e |      58 | 1552861324.747
 317e |      52 | 1552861325.722
 317e |      58 | 1552861326.647
 317e |      82 | 1552861327.609
 317e |     118 | 1552861328.514
 317e |      58 | 1552861329.336
 317e |      58 | 1552861330.317
 317e |      54 | 1552861330.935
 3441 |      68 | 1552861324.765
 3441 |      84 | 1552861326.665
 3441 |      56 | 1552861327.627
 3441 |      50 | 1552861330.952
 5fe6 |      42 | 1552993248.398
 5fe6 |      44 | 1552993255.883
 5fe6 |      44 | 1553166049.261
 c742 |      62 | 1552861322.149
 c742 |      68 | 1552861322.455
(18 rows)

log=> select id, regr_slope(elapsed, ts) as trend from sb1 group by id;
  id  |        trend         
------+----------------------
 c742 |                     
 317e |                     
 5fe6 | 5.78750952760444e-06
 3441 |                     
(4 rows)

有趣的是,相同的数据集和函数在 Oracle 11.2 中返回不同的结果:

SQL> select * from sb1 order by id, ts;

ID            ELAPSED               TS
---------- ---------- ----------------
317e               86   1552861322.627
317e               58   1552861324.747
317e               52   1552861325.722
317e               58   1552861326.647
317e               82   1552861327.609
317e              118   1552861328.514
317e               58   1552861329.336
317e               58   1552861330.317
317e               54   1552861330.935
3441               68   1552861324.765
3441               84   1552861326.665
3441               56   1552861327.627
3441               50   1552861330.952
5fe6               42   1552993248.398
5fe6               44   1552993255.883
5fe6               44   1553166049.261
c742               62   1552861322.149
c742               68   1552861322.455

18 rows selected.

SQL> select id, regr_slope(elapsed, ts) from sb1 group by id;

ID         REGR_SLOPE(ELAPSED,TS)
---------- ----------------------
c742                   19.6078431
5fe6                   5.7875E-06
317e                   -1.0838511
3441                   -3.8283951

我不知道这是否意味着 Postgres、Oracle 有问题,或者两者都没有,尽管5fe6 的结果是一样的。

【问题讨论】:

  • 我没查,是不是回归线是垂直的? PostgreSQL 源有:/* per spec, return NULL for a vertical line */
  • 感谢@LaurenzAlbe,根据 Oracle 返回的值,它们甚至不接近垂直。您认为这是我应该报告的错误吗?

标签: postgresql rounding linear-regression aggregate-functions sql-null


【解决方案1】:

钻研代码后,我有了答案:

问题是 PostgreSQL v12 之前的幼稚方法在这种情况下会导致不必要的大舍入错误。

让我们考虑id = 'c742'

regr_slope 的公式是这样的:

regr_slope := (N ⋅ Σ(XiY em>i) - ΣXi ⋅ ΣYi) / (N ⋅ Σ(Xi2) - ΣXi ⋅ ΣX)

问题出在除数上:

SELECT 2::float8 * (1552861322.149::float8 * 1552861322.149::float8 +
                    1552861322.455::float8 * 1552861322.455::float8) -
       (1552861322.149::float8 + 1552861322.455::float8) *
       (1552861322.149::float8 + 1552861322.455::float8);

 ?column? 
----------
    -2048 
(1 row)

由于结果是否定的,PostgreSQL 返回 NULL 结果。

使用精确计算(使用numeric)不会发生这种情况:

SELECT 2 * (1552861322.149 * 1552861322.149 +
            1552861322.455 * 1552861322.455) -
       (1552861322.149 + 1552861322.455) *
       (1552861322.149 + 1552861322.455);

 ?column? 
----------
 0.093636
(1 row)

自从 PostgreSQL 提交 e954a727f0c8872bf5203186ad0f5312f6183746 后,事情得到了改进,在 PostgreSQL v12 中,PostgreSQL 也返回了正确的结果:

select id, regr_slope(elapsed, ts) from sb1 group by id;

  id  |      regr_slope       
------+-----------------------
 c742 |    19.607858781290517
 317e |   -1.0838511987808963
 5fe6 | 5.787509483586743e-06
 3441 |    -3.828395463097356
(4 rows)

【讨论】:

    【解决方案2】:

    事实证明,这是由于我的 x 轴具有较大的值导致的 Sxx 值计算中的错误。如果您有兴趣,请在 here 进行描述。

    因为我的 x 值是从 extract(epoch from tstz_col) 派生的,所以我很容易减去一个“基”值,这样 Sxx 计算就不会溢出。例如:

    log=> select id, regr_slope(elapsed, ts - extract(epoch from now())) as trend from sb1 group by id;
      id  |        trend         
    ------+----------------------
     c742 |     19.5839996337891
     317e |    -1.08384865545836
     5fe6 | 5.78750948360273e-06
     3441 |    -3.82839498627572
    (4 rows)
    

    结果与 Oracle 返回的结果并不完全相同,但我只是在寻找“趋势”,所以在我的情况下它们很好。

    H.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-28
      • 2016-12-11
      • 2019-12-31
      • 1970-01-01
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多