(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
在外部查询中被忽略。通过过滤删除异常值。
目标是去除超过异常值的+-标准差后得到平均值。 对于我的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
在外部查询中被忽略。通过过滤删除异常值。