outer() 함수에 대하여

Vectorized 함수의 꽃

이번 포스팅에서 다룰 R함수는 바로 outer() 함수이다. 이 함수의 이름은 선형대수학에서 정의되는 두 벡터의 Outer product에서 유래되었다고 생각하면 된다. 따라서 함수를 설명하기에 앞서 먼저 유래가 된 두 벡터의 outer product가 어떤 것인지에 대하여 알아보자.ㅣ

두 벡터 \(\underline{a}\)\(\underline{b}\)를 다음과 같이 정의하자. \[ \underline{a}=\left(\begin{array}{c} a_{1}\\ a_{2}\\ a_{3}\\ a_{4} \end{array}\right),\,\underline{b}=\left(\begin{array}{c} b_{1}\\ b_{2}\\ b_{3}\\ b_{4} \end{array}\right) \] 주어진 두 벡터 \(\underline{a}\)\(\underline{b}\)의 외적(outer product)는 \(\underline{a}\otimes\underline{b}\)으로 표기하고, 다음과 같이 계산된다. \[ \begin{align*} \underline{a}\otimes\underline{b} & =\underline{a}\underline{b}^{T}\\ & =\left(\begin{array}{c} a_{1}\\ a_{2}\\ a_{3}\\ a_{4} \end{array}\right)\left(\begin{array}{cccc} b_{1} & b_{2} & b_{3} & b_{4}\end{array}\right)\\ & =\left(\begin{array}{cccc} a_{1}b_{1} & a_{1}b_{2} & a_{1}b_{3} & a_{1}b_{4}\\ a_{2}b_{1} & a_{2}b_{2} & a_{2}b_{3} & a_{2}b_{4}\\ a_{3}b_{1} & a_{3}b_{2} & a_{3}b_{3} & a_{3}b_{4}\\ a_{4}b_{1} & a_{4}b_{2} & a_{4}b_{3} & a_{4}b_{4} \end{array}\right) \end{align*} \] 따라서 R에서 벡터의 곱셈을 연산자 \(\mbox{%*%}\)를 사용하면 두 벡터의 외적을 아래와 같이 계산할 수 있고, 계산 결과도 outer 함수와 똑같이 나옴을 확인 할 수 있다.

a <- 1:4
b <- 5:8
a %*% t(b) == outer(a,b)
##      [,1] [,2] [,3] [,4]
## [1,] TRUE TRUE TRUE TRUE
## [2,] TRUE TRUE TRUE TRUE
## [3,] TRUE TRUE TRUE TRUE
## [4,] TRUE TRUE TRUE TRUE
# 다음과 같이도 쓸 수 있다.(outer 의 첫글자 o)
a %o% b
##      [,1] [,2] [,3] [,4]
## [1,]    5    6    7    8
## [2,]   10   12   14   16
## [3,]   15   18   21   24
## [4,]   20   24   28   32

그렇다면 outer() 함수는 왜 필요할까? 그 이유는 바로 outer함수가 벡터 외적의 연산을 일반화 시킨 함수이기 때문이다. 두 벡터의 외적의 수학적인 정의는 각 원소들의 ’곱’을 계산한 값을 모아 행렬로 만들어 준다. 만약 이 곱하기 연산을 다른 일반적인 함수로 바꿔주면 훨씬 편하지 않을까? 하는데에서 고안이 된 함수이다. ?outer 명령어를 사용하여 문법을 살펴보자.

outer(X, Y, FUN = "*", ...)

보이는 바와 같이 outer 함수는 기본적으로 벡터의 외적 연산이 설정되어 있지만, 사용자가 마음대로 바꿔서 정의 할 수 있는 것이다. 곱셈을 나타내는 \(*\)기호를 +로 바꾸면 다음의 R 명령어는 아래의 결과를 계산해 준다.

outer(a, b, FUN = "+")

\[ outer(\underline{a},\underline{b},+)=\left(\begin{array}{cccc} a_{1}+b_{1} & a_{1}+b_{2} & a_{1}+b_{3} & a_{1}+b_{4}\\ a_{2}+b_{1} & a_{2}+b_{2} & a_{2}+b_{3} & a_{2}+b_{4}\\ a_{3}+b_{1} & a_{3}+b_{2} & a_{3}+b_{3} & a_{3}+b_{4}\\ a_{4}+b_{1} & a_{4}+b_{2} & a_{4}+b_{3} & a_{4}+b_{4} \end{array}\right) \] 따라서 사용자가 함수를 어떻게 설정하느냐에 따라서 outer 함수는 각 벡터의 순서쌍에 대응하는 함수값을 계산해준다고 생각할 수 있다.

outer(a, b, FUN = "f")

\[ outer(\left(\begin{array}{c} a_{1}\\ a_{2}\\ a_{3}\\ a_{4} \end{array}\right),\left(\begin{array}{c} b_{1}\\ b_{2}\\ b_{3}\\ b_{4} \end{array}\right),\mathtt{f})=\left(\begin{array}{cccc} \mathtt{f}\left(a_{1},b_{1}\right) & \mathtt{f}\left(a_{1},b_{2}\right) & \mathtt{f}\left(a_{1},b_{3}\right) & \mathtt{f}\left(a_{1},b_{4}\right)\\ \mathtt{f}\left(a_{2},b_{1}\right) & \mathtt{f}\left(a_{2},b_{2}\right) & \mathtt{f}\left(a_{2},b_{3}\right) & \mathtt{f}\left(a_{2},b_{4}\right)\\ \mathtt{f}\left(a_{3},b_{1}\right) & \mathtt{f}\left(a_{3},b_{2}\right) & \mathtt{f}\left(a_{3},b_{3}\right) & \mathtt{f}\left(a_{3},b_{4}\right)\\ \mathtt{f}\left(a_{4},b_{1}\right) & \mathtt{f}\left(a_{4},b_{2}\right) & \mathtt{f}\left(a_{4},b_{3}\right) & \mathtt{f}\left(a_{4},b_{4}\right) \end{array}\right)\] 이러한 outer함수가 가장 유용하게 사용되는 곳이 등고선(contour) 그래프를 그릴 때인데, 3차원 함수를 위에서 내려다 본 것을 그린 것이라고 생각하면 된다. 다음은 함수 \[ f\left(x,y\right)=\left(x-1\right)^{2}+\left(y-1\right)^{2} \] 를 x축 0에서부터 2까지, y축 0에서부터 2까지의 범위의 등고선 그래프를 나타내는 R코드 이다.

# Evaluate z on a grid given by x and y
x <- seq(0, 2, by = 0.01)
y <- seq(0, 2, by = 0.01)
z <- outer(x, y, FUN=function(x,y) (x-1)^2+(y-1)^2 )
# Contour plots
image(x, x, z)
par(new=TRUE)
contour(x,y,z, add = TRUE)

References

[1] outer함수 설명서 https://stat.ethz.ch/R-manual/R-patched/library/base/html/outer.html

[2] Nicholas Christian Statistical Computing in R Lecture note (lecture5 outer 함수 설명부분에서 영감을 얻음) http://www.pitt.edu/~njc23/

댓글(0)

Designed by JB FACTORY