본 글은 코세라 머신러닝(Machine Learning)을 수강하면서 일부 내용을 정리한 것입니다.
강의 사이트: https://www.coursera.org/learn/machine-learning
이번 글은 옥타브에서 데이터 계산(Computing on Data)에 대해 다뤄 보도록 하겠습니다.
일단, 실습을 위해 아래와 같이 3 * 2 A 행렬, 3 * 2 B 행렬, 2 * 2 C 행렬을 각각 선언하였습니다.
>> A = [1 2; 3 4; 5 6] A = 1 2 3 4 5 6 >> B = [11 12; 13 14; 15 16] B = 11 12 13 14 15 16 >> C = [1 1; 2 2] C = 1 1 2 2
*는 일반적인 행렬 곱셈(usual matrix multiplication)을 나타내는데요,
>> A * C ans = 5 5 11 11 17 17
반면, .*는 아래와 같이 행렬의 원소별 곱셈(element-wise multiplication)을 나타내는데요,
A와 C 행렬은 상응하는 행*열 개수가 달라서 오류(error)를, A와 B 행렬은 정상적으로 계산됩니다.
>> A .* C error: product: nonconformant arguments (op1 is 3x2, op2 is 2x2) >> A .* B ans = 11 24 39 56 75 96
같은 맥락으로 ./는 행렬의 원소별 나눗셈(element-wise division)을 처리해 줍니다.
>> v = [1; 2; 3]; >> 1 ./ v ans = 1.00000 0.50000 0.33333 >> 1 ./ A ans = 1.00000 0.50000 0.33333 0.25000 0.20000 0.16667
로그(logarithm, log)와 지수(exponential)는 각각 log(), exp()로 적용할 수 있습니다.
>> log(v) ans = 0.00000 0.69315 1.09861 >> exp(v) ans = 2.7183 7.3891 20.0855
abs()는 절대값을 계산합니다.
>> abs([-1; 2; -3]) ans = 1 2 3
자, 이번에는 아래와 같이 계산을 해보겠습니다.
length()는 주어진 값이 행렬인 경우 행과 열 개수 중 더 큰 값을 반환해 주는데요,
v는 3 * 1 벡터이기 때문에 length(v)는 3이 되겠죠?!
ones()는 주어진 행과 열 개수만큼 모두 1인 행렬을 만들기 때문에 [1; 1; 1] 선언과 같습니다. 재밌죠?!
참고로, length()와 ones()에 관한 예제는 이전 튜토리얼에서 정리하였습니다.
옥타브(Octave) 프로그래밍 튜토리얼 (1) - 기본 연산(Basic Operations) | http://blog.daum.net/geoscience/855
옥타브(Octave) 프로그래밍 튜토리얼 (2) - 데이터 이동(Moving Data Around) | http://blog.daum.net/geoscience/858
>>v +ones(length(v), 1) ans = 2 3 4 >>length(v) ans = 3 >>ones(3, 1) ans = 1 1 1 >>v +ones(3, 1) ans = 2 3 4
전치행렬(transposed matrix)은 아래와 같이 '로 선언할 수 있는데요,
예를 들면 A'은 A의 전치행렬이므로 A행렬의 열은 행으로, 행은 열로 바뀌게 됩니다.
당연히 (A')'로 선언하면 A의 전치행렬 A'을 다시 전치행렬 선언하기 때문에 결과는 A가 되겠죠?!
>> A A = 1 2 3 4 5 6 >> A' ans = 1 3 5 2 4 6 >> (A')' ans = 1 2 3 4 5 6
max() 함수는 주어진 행렬에서 최대값을 계산하는데요, [val, ind]와 같이 선언하면 인덱스도 함께 반환됩니다.
여기서는 1 * 4 a 벡터에서 최대값인 15가 2번째 열에 위치하고 있기 때문에 val과 ind가 각각 15, 2로 반환되었습니다.
>> a = [1 15 2 0.5] a = 1.00000 15.00000 2.00000 0.50000 >> val = max(a) val = 15 >> [val, ind] = max(a) val = 15 ind = 2
그렇다면 행렬에서 max() 함수는 어떻게 계산될까요?! 정답은, 각 열마다 최대값을 계산해줍니다.
행렬 A에서 첫 번째 열 1, 3, 5 중 최대값은 5이고 두 번째 열 2, 4, 6 중 최대값은 6이므로 결과는 [5 6]입니다.
>> A A = 1 2 3 4 5 6 >> max(A) ans = 5 6 >> A' ans = 1 3 5 2 4 6 >> max(A') ans = 2 4 6
a < 3은 a 행렬의 각 원소가 3보다 작으면 1, 그렇지 않으면 0을 반환합니다.
find(a < 3)은 위 조건을 확인하여 값이 있는 열의 인덱스를 결과값으로 반환해 줍니다.
>> a a = 1.00000 15.00000 2.00000 0.50000 >> a < 3 ans = 1 0 1 1 >> find(a < 3) ans = 1 3 4
magic()함수는 지정된 개수만큼 N * N 행렬을 만들어주는데요,
이 때 행렬은 행, 열, 대각의 합이 모두 일치하는 특성을 가지고 있습니다.
[r, c] = find(A >= 7)은 A 행렬에서 7보다 같거나 큰 원소들의 행과 열 인덱스를 반환해 줍니다.
아래 예제에서는 8(1 * 1), 9(3 * 2), 7(2 * 3)이기 때문에 r = [1; 3; 2], c = [1; 2; 3]으로 반환되었습니다.
>> A = magic(3) A = 8 1 6 3 5 7 4 9 2 >> [r, c] = find(A >= 7) r = 1 3 2 c = 1 2 3 >> A(2, 3) ans = 7
sum()은 원소들의 합, prod()는 원소들의 곱을 계산하는데요,
sum(a) = 1 + 15 + 2 + 0.5 = 18.5, prod(a) = 1 * 15 * 2 * 0.5 = 15입니다.
floor()는 소수점 이하 내림, ceil()는 소수점 이하 올림을 계산하는데,
rand()는 주어진 값에 따라 임의의 값으로 채워진 행렬을 선언합니다.
>> a a = 1.00000 15.00000 2.00000 0.50000 >> sum(a) ans = 18.500 >> prod(a) ans = 15 >> floor(a) ans = 1 15 2 0 >> ceil(a) ans = 1 15 2 1 >> rand(3) ans = 0.54524 0.55344 0.12546 0.97062 0.83944 0.93303 0.99950 0.33295 0.75760 >> max(rand(3), rand(3)) ans = 0.89003 0.27989 0.86297 0.98787 0.55133 0.45301 0.46248 0.86156 0.86826
앞서 정리한 것처럼 max()는 주어진 행렬의 최대값을 반환하는데요,
max(A, [], 1)에서 값이 1이면 열 최대값을, 2면 행 최대값을 반환합니다.
>> A A = 8 1 6 3 5 7 4 9 2 >> max(A, [], 1) ans = 8 9 7 >> max(A, [], 2) ans = 8 7 9 >> max(A) ans = 8 9 7 >> max(max(A)) ans = 9 >> A(:) ans = 8 3 4 1 5 9 6 7 2 >> max(A(:)) ans = 9
자, 다시 한 번 magic () 행렬을 통해 개념을 정리해 보겠습니다.
아래와 같이 9 * 9 magic 행렬에서 sum(A, 1) 선언은 열 최대값을 계산하는 것 같습니다.
sum(A, 2) 선언은 행 최대값을 계산하는데, 마방진(magic matrix)이므로 행과 열 최대값은 같습니다.
>> A = magic(9) A = 47 58 69 80 1 12 23 34 45 57 68 79 9 11 22 33 44 46 67 78 8 10 21 32 43 54 56 77 7 18 20 31 42 53 55 66 6 17 19 30 41 52 63 65 76 16 27 29 40 51 62 64 75 5 26 28 39 50 61 72 74 4 15 36 38 49 60 71 73 3 14 25 37 48 59 70 81 2 13 24 35 >> sum(A, 1) ans = 369 369 369 369 369 369 369 369 369 >> sum(A, 2) ans = 369 369 369 369 369 369 369 369 369
아래 예제에 나오는 flipud() 함수는 행렬의 위, 아래를 서로 치환해주는 기능을 제공합니다.
>> eye(9) ans = Diagonal Matrix 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 >> A A = 47 58 69 80 1 12 23 34 45 57 68 79 9 11 22 33 44 46 67 78 8 10 21 32 43 54 56 77 7 18 20 31 42 53 55 66 6 17 19 30 41 52 63 65 76 16 27 29 40 51 62 64 75 5 26 28 39 50 61 72 74 4 15 36 38 49 60 71 73 3 14 25 37 48 59 70 81 2 13 24 35 >> A .* eye(9) ans = 47 0 0 0 0 0 0 0 0 0 68 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 0 0 41 0 0 0 0 0 0 0 0 0 62 0 0 0 0 0 0 0 0 0 74 0 0 0 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 35 >> sum(sum(A .* eye(9))) ans = 369 >> flipud(eye(9)) ans = Permutation Matrix 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 >> sum(sum(A .* flipud(eye(9)))) ans = 369
끝으로 pinv()는 의사 역행렬(pseudoinverse)을 반환합니다.
>> A = magic(3) A = 8 1 6 3 5 7 4 9 2 >> pinv(A) ans = 0.147222 -0.144444 0.063889 -0.061111 0.022222 0.105556 -0.019444 0.188889 -0.102778 >> temp = pinv(A) temp = 0.147222 -0.144444 0.063889 -0.061111 0.022222 0.105556 -0.019444 0.188889 -0.102778 >> temp * A ans = 1.00000 0.00000 -0.00000 -0.00000 1.00000 0.00000 0.00000 0.00000 1.00000