Chapter 2 R 데이터 기초

R은 통계 데이터 분석 툴이기도 하지만 그 자체로 프로그래밍 언어이다. 한국어, 영어와 같은 모든 언어가 그러하듯이 R에도 자기만의 어휘와 표현법, 표현 형태들이 있다. 외국어에 익숙해지기 위해 기본적인 문법 요소와 다양한 문형들을 익혀야 하는 것처럼 R도 R의 기본 표현법과 표현 형태를 익혀야만 사용할 수 있다. 고급 문법과 문형에 익숙할수록 더 유창한 언어 실력을 보일 수 있듯이 R도 고급 표현을 익히면 더 다양한 분석을 수행할 수 있다.

이 장에서는 R의 가장 기초적인 데이터 요소를 배운다. 3에서 6 장까지는 이 장에서 배운 내용을 기초로 R의 기초 데이터를 확장해 나간다. 이 장의 내용은 프로그래밍 언어에 익숙한 독자들에게는 이미 익숙한 내용일 것이다. 그런 독자들은 다음 장부터 시작하여도 무방하다.

2.1 단순한 데이터 형식 (data types)

R의 기본적 데이터 형식: 숫자, 문자, 논리값

R은 데이터를 다룬다. R에서 다루는 기본적인 데이터 형식은 숫자, 문자, 논리값이다. 어떤 학생의 키가 172.2이면 이 데이터의 형식은 숫자이다. 그 학생의 이름이 ’홍길동’이면 이 데이터는 문자 데이터이다. 그리고 이 학생이 남자인지 여부를 TRUE 또는 FALSE로 표현하였다면 이 데이터의 형식은 논리값이다. R의 모든 복잡한 데이터 형식은 이러한 숫자, 문자, 논리값을 기반으로 구성된다.

아래는 R의 콘솔에서 숫자, 문자, 논리값을 차례대로 입력해 본 결과이다. ‘>’ 다음 부분을 R 콘솔에 입력한 후 Enter 키를 누른다. 그러면 입력한 내용이 R에 전달되어 출력 결과가 그 다음 줄에 나타난다(’>’가 없는 줄).

10
[1] 10
TRUE
[1] TRUE
"홍길동"
[1] "홍길동"

10 vs ‘10’

여기서 주의할 점은 숫자와 논리값과는 달리 문자 데이터는 큰 따옴표나 작은 따옴표로 시작과 끝을 표현해 주어야 한다는 것이다. 따라서 사칙연산이 가능한 숫자 10과 문자 "10"은 서로 다르다. 마찬가지로 논리값 TRUE와 문자열 "TRUE"도 다른 의미를 가진다.

2.2 단순 연산

사칙 연산

R은 더하기, 빼기, 곱하기, 나누기 등의 사칙연산에 대한 기본적 기능을 제공한다. 아래의 ‘>’ 이후의 부분을 입력 후 Enter 키를 누르면 그 아래에 출력 결과가 나온다.

2 + 2
[1] 4
2 - 2
[1] 0
2 * 2
[1] 4
2 / 2
[1] 1

몫과 나머지

R에서 나눗셈은 부동 소수점 형식의 실수(real numbers)로 계산된다. 만약 정수의 나눗셈에서 몫과 너머지를 구하려면 %/%%% 연산자를 사용한다.

11 / 3
[1] 3.666667
11 %/% 3  # 몫
[1] 3
11 %% 3   # 나머지
[1] 2

거듭 제곱 연산

또한 ‘^’ 연산자를 이용해 거듭제곱도 가능하다. 아래의 예는 2의 1제곱부터 4제곱까지의 결과이다. 여기서 4개의 거듭제곱 연산 명령문 (Enter 키를 쳐서 R로 보내는 내용)을 한 줄로 보내기 위해 ’;’로 각각의 명령문을 나누어 한번의 Enter 키로 명령을 실행하였다. 각 명령문의 결과는 다른 줄로 출력되었음을 볼 수 있다.

2^1; 2^2; 2^3; 2^4
[1] 2
[1] 4
[1] 8
[1] 16

파이썬처럼 ** 연산자를 거듭 제곱 연산자로 사용할 수도 있다.

2**4
[1] 16

비교 연산 ‘==’ vs. ‘=’

R은 사칙연산뿐 아니라 부등호와 등호를 이용한 비교연산도 가능하다. 아래는 비교 연산을 수행한 경우이다. ‘>=’와’<=’ 연산자는 같거나 크다 또는 같거나 작다를 의미한다. ‘==’ 연산자는 같다를 의미하고 ‘!=’ 연산자는 같지 않다를 의미한다. 여기서 주의할 점은 등호가 ‘=’가 아니라’==‘라는 점이다.’=’ 연산자는 뒤에서 살펴볼 변수에 값을 할당하는데 이용된다.

2 > 2; 2 >= 2; 2 < 2 ; 2 <= 2
[1] FALSE
[1] TRUE
[1] FALSE
[1] TRUE
2 == 2; 2 != 2
[1] TRUE
[1] FALSE

논리값 연산

&, |, !, xor(x, y) 연산자를 이용하여 논리적 AND, OR, NOT, XOR 연산을 할 수 있다.

TRUE & FALSE
[1] FALSE
TRUE | FALSE
[1] TRUE
!TRUE
[1] FALSE
xor(TRUE, TRUE)
[1] FALSE

문자열 결합 연산 paste()

문자열에 대한 연산으로는 paste() 함수를 이용하여 문자를 연결하는 연산이 있다. paste() 함수는 문자열을 공백 하나를 사이에 두고 하나의 문자열로 합쳐준다. 숫자처럼 문자가 아닌 것은 문자로 변환한 후 합쳐준다. sep인자를 이용하면 두 문자열의 사이에 다양한 문자를 넣을 수 있다.

paste(2014, 3)
[1] "2014 3"
paste("March", 11, 2014)
[1] "March 11 2014"
paste(2014, 3, 11, sep="-")
[1] "2014-3-11"
paste(2014, 3, 11, sep="/")
[1] "2014/3/11"
paste(2014, 3, 11, sep="")
[1] "2014311"

문자열 분리 연산 strsplit()

paste와 반대로 하나의 문자열을 여러 문자열로 분리해 내는 strsplit 함수도 있다. split인자에 문자열을 분리하는 기준이 되는 문자 또는 문자열을 지정해 준다.

strsplit("2016-3-11 11:16:22", split=" ")
[[1]]
[1] "2016-3-11" "11:16:22" 
strsplit("2016-3-11 11:16:22", split="-")
[[1]]
[1] "2016"        "3"           "11 11:16:22"
strsplit("2016-3-11 11:16:22", split=":")
[[1]]
[1] "2016-3-11 11" "16"           "22"          
strsplit("2016-3-11 11:16:22", split=c("16"))
[[1]]
[1] "20"        "-3-11 11:" ":22"      

strsplit의 split 인자는 사실 정규식 표현도 가능하다. (정규식에 대해서는 regular expression에 대한 다른 자료를 참조하길 바란다.) 다음은 정규식을 이용하여 ‘-’나,’ ‘(공백)나,’:’ 문자가 있는 곳 모두를 분리한 예이다.

strsplit("2016-3-11 11:16:22", split="[- :]")
[[1]]
[1] "2016" "3"    "11"   "11"   "16"   "22"  

2.3 변수와 할당

변수는 메모리 공간에 붙이는 레이블

R에서 연산을 수행하다 보면 연산의 중간 결과를 저장해둘 필요가 있다. 이 때 이용할 수 있는 것이 변수이다. 변수는 데이터를 저장해 두는 공간이라고 생각하면 쉽다. 변수는 사실 데이터를 저장해 두는 공간에 라벨을 붙여두는 것이다. 다시 그 데이터가 필요할 때 라벨을 이용하여 데이터가 저장된 공간에 가서 그 데이터 값을 가져와 이용하면 된다.

변수에 값 할당하기

할당(assignments)이란 어떤 변수에 데이터를 저장하는 것을 말한다. 예를 들어 x에 5라는 숫자 데이터를 할당하였다면 5라는 숫자가 x라는 라벨이 붙은 저장 공간에 들어간 것과 마찬가지이다. 우리는 x라는 라벨을 이용하여 필요할 때 x라는 라벨이 붙은 저장공간에 저장된 데이터 값을 가져올 것이다.

할당 연산자

변수에 데이터를 할당하는 것은 ‘<-’ 또는 ‘=’ 연산자를 이용하여 이루어진다. 이 책에는 할당 연산자로 ‘<-’을 이용할 것이다. 할당 연산자의 모양에서도 알 수 있듯이’<-’ 연산자 오른쪽의 데이터를 왼쪽의 변수에 집어넣는다. x라는 변수에 저장된 데이터 값을 알고 싶으면 x를 입력한 후 Enter 키를 누르면 x의 값이 출력된다.

x <- 5
x
[1] 5

연산에 변수 사용하기

x를 이용하여 다양한 명령을 수행할 수 있다. 뿐만 아니라 괄호 등을 이용하여 복잡한 연산을 수행할 수 있다.

x + 2
[1] 7
x * 2
[1] 10
x^2
[1] 25
(x+3)^2 + 5
[1] 69
x
[1] 5

위의 마지막 결과에서 볼 수 있듯이 변수의 값은 ‘<-’ 연산자에 의해 다시 다른 값으로 할당되지 않으면 연산에서 사용되어도 원래의 값이 변하지 않는다.

변수에 값 재할당하기

변수는 데이터의 저장공간일 뿐이므로 현재 들어간 데이터 값 대신 다른 값을 재할당할 수도 있다. 다음의 예는 x에 7을 재할당한 후 앞서 수행한 연산을 다시 수행해 본 것이다.

x <- 7
x + 2
[1] 9
x*2
[1] 14
x^2
[1] 49
2^x
[1] 128

이제 x라는 라벨이 붙은 저장공간에 7이라는 숫자 데이터가 들어가 있으므로 x를 이용한 연산 결과가 앞의 예와는 다르게 나옴을 볼 수 있다.

할당문은 우변이 수행된 후 좌변으로 할당이 이루어진다.

한 명령문 안에서 x의 값을 가져와 연산에 이용한 후 그 결과를 다시 x에 재할당할 수 있다. 이 경우 ‘<-’ 연산자 오른편의 연산이 먼저 수행된 후 ‘<-’ 연산자에 의해 왼편의 변수로 할당이 이루어진다.

x <- x + 1; x
[1] 8
x <- 2 + x; x
[1] 10
x <- x*2; x
[1] 20
x <- x^2; x
[1] 400

마찬가지로 한 변수의 값을 이용하여 연산을 수행한 후 다른 변수에 값을 할당할 수도 있다. 아래 예에서도 볼 수 있듯이 x가 연산에 이용되더라도 재할당이 이루어지지 않으면 x라고 라벨이 붙은 저장공간에 들어가 있는 데이터 값은 동일하다.

x
[1] 400
y <- 2 * x
y
[1] 800
x
[1] 400

여기서도 변수의 값은 할당문에 의해 할당 또는 재할당이 이루어지지 않으면 변화가 없음을 다시 확인할 수 있다.

변수 제거하기 rm()

여러 가지 이유로 변수를 제거할 필요가 있을 수 있다. 변수를 제거하려면 rm() 함수를 이용하면 된다. 제거할 변수를 rm() 함수 내에 기술하면 이 변수가 사라지게 된다.

x; y
[1] 400
[1] 800
rm(x, y)
x
Error in eval(expr, envir, enclos): 객체 'x'를 찾을 수 없습니다
y
Error in eval(expr, envir, enclos): 객체 'y'를 찾을 수 없습니다

rm() 함수로 변수를 제거하면 변수가 사용하는 메모리는 자유롭게 되며, R이 다른 용도로 이용할 수 있다. 여기서 주의할 점은 rm()에 의해서 메모리가 자유롭게 되더라도 R이 사용하던 메모리가 운영체제로 바로 반환되지는 않는다는 것이다. 이를 처리하려면 gc() 함수를 이용하여 garbage collection을 하도록 해야 한다. 그러나 사실 R은 주기적으로 garbage collection을 하므로 특별한 이유가 없으면 이를 별도로 수행할 필요는 없다.

변수 목록 확인하기 ls()

ls() 함수를 이용하면 현재 환경에서 정의되어진 모든 변수의 이름을 출력해 준다. 반면 rm() 함수는 list 인자에 변수의 이름을 주면 해당 변수를 메모리에서 제거한다. 따라서 아래와 같은 방식을 이용하면 현재 환경에 정의되어 있는 모든 변수를 제거할 수 있다.

a <- 5
b <- 7
ls()
[1] "a"              "b"              "file_embedding" "os_type"       
rm(list=ls())
ls()
character(0)

assign()

참고로 assign() 함수로도 변수의 할당은 할 수 있다. 대부분의 경우는 assign() 함수를 이용하는 것보다는 앞서 설명한 할당 연산자를 이용하여 변수에 값을 할당하는 것이 편리하고 이해하기도 쉽다. 그러나 가끔 많은 변수를 자동적으로 생성해야 하는 경우나 데이터베이스에서 변수의 이름을 읽어들여와 값을 할당하는 등의 경우에는 assign() 함수를 이용하는 것이 필요하다.

assign() 함수는 첫번째 인수로 변수의 이름을 문자열로 갖고, 두번째 인수로 변수에 할당한 값을 갖는다.

x1
Error in eval(expr, envir, enclos): 객체 'x1'를 찾을 수 없습니다
assign("x1", 5)
x1
[1] 5
assign("x1", x1 + 3)
x1
[1] 8

위의 예에서 x1이라는 변수가 없었는데, assign() 함수에 의해 x1 변수가 할당되었음을 볼 수 있다. 주의할 점은 보통의 할당문에서는 변수가 문자열과 구분되도록 따옴표 없이 사용되나, assign() 함수에서는 변수의 이름이 문자열로 따옴표와 함께 표시된다는 것이다.

2.4 함수를 이용한 연산

R의 기본 기능에는 다양한 함수가 포함되어 있다. 사용자도 자신만의 함수를 만들 수 있다. 함수는 입력으로 어떤 값을 받은 후 출력으로 어떤 값을 반환한다. 함수가 어떤 값을 입력받고 반환하는지는 함수마다 다르다.

함수 호출 하기

R에서 함수를 이용하려면 다음의 형태로 함수를 호출하여야 한다.

> 함수이름(함수 입력 인수)
함수 출력 값

아래는 제곱근을 구하는 sqrt() 함수의 예이다. 함수의 입력 인수(arguments)로는 4가 주어져 있고 제곱근을 구하는 함수는 입력된 4를 가지고 결과인 2를 반환하고 있다. 함수는 연산자와 함께 사용될 수 있고 함수의 결과가 다시 다른 함수의 입력 인수가 될 수 있다.

sqrt(4)
[1] 2
(sqrt(9) + 2) / 4
[1] 1.25
sin( (sqrt(9) + 2)/ 4 )
[1] 0.9489846
Table 2.1: 수학 관련 주요 함수
수학 함수 설명
ceiling(x) x의 값을 정수로 올림
floor(x) x의 값을 정수로 내림
trunc(x) x의 값의 소수점 자리를 버림
round(x) x의 값을 반올림
round(x, digits=n) x의 값을 소수점 n자리에서 반올림
sqrt(x) x의 제곱근
exp(x) x의 지수함수 값
log(x) 자연대수를 밑으로 하는 로그 값
log(x, base=a) a를 밑으로 하는 로그 값
sin(x), cos(x), tan(x) x의 삼각함수의 값
factorial(n) \(n! = 1 \times 2 \times \cdots \times n\)
choose(n,k) n 개 중 k를 뽑는 조합의 수

실수를 정수로 변환하는 함수

2.1은 R에 내장되어 있는 수학 관련 주요 함수를 보여준다. 다음 예는 함수를 이용하여 숫자에 대한 올림, 내림, 버림, 반올림 등을 수행한 결과이다.

a <- 3.141593
ceiling(a) 
[1] 4
floor(a) 
[1] 3
trunc(a)  
[1] 3
round(a) 
[1] 3
round(a, digits=2)
[1] 3.14

순열과 조합 함수

다음은 순열(factorial)과 조합(combination)의 값을 구한 결과이다. 30에 대한 순열 값은 매우 커서 공학 형식으로 숫자가 표시된다. 이를 일반적인 형식으로 표시하기 위해서 format 함수를 이용하였다.

factorial(5)
[1] 120
factorial(30)
[1] 2.652529e+32
format(factorial(30), scientific = FALSE, )
[1] "265252859812191032188804700045312"
choose(5, 2)
[1] 10
choose(45, 6)
[1] 8145060

함수에 대한 자세한 내용은 10 장의 함수(function)와 관련된 내용을 참조한다.