IDL/Programming

NaN 값의 이해와 활용 [2]

이상우_idl 2016. 1. 15. 16:53
반응형

지난 게시물에 이어서 오늘은 NaN값에 대한 예제로서 다음과 같이 6개의 실수값들로 이루어진 배열에 대하여 제곱근 연산을 수행하고 그 결과를 얻어봅시다.


y = [3.76.28.3, -7.65.5, 4.6]

result = SQRT(y)

PRINT, result


출력된 결과값들은 다음과 같습니다. 역시나 NaN이 등장합니다. 배열 y안에 (-)인 값이 하나 있었기 때문입니다.


      1.92354      2.48998      2.88097         -NaN      2.34521      2.14476


이제 이 result라는 배열을 플롯의 형태로 표출해보겠습니다. 이해를 돕기 위하여 두가지 방식으로 그려보려고 합니다. 먼저 다음과 같이 PLOT 함수를 사용하되 각 포인트들을 원형 심볼로 표시하고 서로 선으로 이어지지는 않도록 표출해 봅시다. 그러면 그 결과는 다음 그림과 같습니다.


win = WINDOW(DIMENSIONS=[600, 400])

pl = PLOT(result, SYMBOL='circle', /SYM_FILLED, SYM_SIZE=2, COLOR='crimson', $

    LINESTYLE=6, CLIP=0, /CURRENT)



이 그림을 보면 중간에 있는 NaN에 해당되는 데이터 포인트는 아예 표시가 되지 않았음을 알 수 있습니다. 이와 같이 데이터의 표출에 있어서 NaN에 해당되는 값은 아예 표출의 대상에서 제외되어 버립니다. 그리고 위와 같은 플롯을 이번에는 다음과 같이 각 포인트 사이를 선으로 이어서 표출해 봅시다. 그러면 그 결과는 다음 그림과 같습니다.


win = WINDOW(DIMENSIONS=[600400])

pl = PLOT(result, SYMBOL='circle', /SYM_FILLED, SYM_SIZE=2, COLOR='crimson', $

    CLIP=0, /CURRENT)



이와 같이 데이터 포인트들이 선으로 이어지는 와중에도 NaN에 해당되는 부분은 아예 제껴버립니다. 이러한 방식은 1차원이든 2차원이든 마찬가지입니다. 2차원 이미지의 경우에도 이미지 데이터에 해당되는 배열안에 NaN값이 있다면 그 부분은 표출 대상에서 아예 제외되어 버립니다. 마찬가지 원리입니다.


지금까지는 NaN값이 나의 의도와는 상관없이 발생한 경우를 주로 언급했던 셈인데, 이번에는 NaN값을 의도적으로 활용하는 예제를 살펴보겠습니다. 다음과 같은 데이터 값들을 다루게 될 경우들이 실제로 종종 있습니다.


data = [3.7, 6.2, 8.3, -9999, 5.5, 4.6, -9999, 7.1, 9.4, 5.6]


즉, 측정이나 관측이 제대로 이루어지지 않아서 정상적인 값이 존재하지 않을 경우 이러한 부분에 대하여 -9999와 같은 아주 비정상적인 수치를 의도적으로 채워넣는 경우입니다. 측정이나 관측 데이터들 중에서 이러한 식으로 공급되는 경우들이 꽤 많습니다. 하지만 이러한 상태로 그림을 그리거나 계산을 수행하게 되면 당연히 이상한 결과가 나올 수 밖에 없기 때문에, 비정상 값들은 어떤 식으로든 처리를 해야 합니다. 일단 아예 제껴버리는 방법을 생각해볼 수 있습니다. 그런데 그렇다고 해서 -9999를 아예 제거한다면 다음과 같은 형태가 될텐데요.


data = [3.76.28.3, 5.54.6, 7.19.45.6]


이 경우에는 데이터의 갯수 자체가 바뀌게 됩니다. 작업의 성격에 따라서는 이러한 변화가 바람직하지 않을 수도 있습니다. 즉, 데이터의 전체 갯수는 그대로 유지한 상태에서도 처리 과정에서 필요없는 데이터를 제낄 수 있는 방법이 필요할 수도 있는데, 이 때 바로 NaN값을 의도적으로 활용하면 됩니다. 이를 위하여 다음과 같이 원본 데이터(-9999가 존재했던)에 대하여 WHERE 함수를 적용합니다.


ww = WHERE(data LT -9000, count)

IF count NE 0 THEN data[ww] = !values.f_nan

PRINT, data


여기서는 data 배열의 값들 중 -9000보다 작은 것들을 찾도록 하고, 해당 값을 NaN으로 대체하였습니다. 물론 WHERE 안의 조건을 -9999와 같은 경우를 찾으라는 식으로 명시해도 됩니다. 그리고 해당 값을 NaN으로 대체하는데 있어서는 !values.f_nan이라는일종의 시스템 상수를 사용하였습니다. NaN값을 IDL이 유저에게 보여줄 때에는 NaN이라고 표기되지만, 내가 직접 NaN값을 명시하고자 할 때에는 !values.f_nan이라고 표기해야 한다는 점을 유의해야 합니다. 이와 같이 WHERE에 의한 처리를 거친 data의 값들을 출력해보면 다음과 같이 원래 -9999였던 값들이 모두 NaN으로 대체되어 있음을 확인할 수 있습니다.


      3.70000      6.20000      8.30000          NaN      5.50000      4.60000          NaN      7.10000      9.40000      5.60000


그러면 이렇게 변환된 data를 후속 작업에 활용하면 됩니다. 다음과 같이 MEAN 함수를 사용하여 평균값을 구해보면 정상적인 결과를 얻을 수도 있고, 그림을 그려보면 NaN인 부분은 아예 표시가 되지 않은 채로 표출됩니다.


PRINT, MEAN(data, /NAN)

win = WINDOW(DIMENSIONS=[600, 400])

pl = PLOT(data, SYMBOL='circle', /SYM_FILLED, SYM_SIZE=2, COLOR='crimson', $

  LINESTYLE=6, CLIP=0, /CURRENT)



따라서 이와 같이 NaN이라는 값은 예기치않게 등장하여 방해가 될 경우도 있지만, 역으로 잘 활용하면 작업에 있어서 매우 효과적일 수도 있다는 점을 잘 염두에 두면 좋을 것 같습니다.

반응형