Chapter 4 R program basic

4.1 기초 연산

단순 계산기로 사용할 수 있다. 예를 들어 1+2 의 값이라던가, log2(10) 등을 계산할 수 있다. Rsutdio 의 스크립트 창이나 콘솔 창에 아래의 항목을 작성해 볼 수 있다.

3+4;4-3;4/3;3*4
log2(10)
abs(-4)
sqrt(4)

기초 함수는 아래와 같다.

함수 종류
Logarithms and exponentials log2(x), log10(x), exp(x)
Trigonometric functions cos(x), sin(x), tan(x), acos(x), asin(x), atan(x)
Others abs(x): absolute value; sqrt(x): square root.

4.2 조건부 연산

if-else 라는 조건에 따라 연산을 수행시킨다. 예를 들어 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 의 백터에서 5보다 작으면 A 크면 B를 적용시켜주다.

nums<- 1
if (nums <5) {
        chars = 'A'
} else{
        chars = 'B'
}
chars
## [1] "A"
nums <- 6
if (nums <5) {
        chars = 'A'
} else{
        chars = 'B'
}
chars
## [1] "B"

몇가지 예제를 더 살펴보자.

a<-round(rnorm(10)*10)
a
##  [1]  10  -3   8  -1  -2   0 -11  18 -12  16
tab <- ifelse(a>0, '양수', '음수')
tab
##  [1] "양수" "음수" "양수" "음수" "음수" "음수" "음수" "양수" "음수" "양수"
data.frame(a, tab)
##      a  tab
## 1   10 양수
## 2   -3 음수
## 3    8 양수
## 4   -1 음수
## 5   -2 음수
## 6    0 음수
## 7  -11 음수
## 8   18 양수
## 9  -12 음수
## 10  16 양수

데이터 클리닝에서 자주 사용하는 두개의 조건문 any()all()이 있다. any()는 하나라도 TRUE값이 있으면 TRUE를 변환해주고, all()은 모두 TRUE여야 TRUE를 돌려준다.

new.var <- c(1, 2, NA)
is.na(new.var)
## [1] FALSE FALSE  TRUE
any(is.na(new.var))
## [1] TRUE
all(is.na(new.var))
## [1] FALSE

index 를 이용하면 조건 문에서 IF (또는 Where)의 개념을 사용할 수 있다. iris 데이터에서 Sepal.Length 가 가장 큰 값은 찾고, Sepal.Length 최고 값을 갖은 Species의 종류를 찾고자한다. 어떻게 하면될까?

head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
table(iris$Species)
## 
##     setosa versicolor  virginica 
##         50         50         50
max(iris$Sepal.Length)
## [1] 7.9
max.length <- which.max(iris$Sepal.Length)
iris$Species[max.length]
## [1] virginica
## Levels: setosa versicolor virginica

4.3 함수 만들기

저자가 R을 이용하는 이유중 하나가 함수를 손쉽게 만들고 그 결과를 활용하기가 쉽다는 것이다. 자동문, 반복문, 데이터 클리능, 데이터 시각화 등에서 자주 사용하는 기본 원리이다. 평균을 구해주는 함수 avg를 만들어 보자

my_vector<- 1:50
avg <- function(x){
        sum(x)/length(x)
}
avg(my_vector)
## [1] 25.5

좀더 확장해서 변수 갯수, 평균, 최고, 최저 값을 나타내는 함수를 만들어 보자.

tabs <- function(x){
        data.frame( '평균'      = mean(x), 
                    '변수갯수'  = length(x), 
                    '최고값'    = max(x), 
                    '최저값'    = min(x)
        )
}

tabs(my_vector)
##   평균 변수갯수 최고값 최저값
## 1 25.5       50     50      1

그럼 이를 이용해서, 다음을 해석해 보자

avg <- function(x, arithmetic = TRUE){
  n <- length(x)
  ifelse(arithmetic, sum(x)/n, prod(x)^(1/n))
}

4.4 반복문, vectorization, functionals

4.4.1 for loop

1a, 2a, 3a, 4a, 5a, 6a, 7a, 8a, 9a, 10a 을 만들어보자, 어떻게 하면될까?

c('1a', '2a', '10a') # 이렇게 해보는 것도 좋지만
## [1] "1a"  "2a"  "10a"

반목문을 사용하면, 아래와 같다.

for (i in 1:10){
  print(paste0(i, 'a'))
}
## [1] "1a"
## [1] "2a"
## [1] "3a"
## [1] "4a"
## [1] "5a"
## [1] "6a"
## [1] "7a"
## [1] "8a"
## [1] "9a"
## [1] "10a"

물론 대부분 이렇게 사용하지만, 반복문을 사용하여 확장할 수 있다.

paste0(1:10, "a")
##  [1] "1a"  "2a"  "3a"  "4a"  "5a"  "6a"  "7a"  "8a"  "9a"  "10a"

1:n까지의 숫자 합을 만들어보자, 그리고 이를 1부터 100일때 까지 만들고 그림을 그려보자

compute <- function(n){ sum(1:n)}
compute(10)
## [1] 55
test <-c()
for (n in 1:100){
  test[n] <- compute(n)
}

plot(1:100, test)

4.4.2 vectorization 과 apply 구문

사실 ifelse 를 잘 사용하지 않는다. 이는 속도의 문제와도 관련된다. 실제 ifesel 로 10분이 걸리는 연산이 1분으로 줄수도 있다. 이때 사용하게 되는 것이 백터화와 apply 구문이다. 이미 past0(1:10,“a”) 같은 구문이 편할 수 있다는 것을 느꼈을 것이다. 이번에는 구구단 2단과 3단을 서로 곱해보자. 어떻게 하면 좋을까 forif를 생각하기 보다 아래를 고려해 보자. 아래가 백터화이다.

n2 <- c(1:9*2)
n3 <- c(1:9*3)
n2*n3
## [1]   6  24  54  96 150 216 294 384 486

2단에 3단이 아닌 다른 단을 곱하는 함수를 사용해 보자

new.function<-function(n2){
  c(1:9*2) * c(1:9*n2)
}

new.function( 4)
## [1]   8  32  72 128 200 288 392 512 648

그럼 3단 대신에 1, 2, 3, 4, 5, 6, 7, 8, 9 단을 모두 해보자

sapply(1:9, new.function)
##       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
##  [1,]    2    4    6    8   10   12   14   16   18
##  [2,]    8   16   24   32   40   48   56   64   72
##  [3,]   18   36   54   72   90  108  126  144  162
##  [4,]   32   64   96  128  160  192  224  256  288
##  [5,]   50  100  150  200  250  300  350  400  450
##  [6,]   72  144  216  288  360  432  504  576  648
##  [7,]   98  196  294  392  490  588  686  784  882
##  [8,]  128  256  384  512  640  768  896 1024 1152
##  [9,]  162  324  486  648  810  972 1134 1296 1458

상기 행렬을 만들기위해 ifelse를 사용하거나 for 문을 사용하면 좀더 머리가 복잡해 질 수 있다. apply 구문은 확실히 머리가 가벼워진다. tidyverse 부분을 할 때 apply, lapply, tapply, mapply, vaply, replicate등을 다루게 될 것이다.