R 에서 특정 코드를 반복해서 실행하는 방법은 for, while, repeat, apply
과 같은 반복문을 이용하면 간단히 구현할 수 있다.
그런데 만약 반복문의 주안점이 반복된 모든 결과들을 저장해야 한다는 것에
있다면 통상적인 반복문에선 조금 오묘한 방법을 통해 이를 구현한다.
for문을 이용한 주사위 100회 던지기
for 문을 이용한 간단한 예시 코드를 보면
<- c()
res for(i in seq(100)) res[i] <- sample(1:6, 1)
res
## [1] 3 1 5 4 1 6 6 4 5 6 6 1 1 3 2 4 4 2 3 4 4 4 5 1 5 5 6 1 1 3 6 1 3 5 2
## [36] 5 1 2 5 3 4 5 2 4 2 5 6 2 3 4 3 1 6 2 1 4 1 1 3 6 4 3 1 5 6 3 4 3 5 3
## [71] 2 6 3 4 6 3 2 3 3 1 3 6 4 3 6 1 5 4 2 1 6 6 3 3 2 4 3 5 3 1
이 코드는 주사위를 100번 던져 나온 숫자들을 res
라는
객체에 벡터형태로 저장하는 코드로 볼 수 있다.
apply()
를
이용한 주사위 100회 던지기
반복문 방식을 바꿔보겠다.
위 예시를 apply()
를 이용해본 코드이다.
<- apply(matrix(1:6, 6, 100), 2, function(x) sample(x, 1))
res res
## [1] 4 6 5 6 3 5 4 3 5 1 6 6 2 3 5 6 4 6 2 3 5 4 4 5 1 1 2 5 3 6 6 5 5 4 5
## [36] 5 3 6 3 4 6 5 2 2 6 1 3 6 6 3 5 3 6 4 1 1 4 4 5 1 5 3 4 4 4 4 2 4 2 1
## [71] 3 1 5 4 4 4 6 1 2 2 4 5 2 1 5 5 2 3 2 1 2 4 5 3 5 1 6 1 1 6
지금까지 예시로 든 두 가지 방식의 코드는 한가지 공통점이 있다.
반복문의 내용이 무엇이 되었던 100번의 반복으로 인해 어떤
무엇인가가 100번 반환될 것이고, 이에 대한 저장공간을 사전에 생각하여
준비해야 한다는 것이다.
- 첫 번째 for문 반복문 예제에선 100개의 값이 저장될
res
라는 빈 벡터를 사전에 준비한res <- c()
코드가 눈에 띈다.
- 두 번째
apply()
예제에선 일괄함수적용을 위해 1, 2, 3, 4, 5, 6 의 벡터 100개가 열방향으로 bind 된 matrix 를 사전에 준비했고, 이에 대해 무작위로 추출하기 위한sample()
함수를 일괄 적용했다.
이처럼 100회 반복의 모든 결과를 어딘가의 담아 두기 위한 사전 설계의
노력이 따로 필요하다.
분명 정석적으로 이러한 준비는 반드시 필요하며 틀린 방법이라고 말할 수
없다.
문제는 위의 예제처럼 간단한 코드가 아닌 복잡한 상황일 때 사전준비
과정들은 곱절 높아질 수 있다는 것이다.
보통 복잡도는 지수적으로 늘어나기 때문에 이 오묘한 방법이 실전에서
코딩의 비효율로 일어날 수 있다고 생각한다.
replicate()
함수 소개
만약 복잡한 상황일 때,
위의 예제들의 로직을 그대로 가지고 있되 사전준비의 부담을 덜 수 있는
함축된 함수가 있다고 생각하는데
바로 replicate()
함수이다.
<- replicate(100, sample(1:6, 1))
res res
## [1] 2 5 1 4 2 5 2 2 2 5 1 1 4 5 5 6 3 4 5 1 6 1 3 5 6 2 5 1 5 4 1 1 1 5 6
## [36] 3 1 2 3 6 3 5 2 6 5 6 4 6 5 5 4 1 2 6 4 5 1 5 5 1 1 2 2 5 6 2 2 3 1 3
## [71] 4 4 4 6 2 1 2 2 2 1 4 6 5 2 4 5 4 6 4 2 4 1 2 2 2 6 1 4 4 1
replicate()
함수는 반복문의 내용(expr)을 두 번째 인자에
부여하고, 첫 번째 인자에 반복회수를 넣어줌으로써 반복 실행된 코드의
결과를 벡터형태로 반환시켜주는 편리한 함수이다.
사전준비에 대한 로직을 replicate()
함수가 대신해준다.
따라서 코드 길이도 확실히 줄일 수 있게 된다.