IDL/Math

NaN, Infinity와 FINITE 함수

이상우_idl 2020. 8. 10. 11:33
728x90
반응형

우리가 데이터를 다루다보면 숫자값들 중에 실질적으로 아무 의미가 없는 값들이 나오는 경우가 있습니다. 바로 NaN 값과 무한대(Infinity) 값입니다. 특히 숫자값들로 구성된 배열의 형태로 데이터를 다룰 때 그 배열 내에 군데군데 이러한 무의미한 값들이 낑겨들어가 있는 경우는 흔히 있는 일입니다. 예를 들어서 10개의 실수값들로 구성된 배열 x와 y가 있는데, 배열 y의 값들 중 일부가 이러한 무의미한 값들인 경우를 가정해봅시다.

 

x = [0:90:10.]

y = [3.7, 6.2, SQRT(-4.1), 8.3, 5.5, 4.6, 6.8/0, ALOG10(-3.2), 7.1, 7.8]

HELP, x, y

PRINT, y

 

여기서 배열 y의 값들을 잘 보면 -4.1의 제곱근, 6.8을 0으로 나눈 값, -3.2의 상용로그 값이 중간중간에 포함되어 있습니다. 이러한 값들은 수학적으로 NaN 또는 Infinity와 같은 무의미한 값에 해당됩니다. 실제로 HELP 및 PRINT 명령에 의하여 출력된 내용은 다음과 같습니다.

 

X               FLOAT     = Array[10]

Y               FLOAT     = Array[10]

     3.70000     6.20000        -NaN     8.30000     5.50000     4.60000         Inf        -NaN     7.10000      7.80000

 

여기서 배열 y의 값들이 출력된 내용을 보면 NaN과 Infinity가 혼재해 있음을 알 수 있습니다. 그러면 먼저 여기서 정의된 x, y 데이터를 플롯의 형태로 표출해봅시다. 이를 위한 예제 코드는 다음과 같습니다.

 

win1 = WINDOW(DIMENSIONS=[600, 400], /NO_TOOLBAR)

pl = PLOT(x, y, SYMBOL='circle', /SYM_FILLED, SYM_SIZE=2, $

  XRANGE=[0, 100], YRANGE=[0, 10], COLOR='crimson', $

  FONT_SIZE=11, CLIP=0, /CURRENT)

 

여기서는 데이터 포인트들이 붉은 점으로 표시되도록 하고 서로 실선으로 이어지도록 설정하였습니다. 결과는 다음 그림과 같습니다.

 

 

이 그림을 잘 보면 NaN, Infinity와 같은 무의미한 값은 표출에서 아예 제외되었음을 확인할 수 있습니다. 어차피 이러한 값들은 표출에 있어서 위치라는 것 자체가 무의미하기 때문에 IDL이 자체적으로 이런 식으로 처리를 합니다. 어쨌든 이와 같이 무의미한 값에 해당되는 부분이 의도적으로 누락된 것이 그대로 드러나도록 처리되어 표출되면, 눈으로 봐도 '아~ 이런 부분은 뭔가 문제가 있는 값들이 있던 자리였나보네' 하는 짐작을 충분히 할 수 있다고 봅니다.

 

그런데 만약 이렇게 누락된 티가 전혀 나지 않게, 즉 유의미한 값들끼리만 서로 자연스럽게 이어서 표출되도록 하는 것이 경우에 따라서는 필요할 수도 있습니다. 그럴 경우에는 무의미한 값들이 아예 제외된 형태로 데이터를 다시 구성해야 합니다. 이러한 작업을 위해서는 FINITE 함수와 WHERE 함수를 함께 사용하는 것이 필요합니다. 먼저 FINITE 함수는 단일값 또는 배열에 대하여 NaN이나 Infinity와 같은 무의미한 값을 판별해내는 역할을 합니다. 예를 들어 위에서 정의한 배열 y 내의 몇몇 값들에 대하여 FINITE 함수를 적용해보면 결과는 다음과 같습니다.

 

IDL> PRINT, FINITE(6.2)

   1

IDL> PRINT, FINITE(SQRT(-4.1))

   0

IDL> PRINT, FINITE(6.8/0)

   0

 

즉 이와 같이 FINITE 함수를 유의미한 값에 사용할 경우에는 1을 돌려주고 NaN이나 Infinity와 같은 무의미한 값에 사용할 경우에는 0을 돌려줍니다. FINITE 함수를 배열에 대하여 적용하면 배열 내 모든 원소값들에 대한 판별값들을 배열의 형태로 돌려줍니다. 따라서 만약 다음과 같은 내용을 위의 예제코드에 추가한다면 그 결과가 출력될 것입니다.

 

PRINT, FINITE(y)

 

출력된 결과는 다음과 같습니다.

 

   1   1   0   1   1   1   0   0   1   1

 

따라서 여기서 WHERE 함수를 사용하여 유의미한 값들만 걸러내는 것이 가능합니다. 즉 FINITE의 결과가 1인 값들만 추려내는 것입니다.

 

ww = WHERE(FINITE(y) EQ 1, count)

PRINT, count

PRINT, ww

PRINT, y[ww]

 

           7

           0           1           3           4           5           8           9

      3.70000      6.20000      8.30000      5.50000      4.60000      7.10000      7.80000

 

여기서 출력된 결과 내용을 보면 원래 데이터 배열의 10개의 값들 중 유의미한 값들의 갯수는 7개입니다. 그리고 ww는 해당 값들의 인덱스들이고 y[ww]는 해당 값들 자체가 됩니다. 이렇게 얻어진 ww를 이용하여 앞서 표출에 사용했던 PLOT 함수에서 x, y 대신 x[ww], y[ww]를 사용하면 됩니다. 즉 앞서 제시된 예제코드 내용에서 PLOT 함수가 사용된 부분만 다음과 같은 내용을 대체합니다.

 

pl = PLOT(x[ww], y[ww], SYMBOL='circle', /SYM_FILLED, SYM_SIZE=2, $

  XRANGE=[0, 100], YRANGE=[0, 10], COLOR='crimson', $

  FONT_SIZE=11, CLIP=0, /CURRENT)

 

그러면 그 결과는 다음 그림과 같습니다.

 

 

물론 이 표출은 마치 NaN이나 Infinity와 같은 무의미한 값들이 데이터에 전혀 없는 것처럼 보이도록 표출한 경우입니다. 따라서 만약 원래는 무의미한 값들이 엄연히 존재했음에도 불구하고 이러한 방식으로 표출했다면, 적어도 이 그림을 보는 사람들에게는 원래의 데이터 내에서 무의미한 값들이 어느 정도 존재했었는가에 대한 정보를 함께 제공하는 것이 필요할 수도 있다고 봅니다 (제 생각입니다).

 

이와 같이 FINITE 함수를 사용하는 일반적인 방식은 그 결과가 1이냐 0이냐에 따라서 유의미한 값이냐 무의미한 값이냐를 구분하는 것입니다. 그런데 FINITE 함수에는 세부적으로는 NaN 또는 Infinity를 차별화하여 찾아내는 기능도 있습니다. 만약 배열 y 내의 값들 중에서 NaN인 경우만 특정하여 찾아내고 싶을 경우에는 다음과 같이 /NAN 키워드를 사용하면 됩니다.

 

ww = WHERE(FINITE(y, /NAN) EQ 1, count)

PRINT, count

PRINT, ww

PRINT, y[ww]

 

이렇게 하여 출력된 결과는 다음과 같습니다.

 

           2

           2           7

         -NaN         -NaN

 

즉 NaN에 해당되는 값들의 갯수는 2개이고 그 인덱스는 2, 7이라는 의미입니다. 여기서 주의할 점은, /NAN 키워드를 사용할 경우에는 결과가 1이면 NaN 값에 해당되는 것이고 결과가 0이면 NaN이 아니라는 것입니다. 그래서 WHERE 함수에서 기준 값을 1로 사용했음을 유의해야 합니다. 그리고 이와 같이 /NAN 키워드를 사용할 경우에는 말 그대로 NaN만 찾아낼 뿐 Infinity는 찾지 않습니다. 만약 Infinity만 찾고자 할 경우에는 다음과 같이 /INFINITY 키워드를 사용하면 됩니다.

 

ww = WHERE(FINITE(y, /INFINITY) EQ 1, count)

PRINT, count

PRINT, ww

PRINT, y[ww]

 

이렇게 하여 출력된 결과는 다음과 같습니다.

 

           1

           6

          Inf

 

즉 Infinity에 해당되는 값들의 갯수는 1개이고 그 인덱스는 6이란 의미입니다. 여기서도 역시 주의할 점은, /INFINITY 키워드를 사용할 경우에는 결과가 1이면 Infinity 값에 해당되는 것이고 결과가 0이면 Infinity 값이 아니라는 것입니다. 그래서 WHERE 함수에서 기준 값을 1로 사용했음을 유의해야 합니다. 그리고 이와 같이 /INFINITY 키워드를 사용할 경우에는 말 그대로 Infinity 값만 찾아낼 뿐 NaN 값은 찾지 않습니다.

 

그리고 마지막으로 한가지만 더 언급한다면, 이와 같이 NaN이나 무한대와 같은 무의미한 값들이 포함된 배열에 대하여 추가적인 처리 및 연산을 할 경우에는 각별한 유의가 필요합니다. 예를 들어서 배열 y의 값들에 대한 평균값을 MEAN 함수를 이용하여 산출하는 경우를 봅시다. 다음과 같이 하면 될 것처럼 보일 수도 있습니다.

 

PRINT, MEAN(y)

 

하지만 예제 코드 내에 이러한 내용을 삽입해서 계산을 해보면 그 값은 아마도 NaN으로 산출될 것입니다. 왜냐하면 NaN이나 Infinity와 같은 무의미한 값들도 모두 포함된 채로 연산이 수행되었기 때문입니다. 만약 무의미한 값들을 제외하고 나머지 유의미한 값들로만 제한하여 평균값을 산출하고자 한다면 다음과 같이 /NAN 키워드를 함께 사용해야 합니다.

 

PRINT, MEAN(y, /NAN)

 

이렇게 하면 키워드의 이름 자체는 /NAN이긴 하지만 실제로는 NaN, Infinity와 같은 무의미한 값들을 알아서 제외시키고 나머지 유의미한 값들만을 사용하여 연산을 수행하게 됩니다. 이렇게 하면 아마 6.17이라는 결과값이 얻어질 것입니다. IDL에서는 위의 MEAN 함수 뿐 아니라 그 외 상당수의 수치계산용 내장함수들이 /NAN 키워드를 지원합니다. IDL 도움말에서 해당 내장함수에서 지원되는 키워드 목록에 /NAN이 있으면 됩니다.

 

반응형