1.1 R이란?

R은 주로 자료 분석(data analysis)용으로 만들어진 언어이자 계산 환경이다.

R을 컴퓨터 언어로 분류하자면 interpreter 방식의 ’함수형 언어(functional language)’이다.

겉보기에는 C언어와 유사하고, 주로 C언어로 개발되었지만, 내부적으로는 C언어와 매우 다르다.

Function(함수)이란 “무엇인가를 input으로 받고, 무엇인가를 output으로 돌려주는 것”을 말한다. 이때 input을 argument라고도 하고, output을 return value라고도 한다. (사실 return이 좁은 의미의 value가 아니고 함수 같은 object도 return 할 수 있다.)

’함수형 언어’란 결과가 오로지 (또는 최대한) input에 의해서만 결정되지, 그 함수가 불리어진(called) 환경(environment)에 가급적 의존하지 않는 것을 의미한다.

R에서도 event driven programming이나 C++와 같은 object-oriented programming(OOP)가 가능하지만, 처음 만든 취지를 생각하면 그다지 적당하지 않다.

R 언어는 기본적으로 compiler 방식이 아니고 interpreter 방식이어서 느리지만, 속도를 빠르게 하기 위한 장치(예를 들어, 함수별로 미리 compile)가 내부적으로 많이 작동하고 있다. 하지만, 사용자가 보기에는 기본적으로 interpreter 방식이어서 사용자와 interactive하게 작업할 수 있다. 자료 분석(data analysis) 과정은 그때그때의 결과에 따라 다음 처리가 정해지므로 자료 분석 작업에는 (모든 것을 미리 정해 놓고 batch형태로 일괄처리하는 것보다는) 이러한 방식이 적합하다. 느려 보이지만 이것이 rate-limiting step은 아니며, R script로 명령어를 저장해 놓거나 사용자 정의 함수(user defined function)를 만든다면, 얼마든지 자동화도 할 수 있다.

R 실행환경은 내부적으로 여러 ’environment(환경)’으로 나누어져 있고, environment 속에는 data나 function들이 들어있다. 따라서, environment는 object들을 담는 주머니라고 볼 수 있다. 일반적으로 모든 프로그래밍에서 전역변수(global variable)의 사용은 자제하도록 되어 있는데, R 환경에서 굳이 전역변수를 사용하고자 한다면, 특정 environment 내에 저장해두는 방법을 사용할 수 있다.

프로그래밍에서 object(개체, 객체, 것, thing)란 거의 모든 것이다. 함수(function), 자료(data), 모형식(model formula) 등이 모두 object이다.

R은 OOP의 특성(넓은 의미의 polymorphism, encapsulation, inheritance)도 있지만, 일반적인 OOP와는 다른 독특한 방식으로 동작한다. 일반적인 OOP에서는 하나의 object 내에 method라 불리는 함수들과, attribute 또는 property라고 불리는 속성(특성값)이 함께 들어 있다. 그러나, R에서는 이를 분리하되 class들로 object type을 구분하지만 그 내부에는 method를 가지고 있지 않다. Method들은 따로 모아서 관리하고 있어서, 어떤 함수들이 어떤 class와 동작하는지를 matching시켜 준다. 함수 이름 마지막에 .className으로 구분 할 수 있는데, 이런 방식을 S3 방식이라고 한다. 반면에 좀 더 전형적인 OOP를 쓰고 싶으면 (즉, 하나의 object안에 method와 property가 함께 있는) S4 object들을 쓰면 된다. 개인적으로 S3 object를 쓰는 것이 R을 더 잘 활용하는 것이라 생각한다. 즉 S4 object들은 최초 개발 동기와는 다른 것이라 생각한다.

R에서 다음과 같이 methods 함수로 print 함수가 어떤 class들과 연결되어 있는지 볼 수 있다.

methods(print)

그런데, R은 사용자가 S3 system이나 OOP에 대해서 잘 알고 있지 않아도 쓸 수 있다는 것도 하나의 장점이다.

함수를 부른 쪽을 caller, 불리어진 함수를 callee라고 할 수 있다. 다른 언어에서는 pointer라는 개념이 있어서, 함수에게 어떤 값(object 자체)을 넘겨주는 것이 아니라, 그 object가 저장된 메모리의 주소(address) 값을 넘겨줄 수 있다. 이런 방식을 call-by-reference라고 부른다. 반면 object 자체를 한 벌 복제(copy, replication)해서 넘겨줄 수 있는데, 이런 것을 call-by-value라고 한다. 작은 object인 경우에는 call-by-value가 문제가 없으나, 큰 경우에는 한 번 복제가 일어나면 메모리의 손실이 크고, 복사에 시간이 소요되는 등 비효율이 발생한다. 이러한 문제를 해결하기 위해 C언어와 같은 많은 언어들은 call-by-reference를 빈번히 사용한다. 하지만, R은 기본적으로 (거의 대부분, 사용자가 일부로 명확히 지시하지 않는 한) call-by-value이다. 따라서, 매우 큰 object (수 GB 이상)를 함수의 input으로 넣을 때는 주의해야 하며, 본인의 system이 다운되거나, 속도가 매우 느려진다면, 위에서 말한 environment에 저장해두고 access하는 방식을 고려해 봐야 한다.

R의 기본철학은 call-by-value이나 call-by-reference를 사용자가 신경 쓰지 않게 하고, recursion (recursive function call)이 자연스럽다면, 사용자가 마음대로 쓰게 해야지, 이것을 굳이 iterative loop으로 바꾸게 해서는 안된다는 것이다. 그러다 보니, 대다수의 R 사용자는 다른 컴퓨터 언어를 모르는 경우가 많고, 내부적으로 어떻게 동작하는지 기본적인 원리를 모르는 경우도 많다.

R Programming시 자주 사용하는 keyword와 함수 목록은 Appendix A에 정리하였다.

기본적인 것은 CRAN Manuals section의 R Language Definition을 참고하고, 더 자세한 것은 Hadley Wickham의 ’Advanced R’이라는 책(또는 Website)을 참고하면 좋다.