IT

옥타브(Octave) 프로그래밍 튜토리얼 (3) - 데이터 계산(Computing on Data)

유병혁 2015. 12. 16. 23:27

본 글은 코세라 머신러닝(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