IDL/Math

불규칙 분포 데이터를 규칙 격자화된 데이터로 만들기 [1]

이상우_IDL 2018. 1. 9. 10:30
728x90

이번에 다뤄볼 주제는 제목에도 나와있듯이 2차원 공간상에서 불규칙하게 분포하는 데이터들을 규칙 격자화된 데이터로 만들어나가는 과정에 대한 것입니다. 예를 들어, 기온을 측정하는 장비가 지점별로 여기저기 위치해 있다고 한다면, 그 분포 위치들은 제각각이고 어떤 규칙성을 갖지는 않습니다. 하지만 이렇게 불규칙하게 분포하는 지점들마다 측정된 기온값 데이터를 이용하여 100x100의 격자 구조를 갖는 2차원 데이터를 생성해야 한다면 어떻게 해야 할까요? 이러한 상황은 실제로 흔합니다. 다음 그림은 오늘 사용할 예제 데이터를 그림으로 표출한 것인데, 문제의 이해를 돕기 위하여 먼저 제시해 보았습니다.



이 그림에서 각각의 사각형들이 실제 데이터의 위치이고, 사각형을 채운 색상은 그 위치에서 관측된 데이터 값을 나타냅니다. 이와 같이 불규칙하게 분포하는 데이터들을 기반으로, 규칙 격자 형태의 데이터(50x50이나 100x100 등등)를 어떻게 만들 수 있는가가 바로 이번에 다뤄볼 주제입니다. 물론 당연히 가능합니다. 이 과정은 결국 원래의 데이터 값이 존재하지 않는 격자점들에 대해서 어떤 식으로든 값을 계산해야 하는 일이기 때문에, 기본적으로는 내삽(Interpolation)의 범주에 속하는 작업이라고 볼 수 있습니다. 이러한 작업에서는 세부적으로 여러가지 기법들이 존재합니다. 따라서 어떤 기법을 사용하느냐에 따라 그 결과는 서로 다릅니다. 그리고 이렇게 다양한 기법들로 얻은 결과들 중 어느 것이 가장 믿을만하고 정확한 결과인가에 대해서는 정답이란 것이 따로 존재하지 않습니다. 이 부분은 작업을 수행한 당사자 또는 그 결과를 평가하는 제3자가 판단할 문제입니다. 어쨌든 이러한 작업을 수행하는데 있어서 IDL에서는 구체적으로 어떤 방법을 사용하면 되는가에 대하여 이제부터 소개해보기로 하겠습니다.


먼저 위의 그림에서 제시된 예제 데이터를 생성하는 과정부터 먼저 보겠습니다. 실제로 이 그림상에 존재하는 데이터 포인트들의 총 갯수는 100개입니다. 이러한 가상의 데이터를 생성하기 위한 코드의 내용은 다음과 같습니다.


; Create a dataset of N points.

n = 100 ;# of scattered points

seed = -121147L ;For consistency

x = RANDOMU(seed, n)

y = RANDOMU(seed, n)

PRINT, 'X :', MIN(x), MAX(x)

PRINT, 'Y :', MIN(y), MAX(y)


; Create a dependent variable in the form a function of (x,y)

; with peaks & valleys.

f = 3*EXP(-((9*x-2)^2 + (7-9*y)^2)/4) + $

  3*EXP(-((9*x+1)^2)/49 - (1-0.9*y)) + $

  2*EXP(-((9*x-7)^2 + (6-9*y)^2)/4) - $

  EXP(-(9*x-4)^2 - (2-9*y)^2)

PRINT, 'F :', MIN(f), MAX(f)


여기서는 먼저 데이터 포인트의 X, Y 좌표값들을 난수 생성용 함수인 RANDOMU를 사용하여 각각 100개씩 생성하였습니다. 이렇게 생성된 x, y 두 배열은 각각 0~1의 범위의 값들을 가집니다. 따라서 데이터 포인트들은 X축 및 Y축 방향으로 각각 0~1의 범위 내에 존재하도록 생성됩니다. 그리고 각 데이터 포인트의 값 역시 100개가 생성이 되어 f라는 배열로 저장되었는데, 이 f의 경우 값의 범위가 0~5가 되도록 하였습니다. 다만 f의 경우는 난수로 생성하지 않고 적당한 수식의 함수를 사용하여 값을 생성함으로써 어느 정도의 공간 패턴을 가질 수 있도록 하였습니다. 위에서 정의된 x, y, f에 대하여 최소 및 최대값을 출력하도록 하였는데 그 내용은 다음과 같습니다.


X :   0.00442286     0.996311

Y :    0.0183336     0.999016

F :   -0.0445705      4.80226


이렇게 정의된 가상의 원본 데이터 x, y, f를 SCATTERPLOT 함수를 사용하여 표출하는 과정은 다음과 같습니다.


; Original data display.

win0 = WINDOW(DIMENSIONS=[500, 500], /NO_TOOLBAR, $

  WINDOW_TITLE='Original Data')

ct = COLORTABLE(67, /REVERSE)

scp0 = SCATTERPLOT(x, y, SYMBOL='square', /SYM_FILLED, $

  SYM_SIZE=1.2, XRANGE=[0, 1], YRANGE=[0, 1], RGB_TABLE=ct, $

  MAGNITUDE=f>0<5, MARGIN=[0.1, 0.2, 0.1, 0.1], ASPECT_RATIO=1, $

  TITLE='Original Data', XTITLE='X Coord', YTITLE='Y Coord', /CURRENT)

cbar = COLORBAR(TARGET=scp, RANGE=[0, 5], TITLE='Data Value', $

  POSITION=[0.2, 0.07, 0.8, 0.11], /BORDER)


여기서는 SCATTERPLOT 함수를 사용하여 데이터 포인트들을 위치별로 표시하였는데, MAGNITUDE와 RGB_TABLE 속성을 함께 사용하여 각 위치별 데이터 값을 색상으로 나타내었습니다. 참고로 SCATTERPLOT 함수 사용법에 관해서는 제가 예전에 올렸던 게시물이 있으므로, 필요할 경우 이 내용을 참조하시면 됩니다. 여기서는 MAGNITUDE 속성을 사용하여 0~5의 범위에 맞춰 f의 값들을 표시하고그 값에 따라 색상이 표출되도록 하였습니다. 이 때 사용된 색상은 COLORTABLE 함수를 사용하여 67번 컬러테이블을 순서를 뒤집은 형태로 ct라는 변수에 저장한 후 SCATTERPLOT 함수의 RGB_TABLE 속성에서 사용되었습니다. 그리고 COLORBAR 함수를 사용하여 색상별 데이터 값을 보여주는 컬러바를 함께 표출하였습니다. 어쨌든 위와 같은 내용의 코드를 실행하면 바로 앞서 제시했던 것과 같은 그림을 얻게 됩니다.


그러면 이제부터는 위와 같이 불규칙하게 흩어져 있는 데이터를 기반으로 규칙 격자화된 데이터를 얻는 과정을 살펴보겠습니다. IDL에서는 이러한 작업에 있어서 몇가지 방법들이 존재하는데요. 오늘은 그 중 GRIDDATA라는 함수를 사용하는 방법을 소개하고자 합니다. 이 함수는 불규칙하게 흩어져 있는 데이터를 기반으로 규칙 격자화된 데이터를 계산하는 역할을 합니다. IDL 도움말에서 이 함수에 관한내용을 찾아보면, 이러한 계산에 있어서 세부적으로 다양한 기법들이 지원되는 것을 알 수 있습니다. 도움말에 소개된 기법들은 다음과 같습니다.


Inverse Distance (default)

Natural Neighbor

Kriging

Nearest Neighbor

Linear

Polynomial Regression

Minimum Curvature

Quintic

Modified Shepard’s

Radial Basis Function


사실 제가 이러한 기법들 하나하나에 대해서 세부적으로 소개하려면 양도 너무 많아질 뿐 아니라 실제로 가능하지도 않습니다. 다만 각 기법에 대한 간략한 설명은 IDL 도움말에서 다음과 같이 소개되어 있으므로 이 내용으로 대체하도록 하겠습니다.



이제부터는 이 중 몇가지 기법들을 사용하는 예제 코드를 소개하고 그 결과를 보여드리는 방식으로 진행해볼까 합니다. 그러면 먼저 GRIDDATA 함수가 디폴트로 사용하는 Inverse Distance 기법을 적용하는 과정 및 그 결과를 보는 것부터 시작해 봅시다. 이를 위하여 먼저 다음과 같이 그래픽창을 가로로 긴 형태로 띄우고 맨 왼쪽 칸에 원본 데이터만 먼저 표출해봅시다. 그 결과는 일단 다음 그림과 같습니다.


win1 = WINDOW(DIMENSIONS=[300*4, 300], /NO_TOOLBAR, $

  WINDOW_TITLE='Inverse Distance')

scp1 = SCATTERPLOT(x, y, SYMBOL='square', /SYM_FILLED, $

  SYM_SIZE=1.2, XRANGE=[0, 1], YRANGE=[0, 1], $

  RGB_TABLE=ct, MAGNITUDE=f>0<5, $

  XTICKLEN=0.001, YTICKLEN=0.001, $

  MARGIN=0, /CURRENT, LAYOUT=[4, 1, 1])



이 그림을 보면 그림의 우측으로 아직 비어있는 칸들이 여러 개가 있는데, 여기에는 차후 산출될 결과 데이터들을 차례로 채워넣을 예정입니다. 그럼 이제 본격적으로 GRIDDATA 함수를 사용해보겠습니다. 먼저 다음과 같이 가장 간단한 방식으로 GRIDDATA 함수를 사용해서 결과를 산출해봅시다. 아울러 결과 데이터인 gridded_a에 대한 기본적인 정보들도 출력하도록 하였습니다.


gridded_a = GRIDDATA(x, y, f)

HELP, gridded_a

PRINT, MIN(gridded_a), MAX(gridded_a)


이 때 출력된 내용은 다음과 같습니다.


GRIDDED_A       FLOAT     = Array[25, 25]

     0.103193      4.26358


이 내용을 보면 GRIDDATA 함수를 사용하여 산출된 gridded_a는 25x25의 구조를 갖는 2차원 배열이고 값의 범위는 대략 0.1~4.3 정도임을 알 수 있습니다. 여기서는 GRIDDATA 함수에 최소한의 입력인자들만 투입하고 별도의 추가 설정은 하지 않았는데, 이 경우에는 디폴트 알고리즘인 Inverse Distance 기법이 적용됩니다. 그리고 산출될 결과에 대하여 별도의 설정을 하지 않을 경우 그 배열 구조는 디폴트 설정에 의하여 25x25가 됩니다. 그렇기 때문에 결과가 이와 같이 산출된 것입니다. 그러면 이 결과를 앞서 생성했던 그래픽창에서 원본 데이터의 바로 옆에 표출해봅시다. 그 과정은 다음과 같이 해주면 됩니다.


im1a = IMAGE(gridded_a, RGB_TABLE=ct, MIN_VALUE=0, MAX_VALUE=5, $

  MARGIN=0, /CURRENT, LAYOUT=[4, 1, 2])


그리고 결과를 보면 다음 그림과 같습니다.



이 그림을 보면 불규칙 분포를 했던 원본 데이터를 Inverse Distance 기법에 의하여 규칙격자화하면 어떤 결과가 산출되는가를 알 수 있습니다. 나름 그럴듯한 모습의 결과가 얻어진 것 같습니다. 다만 해상도가 좀 아쉬우므로, 결과 데이터의 배열 구조를 좀 다르게 설정해봅시다. 이를 위해서는 GRIDDATA 함수를 사용하면서 다음과 같이 몇가지 키워드들을 추가적으로 사용해야 합니다.


gridded_b = GRIDDATA(x, y, f, START=0, DELTA=0.02, DIMENSION=51)

HELP, gridded_b

PRINT, MIN(gridded_b), MAX(gridded_b)


이렇게 하여 출력된 내용을 보면 다음과 같습니다. 이 내용을 보면 얻어진 gridded_b의 경우 배열 구조가 51x51임을 알 수 있습니다. 앞서 얻었던 gridded_a에 비하여 두 배 높은 해상도의 결과로 얻어진 셈입니다.


GRIDDED_B       FLOAT     = Array[51, 51]

    0.0473668      4.63828


이러한 결과를 얻을 수 있었던 이유는 GRIDDATA 함수를 사용하면서 START, DELTA, DIMENSION 키워드를 추가적으로 사용했기 때문입니다. 여기서 START 키워드는 격자의 시작점 좌표이고, DELTA는 격자점들 사이의 간격이고, DIMENSION은 격자점의 갯수를 뜻합니다. 물론 이러한 설정은 X축 및 Y축 방향 모두에 대하여 해주는 것이 원칙이기 때문에, 원래는 다음과 같이 적어야 합니다.


gridded_b = GRIDDATA(x, y, f, START=[0, 0], DELTA=[0.02, 0.02], $

  DIMENSION=[51, 51])


하지만 지금 이 예제에서는 X, Y 축 모두 동일한 형태의 격자점 분포를 가정하고 있으므로 그냥 처음에 적었던 것처럼 숫자 하나씩만 적어도 됩니다. 이렇게 하면 모든 차원에 대하여 동일하게 적용됩니다. 어쨌든 이 결과를 다음과 같은 방식으로 그래픽창에서 바로 옆에 붙여서 표출해보면, 그 결과는 다음 그림과 같습니다.


im1b = IMAGE(gridded_b, RGB_TABLE=ct, MIN_VALUE=0, MAX_VALUE=5, $

  MARGIN=0, /CURRENT, LAYOUT=[4, 1, 3])



이와 같이 좀 더 부드러워진 그림을 볼 수 있습니다. 따라서 산출될 결과의 격자 구조나 해상도를 직접 조정해가면서 비교해보는 것도 흥미로울 것 같습니다. 그리고 해상도는 그대로 유지하면서 산출 결과 데이터를 좀 더 부드럽게 뭉게는 것도 가능합니다. 이를 위해서는 다음과 같이 SMOOTH라는 키워드를 추가적으로 사용하면 됩니다.


gridded_c = GRIDDATA(x, y, f, START=0, DELTA=0.02, DIMENSION=51, $

  SMOOTH=0.06)

HELP, gridded_c

PRINT, MIN(gridded_c), MAX(gridded_c)


여기서는 SMOOTH 키워드에 대하여 0.06이라는 값을 부여했는데, 결과 데이터의 격자별 간격이 DELTA 키워드에 의하여 0.02로 설정되어 있으므로 0.06은 3격자에 해당됩니다. 따라서 3x3 격자 형태로 smoothing을 한 결과가 바로 얻어집니다. 그 결과를 다음과 같은 방식으로 그래픽창에서 바로 옆에 붙여서 표출해보면, 그 결과는 다음 그림과 같습니다. 이와 같이 좀 더 부드럽고 완만한 패턴의 결과를 얻을 수도 있습니다.


im1c = IMAGE(gridded_c, RGB_TABLE=ct, MIN_VALUE=0, MAX_VALUE=5, $

  MARGIN=0, /CURRENT, LAYOUT=[4, 1, 4])



GRIDDATA 함수에서 디폴트로 사용되는 Inverse Distance 기법은 말 그대로 특정 격자에 대한 결과값을 산출하는데 있어서 원본 데이터 포인트들의 기여도(weight)가 거리에 선형으로 반비례한다는 즉 1/d로 변한다는 가정을 따릅니다. 즉 가까운 포인트의 영향력이 크고 먼 포인트의 영향력은 작습니다. 가장 무난하고 기본적인 가정이라고 할 수 있습니다. 다만 이 기법의 단점은 주변에 데이터 포인트들이 별로 없는 한산한 지역에서는 격자점에 대한 계산값의 신뢰도가 낮을 수도 있다는 점입니다. 따라서 원본 데이터 포인트들의 분포가 균일하지 않을 경우에는 전체적인 결과가 그리 좋지 않을 수도 있다는 특징이 있습니다. 물론 다른 기법들의 경우 나름대로의 장점과 단점을 갖고 있으므로, 데이터의 특성에 맞는 기법을 선택하는 것도 중요합니다.


오늘은 GRIDDATA 함수를 사용하여 불규칙 분포 데이터를 규칙격자화하는 기본적인 방법 및 관련 예제를 소개해보았습니다. 다음 회차에서는 디폴트 알고리즘인 Inverse Distance 기법 외에 다른 기법을 사용하는 방법 및 관련 예제들을 이어서 소개하기로 하겠습니다.

LIST