(Oracle)去除异常值

(Oracle)Removing outlier

目标是去除超过异常值的+-标准差后得到平均值。 对于我的tableACTUAL_OUTPUT中的EQUIP E1,MODEL M1,有6个数据,10,10,100000,10,10.10。 因此预期结果是 10,因为在这种情况下,100000 是异常值。

我的table和数据如下。 我已经对此进行了查询。 还有比这更好的方法吗?

 --Table and data  

 CREATE TABLE ACTUAL_OUTPUT
     (
       EQUIP VARCHAR2(15),
       MODEL VARCHAR2(15),
       LOT VARCHAR2(15),
       VAL NUMBER
    )
    delete FROM ACTUAL_OUTPUT;
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L1',10);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L2',10);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L3',100000);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L4',10);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L5',10);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M1','L6',10);
    INSERT INTO ACTUAL_OUTPUT VALUES('E1','M2','L7',50);



 -- Is there a better way then this?     
   SELECT avg(VAL_2) OUTLIER_REMOVED
    FROM
    (
    SELECT 
    EQUIP,
    MODEL,
    CASE WHEN
    VAL <= AVG(VAL) OVER (PARTITION BY EQUIP,MODEL)+2*STDDEV(VAL) OVER (PARTITION BY EQUIP,MODEL)
    AND 
    VAL >= AVG(VAL) OVER (PARTITION BY EQUIP,MODEL)-2*STDDEV(VAL) OVER (PARTITION BY EQUIP,MODEL)
    THEN VAL ELSE NULL END VAL_2
    FROM ACTUAL_OUTPUT
    )
    WHERE EQUIP='E1' AND MODEL = 'M1';

我会这样写:

SELECT avg(VAL_2) as OUTLIER_REMOVED
FROM (SELECT ao.*,
             STDDEV(VAL) OVER (PARTITION BY EQUIP, MODEL) as val_stddev,
             AVG(VAL) OVER (PARTITION BY EQUIP, MODEL) as val_avg
      FROM ACTUAL_OUTPUT ao
      WHERE EQUIP = 'E1' AND MODEL = 'M1'
     ) ao
WHERE VAL >= val_avg - 2 * val_stddev AND
      VAL <= val_avg + 2 * val_stddev;

但是,假设您的数据库有一个好的优化器,性能应该是一样的。

有什么区别?

  • where 子句在子查询中。大多数优化器无论如何都应该这样做,但我希望尽快进行过滤,以防优化器感到困惑。
  • 平均值和标准偏差的计算仅表示一次。再一次,一个好的优化器不会 运行 window 函数多次。
  • 过滤公式在外层查询中。因为它不使用window函数,所以阅读和验证要简单得多。
  • 这不依赖于 NULL 在外部查询中被忽略。通过过滤删除异常值。