1 < 0 # FALSE
[1] FALSE
1 > 0 # TRUE
[1] TRUE
Acknowledgement: 본 절의 구성에는 다음 교재를 발췌하였다.
Norman Matloff 지음, 권정민 역 (2012). 빅데이터 분석 도구 R 프로그래밍 (원제 The Art of R Programming). 에이콘.
복습: R의 연산은 논리 연산도 지원한다.
1 < 0 # FALSE
[1] FALSE
1 > 0 # TRUE
[1] TRUE
= 3
a > 2 # TRUE a
[1] TRUE
< 2 # FALSE a
[1] FALSE
<= 2 # FALSE a
[1] FALSE
== 3 # a는 3과 같다 # TRUE a
[1] TRUE
!= 3 # a는 3과 같지 않다 # FALSE a
[1] FALSE
if ( condition )
{
expression
....
}
if ( condition )
{
expression 1
....
} else # }과 else 사이에 엔터키가 있 # 으면 안됨
{
expression 2
....
}
만약 condition이 참이면 expression을 실행하라. (거짓이면 실행하지 않음)
만약 condition이 참이면 expression 1을 실행하고, 그렇지 않으면 expression 2를 실행하라.
condition에는 참/거짓을 판별할 수 있는 문장을 적는다.
expression에는 실행하고 싶은 명령어들을 자유롭게 입력한다. 아무거나 해도 된다. 몇 줄이 되어도 상관 없다. 새 변수를 정의해서 더하고 빼고 벡터를 새로 만들어서 그걸 또… 등등. if구문 안에 또 if를 집어넣는 것 또한 당연히 된다.
조건에 쓰이는 괄호와 실행문에 쓰이는 중괄호는 (일단은) 반드시 필요하다(고 하자).
( condition )
과 중괄호 {
사이에 절대로 세미콜론을 쓰면 안 된다.
= 3
a = 3
b
if ( a == b )
{= 1
c else
}
{= 0
c
}
c
[1] 1
= rep(0, 10) # 변수 초기화
a
for (i in 1:10)
{= 2*i - 1 # a[i] : 벡터 a의 i번째 성분값
a[i]
}
a
[1] 1 3 5 7 9 11 13 15 17 19
i에 1, 2, 3, … , 10이 차례대로 대입되면서 중괄호 안의 명령을 반복적으로 수행한다.
꼭 대입될 변수의 이름이 i일 필요는 없다. 아무 변수나, 이름짓는 규칙만 만족한다면 OK. 보통 수학에서의 관습을 따라 i, j, k, … 등을 흔히 쓴다.
1:10은 아까 벡터 소개 부분에서도 언급했듯 1부터 10까지 차례대로 나열된 벡터 c(1, 2, …, 10)를 뜻한다. 그 말은, 위의 for 구문을 입력할 때 (i in 2:19), (i in c(5, 1, 3)), … 같은 형태가 모두 가능하다는 뜻이다.
if구문의 {} 내부와 마찬가지로, for 구문의 {} 내부에도 아무거나 자유롭게 입력할 수 있다.
문법을 정리하면 다음과 같다.
for ( 변수 in 변수가 차례대로 취할 수들을 나열한 벡터 )
{
expression
}
= 1 # 변수 초기화. 지금은 수열의 0번째 항 저장
a
for (i in 1:10)
{= a + 2
a
}
a
[1] 21
= 10000
maxiter
for (i in 1:maxiter)
{= 2^i - 1
a if (a > 10^10)
{= i - 1
res.index = 2^(res.index) - 1
res.value break
}
}
res.index
[1] 33
res.value
[1] 8589934591
자주 쓰이는 알고리즘을 코드에서 반복적으로 입력하는 것보다는, 함수의 형태로 짜 놓았다가 호출하는 것이 더 효율적이다. 가령, (3 + 3 - 1)^2, (-6 + 10 - 1)^2, … 등의 값이 자꾸 필요한 상황이라면, 이것들을 일일이 입력하는 것보다는 F(x1, x2) = (x1 + x2 - 1)^2 라고 R에게 알려주고 F(3, 3), F(-6, 10)… 등을 이용하는 것이 편하다.
다음을 입력하고 실행해 보라.
= function(x1, x2)
F
{= x1 + x2 - 1 ;
temp return ( temp^2 ) ;
}
F(3, 1)
[1] 9
= F(3, 1)
result result
[1] 9
= 3 ; b = 1 ; result = F(a, b)
a result
[1] 9
함수 내부에서 계산된 temp에 대해 temp^2값이 최종적으로 반환(return)됨을 알 수 있다.
문법을 정리하면 다음과 같다.
함수 이름 = function(input variables) # input variable는 여러 개여도 되고, 아예 없어도 된다.
{
expression
return(value) # return시키고 싶은 값이 없으면 안 써도 됨
}
= function(x)
oddcount
{= 0 ;
count = length(x) ; # length(벡터) : 벡터의 길이를 리턴하는 함수
n for (i in 1:n)
{= x[i] %% 2 ; # a %% b : a를 b로 나눈 나머지(remainder)
temp if (temp == 1) { k = k + 1 ;}
}return(k) ;
}
oddcount(c(1,5,2)) ;…. 등을 자유롭게 입력하여 보라.
위 함수 안에는 count, n, temp 등 다양한 변수가 쓰였다. 그러면 함수 바깥에서 저 변수들이 여전히 자기 값을 갖고 있을까? 다음을 입력해 보라. 아마 변수를 못 찾겠다는 메시지가 뜰 것이다.
count
n temp
rm(list=ls()) # 작업공간(메모리) 상의 모든 개체 삭제
= function(a, b=2) {temp = 4 ; return( a + b + temp ) }
myftn # 함수 내에서 사용된 temp는 함수가 끝나고 사라진다.
temp ; :개체 'temp'이 없습니다
에러= 0
temp myftn(0)
1] 6
[# 함수 내에서 사용된 temp는 함수 바깥의 temp와는 아예 다른 # 세상(?)에서 살다가 사라진다.
temp 1] [
함수를 만들 때는 input variable들을 무엇으로 할 것인가, 무엇을 return할 것인가(하지 않을 것인가)를 생각하고 만드는 것이 좋다.
함수를 만들 때 등호로써 기본값을 미리 지정할 수 있다. MAXITER나 initial value같은 귀찮은 input을 다룰 때 유용하다.
= function(a, b=2) return( a + b )
myftn myftn(a=4)
[1] 6
myftn(a=4, b=3)
[1] 7
벡터의 평균을 계산하는 함수 mymean()을 만들되 다음 규칙을 따라서 만들라.
= function(x)
mymean
{= length(x) # n에 x의 길이 입력
n = 0 ; # sum.temp : 벡터의 성분별 누적합을 저장할 공간
sum.temp for (i in 1:n) sum.temp = sum.temp + x[i] ;
# 한 루프마다 실행할 명령이 하나뿐이므로 굳이 중괄호 {}를 입력하지 않음
return(sum.temp / n) ; # (벡터 성분 총합) / 벡터 길이를 리턴
}
= c(1, 2, 3, 4)
a = c(0, 1, 0, 1)
b mymean(a)
[1] 2.5
mymean(b)
[1] 0.5
\(a_{n+1} = f(a_n)\)으로 정의된 수열 \(\{a_n\}\)의 수렴 여부를 판정하는 함수 convtest()를 다음 규칙에 따라 만들라. - input : 함수 F, 수열의 초항(\(a_0\)) a, \(n\)에 대입할 최대 index M - for문 이용 - for문의 매 루프마다 loop index와 \(|a_n - a_{n-1}|\)을 화면에 출력할 것 - n = M까지 가기 전에 \(|a_n - a_{n-1}| < 10^{-6}\)이 달성되면 수렴된 것으로 판정하고 그 때의 \(a_n\)값을 수렴값으로서 반환, 만약 n = M이 되어도 \(|a_n - a_{n-1}| < 10^{-6}\)이 달성되지 않으면 수렴하지 않은 것으로 판정하고 NULL을 반환 - \(f(t) = \sqrt{t+1}\), a = 1, M = 100 으로 테스트 코드 작성
= function(F, a, M)
convtest
{= a # a.new의 초기화
a.new for (i in 1:M)
{= a.new
a.old = F(a.old)
a.new = abs(a.new - a.old) # err에 대입
err cat("Step ", i, ", current error : ", err, "\n", sep="")
if ( err < 10^(-6) )
{cat("Convergence occured!!\n")
return(a.new)
}
}cat("Convergence not occured\n")
return(NULL)
}
= function(t) return( sqrt(t + 1) ) ; a = 1 ; M = 100
f convtest(f, a, M)
Step 1, current error : 0.4142136
Step 2, current error : 0.1395604
Step 3, current error : 0.04427921
Step 4, current error : 0.01379457
Step 5, current error : 0.004273452
Step 6, current error : 0.001321592
Step 7, current error : 0.0004084921
Step 8, current error : 0.0001262403
Step 9, current error : 3.90113e-05
Step 10, current error : 1.205524e-05
Step 11, current error : 3.725282e-06
Step 12, current error : 1.151176e-06
Step 13, current error : 3.557331e-07
Convergence occured!!
[1] 1.618034