본문 바로가기
R

R 프로그래밍 apply() 함수 - 당신의 코드를 짧고 간결하게

by 슬통이 2023. 4. 5.
반응형

필자의 유튜브 슬기로운 통계생활 R과 통계에 관한 강의를 올려놓았다. 기초 내용이지만 초급자들이 어려워하는 함수와 개념들을 자세하게 올려놓았고, 계속 업데이트 예정이니 자주 들려주시기 바란다. 😎

 

이번 포스팅에서 다룰 R함수는 바로 apply() 함수이다. 사실 R에는 여러가지 apply()로 끝나는 이름의 함수들이 많다. 예를들어, lappy(), sapply(), tapply(), 그리고 mapply() 등등 사실 이런 함수들의 사용법을 알고 있어도 필자도 매번 잊어버리고 도움말을 찾아본다. 일일이 이러한 함수의 사용법을 알고 있는 것 자체도 비효율적이라고 생각하는 측면도 있고, 따지고 보면 오늘 설명할 apply 함수에서 출발한 아류들이기 때문이다. 따라서 apply 함수를 확실하게 이해하고, 자신의 코드 상황에 맞춰 다른 함수들을 응용할 수 있게 된다면, 자신의 코드가 훨씬 간결해지는 것을 느낄 수 있을 것이다.

함수의 이름이 apply인 이유는 기존에 정의된 함수를 어떤 대상에 편하게 적용할 수 있게 만들어 주는 특성에서 유래되었다고 생각한다. 여기서 적용하는 대상의 종류에 따라서 사용되는 함수가 달라지게 된다. 예를 들면, array가 적용대상인 경우는 apply함수, list인 경우에는 lapply함수, table인 경우에는 tapply함수가 된다.

apply 함수의 문법

apply함수의 문법은 다음과 같다.

apply(array, margin, fun)

위의 구문을 직관적으로 이해하기 쉽게 바꿔보면 다음과 같다.

apply(object, direction, function to apply)

즉, apply 함수의 첫번째 자리에는 함수를 적용하고 싶은 대상을 써주면 되고, 두번째 자리에는 함수가 적용되는 방향, 마지막 자리에는 적용하고 싶은 함수를 써주면 된다. 좀 더 구체적인 설명을 위하여 R코드를 살펴보자.

적용대상인 array에 대하여

먼저 함수의 적용대상이 되는 array를 정의하자. array란 R의 데이터 오브젝트(data object)들 중 하나로서 데이터를 2차원 이상의 공간에 저장할 수 있다. 특히, 2차원 array를 특별히 행렬(matrix)라고 부른다. 따라서 1에서 12까지의 숫자를 원소로 갖는 3행 4열의 행렬을 다음과 같이 두 가지 방법으로 정의 할 수 있다.

a <- array(1:12, dim = c(3,4))
b <- matrix(1:12, nrow = 3, ncol = 4)
a == b
##      [,1] [,2] [,3] [,4]
## [1,] TRUE TRUE TRUE TRUE
## [2,] TRUE TRUE TRUE TRUE
## [3,] TRUE TRUE TRUE TRUE
a
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12

적용방향 - 1:가로방향, 2: 세로방향

이제, 우리가 주어진 행렬의 열(column)을 기준으로 각 열의 최대값을 구하고 싶다고 가정하자. 주어진 예제를 사용하면 3, 6, 9, 12의 숫자를 얻고 싶은 것이다. 이 경우 다음과 같은 코드를 사용하면 된다.

apply(a, 2, max)
## [1]  3  6  9 12

apply() 함수 구문에서 두번째 자리에 들어가는 내용은 적용방향이었다. 어느정도 예상하였을 테지만, 함수를 행방향(가로방향)으로 적용하고 싶을 경우 1, 열뱡향(세로방향)으로 적용하고 싶을 때에는 2를 사용한다. 즉 위의 코드의 두번째 항목을 2로 변경할 경우 다음과 같이 각 행의 최대값을 얻을 수 있다.

apply(a, 1, max)
## [1] 10 11 12

우리가 행렬을 부를때 ‘행’, ‘열’로 부르듯, 적용방향도 ’행: 1’, ’열: 2’로 생각하면 외우는데에 도움이 될 것이다. 이것을 그림으로 나타내면 다음과 같다.

apply 적용방향

적용할 함수

apply() 함수 구문에서 세번째 자리에 들어가는 항목은 적용할 함수였다. 이것은 우리가 적용할 함수를 마음대로 선택할 수 있다는 건인데, 사실 apply() 함수의 진짜 강점은 우리가 정의한 함수를 적용할 수 있다는 것이다. 예를 들어 각 행별 최대값을 찾아서 제곱을 하고 3을 더한 값을 얻기 위해서 우리는 다음과 같이 함수를 정의하고 apply()를 사용하여 계산할 수 있다.

f <- function(vec){
    max(vec)^2 + 3
}
apply(a, 1, f)
## [1] 103 124 147

3차원 Array에 Apply() 적용하기

이제까지 우리는 apply() 함수를 2차원 array인 행렬(Matrix)에 적용시켜 보았다. 사실 array는 2차원 이상의 공간에 정의된 오브젝트인데, 그 중에서 3차원 array가 가장 많이 쓰인다. 아래의 그림과 같이 3차원 array의 경우 여러개의 행렬을 쭉 겹쳐서 쌓아 놓았다고 생각하면 된다. 3차원 array의 각 차원은 행렬에서 사용한 행과 열에 추가하여 레이어(layer)라는 차원을 사용한다.

예를들어, 1부터 24까지의 숫자를 원소로 갖는 3행 4열의 행렬 두 개로 이루어진 array는 다음과 같이 정의할 수 있다.

array3D <- array(1:24, dim = c(3,4,2))
array3D
## , , 1
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
## 
## , , 2
## 
##      [,1] [,2] [,3] [,4]
## [1,]   13   16   19   22
## [2,]   14   17   20   23
## [3,]   15   18   21   24

위에서 정의한 array3D를 그림으로 표현하면 다음과 같이 나타낼 수 있다.

array3D 시각화

자, 그렇다면 우리가 배운 apply()함수가 3차원 array에 적용이 될 때엔 어떻게 작동이 될까? 앞에서 배운 적용방향에 따른 함수의 작동 방식을 떠올리면서 다음 R코드의 결과를 해석해보자.

apply(array3D, 1, max)
## [1] 22 23 24

분명 행(row)방향으로 max()함수가 적용되었는데, 결과를 살펴보면 2번째 레이어(layer)의 행렬에만 적용이 된 것처럼 보인다. 하지만 잘 살펴보면 1번째 레이어의 행렬의 값은 두번째 행렬보다 다 작아서 이러한 결과값이 나온 것이며, 실제로는 아래의 그림과 같이 2차원에서 행방향으로 적용되었던 방식이 3차원에서는 행 평면 위에 놓여있는 원소들 기준으로 적용이 되어 계산이 되어진다.

3D array 방향 1 적용

apply(array3D, 2, max)
## [1] 15 18 21 24

이번에는 max()함수를 array3D에 행(column)방향으로 적용하여 결과를 살펴보자. 3차원 array에 적용되는 apply()함수의 세로방향 적용방식 역시 아래의 그림과 같이 세로방향 평면에 위치한 원소들을 기준으로 max()함수가 적용되었다는 것을 알 수 있다.

3D array 방향 2 적용

마지막 확인 작업을 위해서, 램덤(random)한 원소들을 갖는 array에 적용된apply()함수의 결과값을 보자. 우리가 이해한 방식대로 잘 작동한다는 것을 확인할 수 있을 것이다.

array3D <- array(sample(24,24), dim = c(3,4,2))
array3D
## , , 1
## 
##      [,1] [,2] [,3] [,4]
## [1,]   18   21    6   22
## [2,]   23   12   10   15
## [3,]    1    7    9    2
## 
## , , 2
## 
##      [,1] [,2] [,3] [,4]
## [1,]   11   16   14    3
## [2,]   20    5   24    4
## [3,]    8   19   13   17
apply(array3D, 1, max)
## [1] 22 24 19

마지막으로 3차원 array를 가지고 있으므로, 함수를 적용할 수 있는 방향이 하나 더 존재한다. 바로 레이별로 함수를 적용할 수 있는 것이다. 각 레이어별 행렬의 최대값은 max()함수를 적용방향을 3으로 설정하여 주면 구할 수 있다.

apply(array3D, 3, max)
## [1] 23 24

이 포스팅에서 다룬 apply()함수의 속성을 잘 이해하고 있다면, 비슷한 성격을 가진 다른 apply family 함수들을 다룰때에 확실히 이해가 빨라질 것이라 생각한다.

References

  1. Matloff, Norman. “The art of R programming.” (2009).
  2. R apply 함수 설명서

 

 

반응형

댓글