앞에서처럼 컴퓨터를 노가다 뛰게 하는 SQL을 만들고서는 어떻게 하면 속도를 개선할까, 정밀도를 높일까... 했는데... 이게 근사식을 만드는 공식이 있었다. 그것도 아주 여러 레코드(Row)를 SUM 하지 않고서도 한 번에 계산이 되는.


애초에 누적정규분포를 구하는 공식은 아래와 같은 적분식인데...누적 정규분포 적분식.jpg

이 적분을 나타나게 해주는 일반적인 식이 없다...라는 게 인터넷 검색 결과였는데... 근사식은 있었던 거...


자 공식 한 번 보자.



누적정규분포 근사식(소수 6째자리).jpg


a0 = 0.2316419
a1 = 0.319381530
a2 = –0.356563782
a3 = 1.781477937
a4 = –1.821255978
a5 = 1.330274429


근사식만 봐도 골치아플 거 같다. 이해하기 싫으면 그냥 아래 SQL을 퍼가기만 하자.


SELECT  CASE
            WHEN :InpVal >= :mean THEN 1 - FX_VAL /* 입력값이 평균보다 이상일 경우 */
            ELSE FX_VAL                           /* 입력값이 평균보다 작을 경우 */
        END AS REGULAR_DISTRIBUTE
FROM
    (
        SELECT  (
                    (A1 * Y)
                  + (A2 * POWER(Y, 2))
                  + (A3 * POWER(Y, 3))
                  + (A4 * POWER(Y, 4))
                  + (A5 * POWER(Y, 5))
                )
                *
                  ----------------------------
                  -- 아래는 위 수식의 f(x) 부분
                  ----------------------------
                  (   EXP( -1 * POWER(X, 2) / 2)
                    / SQRT( 2 * ACOS(-1) )        /* SQRTPI(2) */
                  )
                AS FX_VAL
        FROM
            (
                SELECT   A0
                       , A1
                       , A2
                       , A3
                       , A4
                       , A5
                       , X
                       , 1 / (1 + (A0 * X)) AS Y
                FROM
                    (
                        SELECT    0.2316419     AS A0
                                , 0.319381530   AS A1
                                , -0.356563782  AS A2
                                , 1.781477937   AS A3
                                , -1.821255978  AS A4
                                , 1.330274429   AS A5
                                , ABS( :InpVal - :mean ) / :stdv AS X   /* 표준정규분포 변환식 */
                        FROM    DUAL
                    )
           )
     )
;


SQL 의 주석이랑 수식을 비교해보면 대충 감이 올 거다. 안오면 할 수 없고. 위의 SQL은 표준정규분포의 누적함수 개념을 차용했지만, 변환식을 중간에 넣어놨기 때문에 사용자가 입력값들을 표준정규분포로 변환할 필요는 없다. 물론 평균 0, 표준편차 1로 하는 걸로 :InpVal 을 변환해도 상관없고.


결과나 보자.


누적정규분포 근사 SQL(소수 6째자리) 결과 01.jpg


엑셀 결과는 아래와 같다.



상당히 많이 근접했다. 이 케이스의 경우 소수점 이하 8째 자리까지이지만 일반적으로는 6째 자리까지라고 한다.




그럼 다른 케이스를 검증해보자.


누적정규분포 근사 SQL(소수 6째자리) 결과 02.jpg


누적정규분포 근사 SQL(소수 6째자리) 결과 02 (엑셀).jpg


여기서는 소수점 이하 6째 자리까지만 맞다.


이와 같이 이 SQL은 이후에 나올 정밀도 높은 거보다는 길이가 짧고, 바탕 수식도 이해하기 쉬워서 소수점 이하 6째 자리 정도로만 해도 충분할 경우에는 (고등학교 통계 시간에 본 정규분포표도 소수점 이하 4째 자리까지만 나온다) 저걸로 써도 된다.


하지만 소수점 이하 10째 자리 이상의 정밀도가 필요할 경우에는 다음 글의 SQL을 사용해야 한다.

profile

이브리타, 나의 에뜨와르
너와 내가 공유하는 추억
너와 내가 만들 추억