잠시동안 배운 R

이번에 R 프로그래밍을 배울 수 있었는데, 새로운 언어를 익혀서 재미는 있었지만 너무 수학적인 언어라 다시 쓸일이 있을까 싶은 생각이 든다. 여하간 이번에 배운 R 프로그래밍 기초 문법을 블로그에 기록해 둘 생각이다.



1. 변수의 이름

변수의 이름에는 ‘.’ ‘_’ 등이 올 수 있다. ‘.’은 먼저 사용할 수 있지만 ‘_’는 먼저올 수 없다.

a... = 0 (o)
a___ = 0 (o)
.a = 0 (o)
_a = 0 (x)



2. 대입 연산자

C언어에서는 변수에 값을 넣는 대입연산자로 ‘=’을 사용한다. R에서도 ‘=’을 사용하지만 추가적으로 ‘<-’도 사용한다.

a = 1
b <- 1



3. 문자열

문자열은 파이썬과 문법이 매우 흡사하다. 따옴표는 작은따옴표 큰따옴표 구분하여 사용하지 않고 짝만 맞추면 된다.

a <- 'Hello World'
a <- "Hello World"
a <- "He said 'Hello World'"



4. 불리언

불리언 값은 TRUE 또는 T, FALSE 또는 F 로 표시된다. 불리언 값과 같이 쓰이는 특수문자는 &(AND), |(OR), !(NOT) 등등이 있다.

> T & F
[1] FALSE
> T | F
[1] TRUE
> !TRUE
[1] FALSE



5. 벡터

R 프로그래밍에선 변수(?)는 스칼라, 배열(?)은 벡터로 불리운다. c()함수를 통해서 스칼라값을 벡터로 묶을 수 있다.

> a = c(1,2,3)
[1] 1 2 3
> a = c(1,2,3,c(4,5,6))
[1] 1 2 3 4 5 6
> a = c(c(1,2,3),c(4,5,6))
[1] 1 2 3 4 5 6

벡터에 접근하는 방법은 벡터의 인덱스를 불러오는 것이다. 대부분의 프로그래밍 언어는 배열의 시작이 [0]부터지만 R 에서는 [1]부터 시작이다.

> a[1]
[1] 1
> a[c(1,3)]
[1] 1 3




6. 펙터

변주형 변수, 카테고리를 지정할 수 있는 요소다. 이것은 데이터 프레임을 다룰때 주로 사용되었다.

> sex <- factor(c("M","F"))
> levels(sex)
[1] "F" "M"
> print(sex)
[1] M F
Levels: F M



7. 벡터의 길이

벡터의 길이를 파악하는 함수는 nrow, NROW, length가 있다. nrow 함수는 행렬의 길이만 알아낼 수 있다. 나머지 두개는 벡터도 가능.

> x <- c("a","b","c")
> length(x)
[1] 3
> nrow(x)
NULL
> NROW(x)
[1] 3



8-1. 조건 연산

스칼라 혹은 벡터에 대한 조건의 결과를 얻는 방법이다.

> x <- c(11,12,13,14,19,20)
> x > 15
[1] FALSE FALSE FALSE FALSE  TRUE  TRUE

벡터 x의 값과 15를 비교하여 하나의 벡터값이 만들어졌다. 이 벡터를 x의 인덱스 값으로 넣으면

> x[x>15]
[1] 19 20

벡터 x의 값에서 15보다 큰 값을 추출할 수 있다.


> which(x>15)
[1] 5 6
> which(x==9)
integer(0)

which 함수를 사용하면 조건을 충족하는 값의 위치(?)를 알아낼 수 있다.

> x[which(x>15)]
[1] 19 20
> x[x>15]
[1] 19 20

이 처럼 같은 결과를 출력한다.



8-2. 조건 연산

벡터에서 같은 문자값이 있는지 확인하는 방법은 다음과 같다.

> "a" %in% c("a","b","c")
[1] TRUE
> "d" %in% c("a","b","c")
[1] FALSE



9. 시퀀스

1부터 100까지 들어간 혹은 규칙있는 벡터값을 생성하기 위해선 시퀀스라는 함수를 사용한다.

> seq(1,5)
[1] 1 2 3 4 5
> seq(1,5,2)
[1] 1 3 5
> seq(0,100,5)
 [1]   0   5  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80  85  90
[20]  95 100

이처럼 작성되며 seq(시작 값, 종료 값, 순서)로 표현한다.


> rep(1:2,5)
 [1] 1 2 1 2 1 2 1 2 1 2
> rep(1:2,each=5)
 [1] 1 1 1 1 1 2 2 2 2 2

리피트 함수를 사용하면 시퀀스 함수와는 약간 다른 모양의 벡터 생성이 가능하다.



10. 행렬

행렬은 행의 갯수를 선택하여 생성하거나 열의 갯수를 선택하여 생성할 수 있다. 말로 쓰기 어려우니 다음 코드를 보자.

> matrix(c(0,1,2,3,4,5,6,7,8,9),nrow=2)
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    6    8
[2,]    1    3    5    7    9
> matrix(c(0,1,2,3,4,5,6,7,8,9),ncol=2)
     [,1] [,2]
[1,]    0    5
[2,]    1    6
[3,]    2    7
[4,]    3    8
[5,]    4    9

이처럼 같은 값으로 만든 행렬이지만 행이 2개냐 열이 2개냐의 차이로 모양이 확연히 달라졌다.


     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> matrix(c(1,2,3,4,5,6,7,8,9),ncol=3, byrow=T)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

또 기본은 세로(열) 우선으로 값이 채워져 나가지만 byrow를 통해서 가로(행) 우선으로 값을 채울 수 있다.


> our.mat <- matrix(c(1,2,3,4,5,6,7,8,9),nrow=3,dimnames = list(c("item1","item2","item3"),c("feature1","feature2","feature3")))
> our.mat
      feature1 feature2 feature3
item1        1        4        7
item2        2        5        8
item3        3        6        9

위와같이 각행렬의 이름을 지정해 줄 수도 있다.



행렬에 접근하는 방법은 벡터와 유사하며 2차원 배열에 접근하듯 하면된다. our.mat에 접근해 보도록 하자.

# our.mat[row,col]
> our.mat[1,]
feature1 feature2 feature3
       1        4        7
> our.mat[1,c(1,2)]
feature1 feature2
       1        4
> our.mat[!our.mat[,1]==2,]
      feature1 feature2 feature3
item1        1        4        7
item3        3        6        9
> our.mat["item1",]
feature1 feature2 feature3
       1        4        7

코드번호 10 : our.mat의 1열이 2가 아닌 행을 뽑아내므로 결과는 1,3행이 출력된다. 또한 코드번호 14처럼 행과 열의 이름으로 행열을 뽑아내는 것도 가능하다.


이번엔 행렬의 연산을 해보자.

> our.mat*our.mat
      feature1 feature2 feature3
item1        1       16       49
item2        4       25       64
item3        9       36       81
> our.mat%*%our.mat
      feature1 feature2 feature3
item1       30       66      102
item2       36       81      126
item3       42       96      150

기본적인 *로 곱셈 연산을 실시하면 쓸데없이(?) 행렬의 각각의 자리에서 곱셈이 일어난다. 우리가 알고있는 일반적인 행렬의 곱셈을 실시하기 위해선 코드번호 9와 같이 작성해야 한다.



11. 데이터 프레임

R 프로그래밍에서 가장 중요한 데이터로 사용된다고 한다. 행렬은 숫자의 집합체임에 비해 데이터 프레임은 벡터, 펙터 등등이 모두 합쳐질 수 있기 때문인듯 하다.

> x=c(1,2,3,4,5)
> y=c(2,4,6,8,10)
> z=c('M','F','M','F','M')
> our.dataFrame <- data.frame(x,y,z)

colnames(our.dataFrame) <- c("number", "age", "gender")
rownames(our.dataFrame) <- c("a","b","c","d","e")

데이터 프레임의 생성은 위와같이 이루어지며 데이터 프레임의 구조를 확인하는 방법은 다음과 같다.

> str(our.dataFrame) #
'data.frame':   5 obs. of  3 variables:
 $ x: num  1 2 3 4 5
 $ y: num  2 4 6 8 10
 $ z: Factor w/ 2 levels "F","M": 2 1 2 1 2
> head(our.dataFrame)
  x  y z
1 1  2 M
2 2  4 F
3 3  6 M
4 4  8 F
5 5 10 M
> View(our.dataFrame)

마지막 View의 경우 아래와 같은 창이 새로뜨며 값을 보여준다.



데이터 프레임의 접근 방법은 행렬과 비슷하지만 $ 특수문자를 통해서 벡터의 이름으로 열에 접근이 가능하다.

> our.dataFrame[1,]
  x y z
1 1 2 M
> our.dataFrame$z
[1] M F M F M
Levels: F M
> our.dataFrame[our.dataFrame$z=="F",]
  x y z
2 2 4 F
4 4 8 F



12. 합, 평균

R 프로그래밍에선 벡터의 합과 평균값을 구해주는 함수가 존재한다.

> sum(c(1,2,3))
[1] 6
> sum(c(1,2,3,NA))
[1] NA
> sum(c(1,2,3,NA),na.rm=T)
[1] 6
> mean(c(1,2,3))
[1] 2
> mean(c(1,2,3,NA),na.rm=T)
[1] 2

결칙지(NA)가 있는 경우 원활한 계산이 불가하므로 na.rm으로 결칙치를 모두 제거해야 한다.



13. 조건문

조건문을 작성하는 방법은 C언어와 아주 유사하다.

x <- 1
if(x>3) {
    print("TRUE")
} else {
    print("FALSE")
}

하지만 유의해야 할 점은 if문의 닫히는 중괄호 바로 옆에 else가 (이어지도록)와야한다. 한줄씩 코드가 실행되서 그런것 같다.



14. 반복문

마지막으로 반복문은 for, while이 존재하며 문법은 C와 파이썬이 뒤죽박죽으로 된 느낌이다.

# [ FOR ]
for(i in 1:10) {
    print(i)
}

# [ WHILE ]
i <- 0
while(i<10) {
    print(i)
    i <- i+1
}

R 프로그래밍에선 딱히 반복문을 사용할 일이 적었다. 단기간으로 배워서 그런지도 모르겠다. 유일하게 사용했던 이유는 벡터값을 전부 뒤집기 위해서였다.

a <- NULL

for(i in 1:length(airquality$Ozone)) {
    a[i] <- airquality$Ozone[length(airquality$Ozone)-(i-1)]
}

for(i in 1:length(airquality$Ozone)) {
    print(a[i])
}

이게 따로 함수로 제공되는 기능인지는 모르겠으나 여하간... R은 나랑 잘 안맞는듯, 뭔놈의 언어가 구조만 맨종일 배우는지...



WRITTEN BY

배진오

소비적인 일보단 생산적인 일을 추구하며, 좋아하는 일을 잘하고 싶어합니다 :D
im@baejino.com