MATLAB에서의 행렬 인덱싱
작성자: Steve Eddins 및 Loren Shure, MathWorks
행렬 인덱싱은 행렬의 요소 중 일부를 선택하거나 수정하는 데 쓰이는 방법입니다. MATLAB®에는 강력하고 유연하며 가독성과 표현력도 우수한 여러 인덱싱 스타일이 있습니다. 행렬은 MATLAB에서 데이터 구성과 분석에 핵심적인 구성요소이며, 인덱싱은 행렬을 이해 가능한 방식으로 조작하는 데 필수적인 작업입니다.
인덱싱은 MATLAB 사용자들이 자주 접하는 또 다른 용어인 벡터화와 밀접히 연관되어 있습니다. 벡터화는 스칼라 연산 대신 MATLAB 행렬과 벡터 연산을 사용하는 작업인데, 이 방법을 활용하면 일반적으로 코드가 더 짧아지고 수학적 표현력과 가독성도 우수해지며 때로는 연산 속도도 빨라집니다.
벡터 인덱싱
먼저 벡터와 첨자의 간단한 사례부터 살펴봅시다.
v = [16 5 9 4 2 11 7 14];
첨자는 아래처럼 단일한 값일 수 있습니다.
v(3) % 3번째 요소 추출
ans =
9
또는 첨자 자체가 또 하나의 벡터일 수도 있습니다.
v([1 5 6]) % 1번째, 5번째, 6번째 요소 추출
ans =
16 2 11
MATLAB의 콜론 표기법을 통해 v에서 일정 범위의 요소를 쉽게 추출할 수 있습니다.
v(3:7) % 3번째부터 7번째 요소까지 추출
ans =
9 4 2 11 7
v를 반으로 나눈 후 이들의 순서를 바꿔 새로운 벡터를 만들 수 있습니다.
v2 = v([5:8 1:4]) % v를 반으로 나눠 추출하고 순서 변경
v2 =
2 11 7 14 16 5 9 4
특수 연산자인 end
를 사용하면 v의 마지막 요소를 쉽고 빠르게 참조할 수 있습니다.
v(end) % 마지막 요소 추출
ans =
14
end
연산자는 범위에서도 사용할 수 있습니다.
v(5:end) % 5번째부터 마지막 요소까지 추출
ans =
2 11 7 14
또한 end
로 산술을 수행할 수도 있습니다.
v(2:end-1) % 2번째부터 마지막에서 2번째 요소까지 추출
ans =
5 9 4 2 11 7
콜론 연산자와 end
를 조합하여 k번째 요소를 모두 추출하거나 전체 벡터를 뒤집는 등 다양한 효과를 줄 수 있습니다.
v(1:2:end) % 홀수 번째 요소 모두 추출 ans = 16 9 2 7 v(end:-1:1) % 요소의 순서 반전 ans = 14 7 11 2 4 9 5 16
등호 좌변의 인덱싱 표현식을 사용하여 벡터의 특정 요소를 교체할 수 있습니다.
v([2 3 4]) = [10 15 20] % v의 일부 요소 교체
v =
16 10 15 20 2 11 7 14
일반적으로, 우변의 요소의 수는 좌변에서 인덱싱 표현식으로 참조되는 요소의 수와 동일해야 합니다. 하지만 오른쪽에는 언제든지 스칼라를 사용할 수 있습니다. 이를 가리켜 스칼라 확장이라고 합니다.
v([2 3]) = 30 % 2번째, 3번째 요소를 30으로 교체
v =
16 30 30 20 2 11 7 14
기억할 사항: MATLAB은 1부터 시작하는 인덱싱을 사용합니다. 행렬 인덱싱에 있어 몇몇 언어는 0부터 시작합니다. MATLAB과 같은 다른 언어들은 1부터 시작합니다. MATLAB은 수학 교과서에서 볼 법한 표기법과 동일한 방법을 따릅니다. MATLAB은 왜 1부터 시작했을까요? MATLAB의 최초 개발자인 Cleve Moler의 말에 따르면 “그게 바로 수학의 법칙이기 때문입니다.”
두 첨자를 사용한 행렬 인덱싱
이제 행렬에서 요소를 참조해 봅시다. 여기서는 마방진을 예로 사용할 것입니다.
A = magic(4) A = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1
행렬의 요소를 참조할 때에는 2개의 첨자를 사용하는 경우가 가장 많으며, 첫 번째 첨자는 행을 뜻하고 두 번째는 열을 뜻합니다.
가장 단순한 형식에서는 하나의 요소만 추출합니다.
A(2,4) % 2번째 행과 4번째 열의 요소 추출
ans =
8
때로는 행렬에서 여기저기 흩어진 요소를 선택하는 방법이 혼란스러운 경우도 있습니다. 예를 들어 A에서 (2,1), (3,2), (4,4) 위치의 요소를 추출해야 한다고 가정해 봅시다.
A([2 3 4], [1 2 4])라는 표현식으로는 원하는 결과를 얻을 수 없습니다. 아래의 다이어그램은 2개의 첨자로 인덱싱하면 어떻게 되는지를 보여줍니다.
행렬에서 흩어진 요소를 추출하려면 다른 스타일의 인덱싱이 필요하므로 다음 주제로 넘어가 보겠습니다.
선형 인덱싱
A(14)
라는 표현식은 어떻게 기능할까요?
첨자 하나만 사용해서 행렬 A로 인덱싱을 하면 MATLAB은 A의 요소가 아래와 같이 여러 열을 아래로 길게 연이은 열 벡터 형태로 늘어진 것처럼 간주합니다.
16
5
9
...
8
12
1
팁: MATLAB은 열 우선적이며, 선형 인덱싱은 각 열을 연이어 내려가면서 시작합니다.
A(14)
표현식은 이렇게 암묵적으로 나열된 열 벡터의 14번째 요소를 간단히 추출해 냅니다. 이처럼 첨자 하나만 사용하는 행렬 내 인덱싱 방식은 흔히 선형 인덱싱이라고 불립니다.
각 행렬 요소의 왼쪽 상단에 선형 인덱스를 표시한 이 다이어그램에서는 A(14)
가 A(2,4)
와 동일함을 확인할 수 있습니다.
하나의 첨자가 아래처럼 둘 이상의 선형 인덱스를 포함한 벡터일 수도 있습니다.
A([6 12 15]) ans = 11 15 12
A의 (2,1), (3,2), (4,4) 요소만 추출하는 문제를 다시 살펴봅시다. 이 요소들은 선형 인덱싱으로 추출할 수 있습니다.
A([2 7 16]) ans = 5 7 1
이 예제로는 한눈에 보기 쉽지만, 선형 인덱스는 보통 어떻게 계산할까요? MATLAB은 행과 열의 첨자를 선형 인덱스로 변환하는 sub2ind
라는 함수를 제공합니다. 이 함수를 사용하면 원하는 요소를 아래와 같이 추출할 수 있습니다.
idx = sub2ind(size(A), [2 3 4], [1 2 4]) ans = 2 7 16 A(idx) ans = 5 7 1
논리형 인덱싱
또 다른 인덱싱 방법인 논리형 인덱싱은 간결함과 우수한 표현력으로 영상 처리 등의 여러 응용 분야에 유용한 표기법입니다. 논리형 인덱싱에서는 행렬 첨자에 단일한 논리형 배열을 사용합니다.
예시로 사용할 만한 논리형 배열은 아래와 같습니다.
A > 12
ans =
4×4 logical array
1 0 0 1
0 0 0 0
0 0 0 0
0 1 1 0
이 숫자들은 행렬에서 논리식이 참인 위치를 가리키는데, 이 경우엔 12보다 큰 모든 숫자의 위치를 뜻합니다.
이제 A(A > 12)
표현식은 논리형 배열에서 0이 아닌 값에 해당하는 행렬 요소를 추출합니다. 그 결과는 항상 열 벡터의 형식으로 표시됩니다.
A(A > 12) ans = 16 14 15 13
is
로 시작하는 여러 MATLAB 함수는 논리형 배열을 반환하며 논리형 인덱싱에 매우 유용합니다. 예를 들면 isnan
, 논리형 인덱싱, 스칼라 확장을 조합해서 한 줄의 코드에 사용하여 특정 배열 안의 모든 NaN 요소를 다른 값으로 교체할 수 있습니다.
B(isnan(B)) = 0
MATLAB에는 contains
, startsWith
, matches
처럼 논리형 배열을 반환하는 여러 string형 배열 함수가 있습니다. 이러한 함수를 사용하면 논리형 인덱싱으로 텍스트에 대해 연산을 수행할 수 있습니다. 예를 들면 “Skylab”이 포함된 우주 프로그램 명칭을 모두 추출할 수 있습니다.
>> names
names =
6×1 string array
"Mercury"
"Gemini"
"Apollo"
"Skylab"
"Skylab B"
"ISS"
>> names(contains(names,"Skylab"))
ans =
2×1 string array
"Skylab"
"Skylab B"
논리형 인덱싱은 find
함수와 밀접히 연관되어 있습니다. A(A > 5)
표현식은 A(find(A > 5))
와 같습니다. 간단한 사례에서는 논리형 인덱싱 표현식이 더 빠르긴 하지만, 계산 중 다른 무언가의 인덱스 값이 필요하면 find
를 사용할 수도 있습니다. 예를 들면 NaN 값을 0으로 잠시 교체하고 특정 계산을 수행한 후 NaN 값을 원래의 위치로 되돌려야 한다고 가정해 봅시다. 이 예에서 그 계산은 filter2
를 사용한 2차원 필터링입니다. 방법은 아래와 같습니다.
nan_locations = find(isnan(A)); A(nan_locations) = 0; A = filter2(ones(3,3), A); A(nan_locations) = NaN;
이 기술 칼럼에서 소개된 예제를 통해 간결하고 효율적인 알고리즘 표현 방법을 알아보실 수 있었기를 바랍니다. 이와 같은 기법과 관련 함수를 다양한 MATLAB 프로그래밍 작업에 포함하면 간결성과 가독성이 우수하고 벡터화된 코드를 생성할 역량이 더욱 늘어날 것입니다.
자세히 알아보기
2024년 기고
사용된 제품
관련 기능에 대한 칼럼 보기
무료로 사용해 보기
시작하기