Oracle SQL для выполнения локальных факторов выбросов (LOF) с евклидовым расстоянием - PullRequest
2 голосов
/ 19 апреля 2020

У меня есть пример данных, как показано ниже, и я хотел выполнить локальные коэффициенты выбросов (LOF) с евклидовым расстоянием , а затем отфильтровать / идентифицировать из нормальных значений. Я знаю, что мы можем легко сделать это, используя ML Platform, но любопытно, сможем ли мы добиться того же, используя oracle SQL.

DT     DEPT_ID  SAL
201907   10      5      
201907   10      28378  
201907   10      34     
201907   10      2      
201907   10      1800   
201907   10      723        
201907   10      701            
201907   10      38877  
201907   10      3628   
201907   10      16818.28   
201907   10      10         
201907   10      3574.16        
201907   10      199994.73  
201907   10      1073173        
201907   10      1999999.94 
201907   10      468682.16  
201907   10      19999997.15    
201907   10      21999998.46    
201907   10      16580003.29    
201907   10      5909999.69 
201907   10      49130  
201907   10      10000  

ожидаемый результат. Здесь выброс> 50 не соответствует норме

 LOF_outlier    date     dept_id   sal
        0.8      201907   10        2
        0.8      201907   10        5
        0.8      201907   10        10
        0.8      201907   10        34
        0.8      201907   10        701
        0.8      201907   10        723
        0.9      201907   10        1800
        1.0      201907   10        3574
        1.0      201907   10        3628
        2.2      201907   10        10000
        2.9      201907   10        16818
        3.9      201907   10        28378
        4.9      201907   10        38877
        6.4      201907   10        49130
        26.3     201907   10        199994
        50.7     201907   10        468682
        73.4     201907   10        1073173
        125.0    201907   10        1999999
        274.6    201907   10        5909999
        311.3    201907   10        16580003
        373.5    201907   10        19999997
        411.3    201907   10        21999998

1 Ответ

1 голос
/ 20 апреля 2020

Вот попытка вычислить LOF (локальные коэффициенты выбросов) для данных в вашей выборке. Как я сказал в комментарии к вашему вопросу, не существует только одного набора LOF; существует параметризованное семейство, зависящее от положительного целочисленного параметра k, который я смоделировал как переменную связывания ниже.

Я вычислил LOF для различных значений k; Я не смог сопоставить ваш вывод (и, действительно, мне интересно, действительно ли ваш вывод правильный). В любом случае, это демонстрация концепции - если моя математика или мой код (или оба) неверны, это можно исправить.

Вот ссылка на оригинальный (2000) документ, в котором Была представлена ​​концепция LOF; соответствующие определения приведены на страницах 3 и 4. https://www.dbs.ifi.lmu.de/Publikationen/Papers/LOF.pdf

Подзапросы в предложении WITH ниже следуют определениям шаг за шагом - k- d istance в подзапросе d, k-расстояние n двойное расстояние и расстояние достижимости в подзапросе n, l плотность достижимости ocal в l и локальные выбросы в конечном итоге запрос. Ниже я показываю запрос и результаты для k = 12.

variable k number
exec :k := 12

with
  p (rn, sal) as (
    select row_number() over (order by sal), sal 
    from   t
  )
, b (rn, sal, dist, drk) as (
    select p.rn, p.sal, abs(p1.sal - p.sal), 
           row_number() over (partition by p.sal order by abs(p1.sal - p.sal)) 
    from   p join p p1 on p1.rn between p.rn - :k and p.rn + :k
  )
, d (rn, sal, kdist) as (
    select b.rn, b.sal, b.dist
    from   b
    where  b.drk = :k + 1
  )
, n (rn, sal, pt_rn, pt, rdist) as (
    select d.rn, d.sal, d1.rn, d1.sal, greatest(abs(d1.sal - d.sal), d1.kdist)
    from   d join d d1 on abs(d1.sal - d.sal) <= d.kdist and d1.rn != d.rn
  )
, l (rn, sal, lrd) as (
    select rn, sal, 1/avg(rdist)
    from   n
    group  by rn, sal
  )
select l.sal as sal, round(avg(l1.lrd) / l.lrd, 2) as lof
from   n join l    on n.rn    = l.rn
         join l l1 on n.pt_rn = l1.rn
group  by l.rn, l.sal, l.lrd
order  by l.rn
;

Вывод:

       SAL        LOF
---------- ----------
         2        .99
         5        .99
        10        .99
        34        .99
       701        .99
       723        .99
      1800        .99
   3574.16          1
      3628          1
     10000       1.01
  16818.28       1.03
     28378       1.02
     38877          1
     49130       1.23
 199994.73       5.21
 468682.16      11.36
   1073173      23.08
1999999.94      39.61
5909999.69     106.26
16580003.3     196.89
19999997.2     227.52
21999998.5     245.42
...