IDL/배열 생성 및 처리

IDL에서 배열의 생성에 관한 각종 팁들 정리

이상우_idl 2020. 7. 16. 18:14
728x90
반응형

어떤 프로그래밍 언어든지 다 마찬가지이겠지만 IDL에서도 배열의 생성 및 처리는 모든 작업의 기본입니다. 이와 관련하여 IDL 도움말, 관련 서적들 또는 제 블로그에 있는 관련 게시물들 등 여러가지 참고 자료들이 있습니다. 저도 모처럼 찾아보니까 이 블로그에서도 제가 여러 차례 관련 게시물들을 올렸더군요. 그래서 오늘 또 이런 주제로 게시물을 올리는 것이 다소 재탕이 될 위험성이 없지는 않지만, 그래도 기존에 제가 다루었던 내용들과 새로운 내용들을 적절히 섞어서 정리를 해보았습니다. 최근에 (주)에스이랩에서 발송했던 "IDL의 배열 생성 관련 팁"이라는 제목의 한장강의가 있었는데, 여기에 지면 관계상 다 실을 수 없었던 추가적이고 보충적인 내용들을 이 게시물에서 본격적으로 정리해보았습니다.

 

 

< 2차원 및 3차원 배열의 생성 >

 

 

배열을 생성할 때 ~~~ARR 또는 ~~~INDGEN과 같은 배열 생성용 함수들을 사용하기도 하지만, 원소값들을 직접 적어줘야 하는 경우도 있습니다. 이 경우 기본적으로 [ ] 괄호를 사용하면 되는데, 1차원 배열의 경우는 다음과 같습니다.

 

arr = [4, 7, 8, 6, 3]

 

그런데 2차원 배열을 직접 원소값들을 적어서 생성하는 경우에는 [ ] 괄호를 다음과 같이 2중으로 사용해야 합니다. 예를 들어 3x2의 구조를 갖는 2차원 배열의 경우는 다음과 같습니다.

 

arr = [ [7, 6, 3], [9, 11, 8] ]

HELP, arr

PRINT, arr

 

이렇게 하여 생성된 배열에 관하여 출력된 내용은 다음과 같습니다.

 

ARR             INT       = Array[3, 2]

       7       6       3

       9      11       8

 

그리고 3차원 배열의 경우도 직접 원소값들을 적어서 생성할 수 있습니다. 위의 2차원의 경우에서 한 단계 확장하면 됩니다. 예를 들어 2x2x3의 구조를 갖는 3차원 배열의 경우는 다음과 같습니다.

 

arr = [ [ [3, 5], [9, 4] ], [ [8, 6], [1, 7] ], [ [4, 2], [8, 3] ] ]

HELP, arr

PRINT, arr

 

이렇게 하여 생성된 배열에 관하여 출력된 내용은 다음과 같습니다.

 

ARR             INT       = Array[2, 2, 3]

       3       5

       9       4

 

       8       6

       1       7

 

       4       2

       8       3

 

 

< 순차적인 규칙성을 갖는 배열의 생성 >

 

 

이것은 예를 들어 0, 0.2, 0.4, 0.6, ....과 같이 순차적으로 규칙성을 갖는 값들로 구성된 배열을 생성하는 경우입니다. 만약 0.0으로 시작하여 1.0으로 끝나고 간격이 0.2인 실수형 값들로 구성된 배열을 생성한다면 전통적인 방법으로는 다음과 같이 하면 됩니다.

 

arr = FINDGEN(6)*0.2

 

그런데 IDL 8.3 버전부터는 다음과 같이 콜론 기호 :를 사용하는 문법에 의하여 똑같은 결과를 얻을 수도 있습니다.

 

arr = [0:1:0.2] 또는 arr = [0.0:1.0:0.2]

 

그리고 만약 100으로 시작하여 50으로 끝나고 간격이 -10인 정수형 값들로 구성된 배열을 생성하는 경우를 봅시다. 즉 100, 90, 80, 70, 60, 50의 순서로 일정 간격으로 감소하는 값들로 구성된 배열을 만들고자 할 경우 전통적인 방법으로는 다음과 같이 하면 됩니다.

 

arr = 100-10*INDGEN(6)

 

하지만 IDL 8.3부터는 다음과 같은 문법을 사용해도 똑같은 결과를 얻을 수 있습니다.

 

arr = [100:50:-10]

 

이러한 새로운 문법은 IDL 8.3부터 지원되기 시작했기 때문에, 혹시라도 IDL 8.3 이전 버전과의 호환성이 필요한 경우에는 사용하면 안된다는 점을 유의해야 합니다. 사실 이 내용은 제가 이 블로그에서 다루었던 적이 있습니다. 어차피 같은 얘기이긴 하지만 참조를 위하여 그 게시물의 링크도 올립니다.

 

blog.daum.net/swrush/284

 

 

< 통일된 값들로 구성된 배열의 생성 >

 

 

배열 내 값들이 모두 똑같은 형태로 배열을 생성하는 방법입니다. 원래 IDL에서 지원되는 ~~~ARR이라는 이름의 배열생성 함수들을 사용하여 숫자들로 구성된 배열을 생성하면 배열 내 값들은 모두 0으로 통일됩니다. 즉, 정수형인 INTARR을 사용하면 0이고 실수형인 FLTARR의 경우는 0.0입니다. 그런데 0이 아닌 다른 값으로 통일된 배열을 만들고자 한다면 MAKE_ARRAY라는 함수를 사용하는 것이 좋습니다. 예를 들면 다음과 같습니다.

 

arr = MAKE_ARRAY(4, 3, VALUE=20)

HELP, arr

PRINT, arr

 

이렇게 하면 4x3의 형태를 갖는 2차원의 정수형 배열이 생성되면서, 배열 내 값들이 모두 20으로 통일됩니다. 실제로 출력된 내용을 보면 다음과 같습니다.

 

ARR             INT       = Array[4, 3]

      20      20      20      20

      20      20      20      20

      20      20      20      20

 

MAKE_ARRAY 함수로 생성되는 배열의 자료형은 VALUE 키워드에 부여된 값에 따라 결정됩니다. 예를 들어, 만약 20 대신 20.0으로 적으면 실수형 배열로 생성됩니다. 사실 위와 같은 결과를 얻기 위하여 그냥 다음과 같이 해도 상관은 없습니다.

 

arr = INTARR(4, 3)+20

 

이렇게 해도 어차피 결과는 똑같습니다. 하지만 어떤 값으로 통일될 것인지에 대한 정보를 명확하게 볼 수 있으려면 아무래도 MAKE_ARRAY 함수를 사용하는 것이 더 낫지 않을까 생각합니다. 만약 -9999.0이라는 값 10개로 구성된 실수형 1차원 배열을 생성한다면 다음과 같이 하면 될 것입니다.

 

arr = MAKE_ARRAY(10, VALUE=-9999.0)

 

그리고 만약 NaN 값으로 통일된 형태로 1차원 배열을 생성한다면 다음과 같이 하면 될 것입니다.

 

arr = MAKE_ARRAY(10, VALUE=!values.f_nan)

 

 

< 행 또는 열의 내용이 반복되는 2차원 배열 생성 >

 

 

예를 들어 2차원 배열을 생성하고자 하는데 가로 방향의 행(Row)이 [2, 5, 7, 8]과 같고 이러한 형태가 세로 방향으로 6회 반복되어 6줄이 되는 배열을 생성하는 경우를 가정해봅시다. 이러한 2차원 배열을 직접 생성하려면 다음과 같이 가로 및 세로 방향의 형태를 정의하는 1차원 배열을 각각 생성하고, 이 두 배열에 대하여 행렬연산자 #를 적용하면 됩니다.

 

arr1 = [2, 5, 7, 8]

arr2 = MAKE_ARRAY(6, VALUE=1)

arr = arr1#arr2

HELP, arr

PRINT, arr

 

생성된 배열에 대한 정보 및 배열값들이 출력된 모습은 다음과 같습니다.

 

ARR             LONG      = Array[4, 6]

         2         5         7         8

         2         5         7         8

         2         5         7         8

         2         5         7         8

         2         5         7         8

         2         5         7         8

 

이번에는 세로 방향의 열(Column)이 [2, 5, 7, 8]과 같고 이러한 형태가 가로 방향으로 6회 반복되어 6열이 되는 배열을 생성하는 경우를 가정해봅시다. 이 경우에는 문법상으로는 위의 경우와 거의 유사하지만 다음과 같이 연산자가 # 대신 ##이 되어야 합니다. 나머지는 동일합니다.

 

arr = arr1##arr2

 

이렇게 생성된 배열에 대한 정보 및 배열값들이 출력된 모습은 다음과 같습니다.

 

ARR             LONG      = Array[6, 4]

      2      2      2      2      2      2

      5      5      5      5      5      5

      7      7      7      7      7      7

      8      8      8      8      8      8

 

즉 이와 같이 6x4의 형태를 갖는 배열로 생성됩니다. 여기서는 ## 연산자를 사용하였는데, 다음과 같이 # 연산자를 사용해도 똑같은 결과를 얻을 수 있습니다.

 

arr = arr2#arr1

 

그 대신 연산에 투입되는 두 배열의 순서를 바꿔줘야 한다는 점을 유의해야 합니다. 어쨌든 행렬연산자 # 또는 ##를 이용하여 원하는 결과를 얻을 수 있습니다. 이러한 기법에 관해서는 역시 제가 이 블로그에서 관련 게시물을 예전에 올린 바 있습니다. 참조를 위하여 링크를 첨부합니다.

 

blog.daum.net/swrush/445

 

 

< 배열의 크기 부풀리기(?) >

 

 

배열 내 값들을 그래도 유지하되 크기만 더 부풀리는 즉 배열 크기를 팽창시키는 경우입니다. 예를 들면 원본 배열은 [2, 5, 7, 8]과 같이 4개의 값들로 구성되어 있는데, 개수를 12개로 늘리면서 값들 자체는 각각 3개씩으로 늘어난 형태로 만드는 경우입니다.  [2, 2, 2, 5, 5, 5, 7, 7, 7, 8, 8, 8]과 같은 구성이 되도록 만들고자 한다면 어떻게 하면 될까요? 여기서 약간 의외의 게스트가 등장하는데 바로 CONGRID 함수입니다. 다음과 같이 CONGRID 함수를 이용하면 됩니다.

 

arr0 = [2, 5, 7, 8]

arr = CONGRID(arr0, 12, /CENTER)

HELP, arr

PRINT, arr

 

이렇게 하여 생성된 배열 arr의 값들을 출력해보면 확인이 가능합니다. 출력된 내용은 다음과 같습니다.

 

ARR             INT       = Array[12]

       2       2       2       5       5       5       7       7       7       8       8       8

 

이와 같이 처음에는 4개 짜리 배열이었지만 각 원소값을 3개씩 늘려서 총 12개의 값들로 구성된 배열로 늘린 것입니다. 만약 4개씩으로 부풀려서 2, 2, 2, 2, 5, 5, 5, 5, ....와 같이 총 16개의 값들로 구성된 배열로 만들고자 한다면 위의CONGRID 함수 내용에서 12 16으로 바꿔주면 됩니다. 직접 확인해보시기 바랍니다. 사실 IDL 유저들에게 CONGRID는 그리 낯선 함수는 아닙니다. 아마도 주로 2차원 이미지 배열의 크기를 변경할 때 많이들 사용하셨을 것 같습니다. 하지만 위와 같은 방식으로도 이용이 가능합니다. 그 이유는 CONGRID 함수를 사용하여 배열의 크기를 늘릴 경우 그만큼 격자들의 갯수도 늘어나는데, 늘어난 각 격자점의 값을 내삽할 때 기본적으로 Sampling 기법을 사용하기 때문입니다. 즉 주변의 가장 가까운 원본 값을 끌어오기 때문에 이러한 효과를 얻게 되는 것입니다. 다만 유의할 것은 /CENTER 키워드를 반드시 사용해야 합니다. 그러지 않으면 약간 엉뚱한 결과가 나오기 때문입니다. 만약 위의 내용에서 /CENTER 키워드를 빼먹게 되면 결과는 다음과 같습니다.

 

arr0 = [2, 5, 7, 8]

arr = CONGRID(arr0, 12)

HELP, arr

PRINT, arr

 

ARR             INT       = Array[12]

       2       2       5       5       5       7       7       7       8       8       8       8

 

이와 같이 각각의 값이 동일한 갯수로 늘려지지 않습니다. 따라서 /CENTER 키워드의 사용이 반드시 필요하다는 점을 유의해야 합니다. 그리고 이러한 기법은 2차원 배열에 대해서도 응용이 가능합니다.

 

 

만약 원본 배열이 [[2, 5], [7, 8]]로 구성된 2x2인 2차원 배열인데, 각 원소값이 3x3만큼 복제되어서 총 6x6의 형태를 갖도록 팽창된 배열을 생성하려면 다음과 같이 하면 됩니다. 원본 2x2 배열은 arr0라고 간주합니다.

 

arr0 = [[2, 5], [7, 8]]

arr = CONGRID(arr0, 6, 6, /CENTER)

HELP, arr

PRINT, arr

 

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

 

ARR             INT       = Array[6, 6]

       2       2       2       5       5       5

       2       2       2       5       5       5

       2       2       2       5       5       5

       7       7       7       8       8       8

       7       7       7       8       8       8

       7       7       7       8       8       8

 

 

< 누적에 의한 배열의 증식(?) >

 

 

배열에 대하여 원소값을 추가적으로 계속 붙여나가면서 그 크기가 점점 늘어나도록 하는 경우입니다. 제가 적당한 용어가 생각이 안나서 그냥 배열의 증식이라고 표현을 해보았습니다. 예를 들어서 처음에는 [6, 4, 7]로 3개의 값들로만 구성되었던 배열이 있을 때, 값을 추가적으로 붙여나가면서 4, 5개 이런 식으로 배열 크기를 늘려나가는 것입니다. 이런 식의 처리를 위해서는 [ ] 괄호 안에 원본 배열과 추가 값을 함께 적어주면 됩니다. 예를 들어 [6, 4, 7]과 같이 3개의 값들로 구성된 초기 배열 arr이 있을 때, 추가적으로 2라는 값을 붙여서 4개 짜리 배열로, 그리고 이어서 5라는 값을 붙여서 5개 짜리 배열로 증식시키려면 다음과 같이 하면 됩니다.

 

arr = [6, 4, 7]

arr = [arr, 2]

HELP, arr

PRINT, arr

arr = [arr, 5]

HELP, arr

PRINT, arr

 

이렇게 하여 HELP, PRINT에 의하여 출력된 내용은 다음과 같습니다.

 

ARR             INT       = Array[4]

       6       4       7       2

ARR             INT       = Array[5]

       6       4       7       2       5

 

이와 같이 배열의 크기가 점점 커지는 것을 확인할 수 있습니다. 그리고 심지어는 초기 배열이 null이어도 됩니다. 즉 처음에는 전혀 배열이 아니었던 것에 값들을 계속 붙여나가면서 결국 배열로 만드는 것입니다. 무에서 유를 창조하는 셈입니다.

 

arr = !null

arr = [arr, 2]

arr = [arr, 5]

arr = [arr, 4]

 

이렇게 하면 arr은 처음에는 아무것도 아닌 null이었지만 결국 [2, 5, 4]의 형태를 갖는 배열로 진화하게 됩니다. 이러한 기법은 반복형 구문에서 활용하면 편리합니다. 즉 처음에는 배열의 크기를 정할 수 없지만 계속 값들을 붙여나가면서 제대로 된 배열로 완성해가야 하는 작업에서 그 진가를 발휘합니다. 반복형 구문이 사용된 예는 다음과 같습니다.

 

arr = !null

FOR j = 1, 5 DO arr = [arr, j*3]

HELP, arr

PRINT, arr

 

이렇게 하면 arr은 처음에는 아무것도 아니었지만 반복에 의하여 3, 6, 9, 12, 15의 값들이 순차적으로 추가되어 결국 5개의 값들로 구성된 배열로 완성됩니다.

 

ARR             INT       = Array[5]

       3       6       9      12      15

 

이와 같이 배열의 크기를 증식시키는 방법에 관해서는 제가 예전에 관련 게시물을 올렸던 적이 있습니다. 이 내용도 함께 참조하시면 좋을 것 같습니다. 링크는 아래와 같습니다.

 

blog.daum.net/swrush/174

 

 

< 2차원 배열에 행 또는 열 추가하기 >

 

 

앞서 1차원 배열을 증식시키는 기법을 소개하였는데, 2차원 배열 역시 크기의 증식이 가능합니다. 즉 2차원 배열이 있을 때, 가로 방향의 행(Row)을 추가로 더 붙이거나 세로 방향의 열(Colume)을 추가로 더 붙이는 것입니다. 예를 들어 다음과 같이 3x2의 구조를 갖는 2차원 배열이 있다고 합시다.

 

arr = [ [7, 6, 3], [9, 11, 8] ]

HELP, arr

PRINT, arr

 

ARR             INT       = Array[3, 2]

       7       6       3

       9      11       8

 

여기에 [20, 20, 20]과 같은 가로 방향의 행(Row)을 추가로 더 붙여서 3x3의 배열로 만들 수 있습니다. 이를 위해서는 다음과 같이 해주면 됩니다.

 

arr = [ [arr], [20, 20, 20] ]

HELP, arr

PRINT, arr

 

그 결과 arr은 다음과 같이 3x3 배열이 됩니다.

 

ARR             INT       = Array[3, 3]

       7       6       3

       9      11       8

      20      20      20

 

처음에 정의했던 3x2의 배열 arr에 세로 방향의 열(Column)을 붙이는 것도 가능합니다. 다만 이 경우에는 추가될 열을 정의할 때 다음과 같이 TRANSPOSE 함수를 반드시 이용해야 합니다.

 

arr = [ [7, 6, 3], [9, 11, 8] ]

arr = [ [arr], TRANSPOSE([20, 20]) ]

 

그러면 결과적으로 다음과 같이 4x2 배열이 됩니다.

 

ARR             INT       = Array[4, 2]

       7       6       3      20

       9      11       8      20

 

 

이상과 같이 배열의 생성과 관련된 여러가지 팁들을 정리해보았습니다. 배열의 생성 또는 처리와 관련해서는 이 블로그에서도 다른 관련 게시물들이 많이 있으니 그런 내용들도 추가적으로 참조하시기 바랍니다. 그리고 이번에 언급했던 내용들 외에 또 다른 괜찮은 팁들에 대해서도 나중에 정리가 되면 여기서 마저 소개하도록 하겠습니다.

반응형