在SQL中的一系列连续行上通过前向填充/LOCF列进行插补?

在SQL中的一系列连续行上通过前向填充/LOCF列进行插补?,sql,time-series,data-warehouse,data-cleaning,Sql,Time Series,Data Warehouse,Data Cleaning,为时间序列分析格式化数据时,通常需要通过填充随时间推移的正向值(也称为上次观测结转/LOCF)来插补缺失值 虽然数据分析环境通常提供该功能(例如Pandasfillna()),但对于较大的数据集,使用SQL进行计算(例如,使用数据并行数据仓库设备)可能更有效 例如,考虑: | UNIT | TIME | VALUE | |------|------|-------| | 1 | 1 | NULL | | 1 | 2 | .5 |

为时间序列分析格式化数据时,通常需要通过填充随时间推移的正向值(也称为上次观测结转/LOCF)来插补缺失值

虽然数据分析环境通常提供该功能(例如Pandas
fillna()
),但对于较大的数据集,使用SQL进行计算(例如,使用数据并行数据仓库设备)可能更有效

例如,考虑:

    | UNIT | TIME | VALUE |
    |------|------|-------|
    | 1    | 1    | NULL  |
    | 1    | 2    | .5    |
    | 1    | 3    | NULL  |
    | 1    | 4    | NULL  |
    | 1    | 5    | .2    |
    | 1    | 6    | NULL  |
    | 2    | 1    | .6    |
    | 2    | 2    | NULL  |
在随时间向前填充值列(独立于每个单位)后,产生:

(注意,1号机组的初始空值无法插补,因为没有先验值)


时间也可以是时间戳或日期时间类型列。

如果使用PostgreSQL风格的SQL方言(例如Netezza PureData)作为日期时间索引(假设为过去的数据),则以下查询结构将实现前向填充。它也适用于多列索引/键

考虑到以下参数:

  • -唯一标识每个时间序列样本的列列表(例如,
    单位、时间
  • -需要插补值的列(例如
  • -时间序列的顺序范围列(例如
    时间
并得出:

  • -除


下面是上述查询的SQLFIDLE:

对于一些数据库,例如Postgres,您可以定义自己的聚合函数。 LOCF只是一个连续的联合体

CREATE OR REPLACE FUNCTION locf_state( FLOAT, FLOAT )
RETURNS FLOAT
LANGUAGE SQL
AS $f$
  SELECT COALESCE($2,$1)
$f$;

CREATE AGGREGATE locf(FLOAT) (
  SFUNC = locf_state,
  STYPE = FLOAT
);
查询的可读性更强:

SELECT unit, time, 
       locf(value) OVER( PARTITION BY unit ORDER BY time )
FROM   mytable;

SQLFIDLE:

关于如何在PostgreSQL上线性插值/插补数值数据SQL:我还有其他问题。如何在mssql上“创建聚合locf”
SELECT DISTINCT T1.UNIT, T1.TIME, 
                COALESCE(T1.VALUE, T2.VALUE) AS VALUE
FROM table T1
LEFT OUTER JOIN (SELECT T1.UNIT, T1.TIME,
                     T1.VALUE,
                     LEAD(T1.TIME,1) 
                         OVER (PARTITION BY T1.UNIT 
                               ORDER BY T1.UNIT, T1.TIME)
                         AS NEXT_RANGE
                     FROM table T1
                     WHERE T1.VALUE IS NOT NULL
                     ORDER BY T1.UNIT, T1.TIME
                ) T2
              ON (T1.TIME BETWEEN T2.TIME
                           AND COALESCE(NEXT_RANGE, CURRENT_DATE)) 
              AND T1.UNIT = T2.UNIT
CREATE OR REPLACE FUNCTION locf_state( FLOAT, FLOAT )
RETURNS FLOAT
LANGUAGE SQL
AS $f$
  SELECT COALESCE($2,$1)
$f$;

CREATE AGGREGATE locf(FLOAT) (
  SFUNC = locf_state,
  STYPE = FLOAT
);
SELECT unit, time, 
       locf(value) OVER( PARTITION BY unit ORDER BY time )
FROM   mytable;