새소식

강의 및 세미나 자료/R

R 핵심만 배우기 #4 - 데이터 프레임 2번째

  • -
R 기초 4

데이터 프레임 다루기

지금까지 배웠던 자료구조들을 토대로 데이터를 다루는 것을 조금씩 해보겠습니다.


data.frame 에서 row / column 추가하기

  • 두 벡터를 각각 row로 하는 dataframe을 만들고 싶으면? : rbind
vec1 <- c('one','two','three')
vec2 <- c(1,2,3)

rbind(vec1, vec2)
##      [,1]  [,2]  [,3]   
## vec1 "one" "two" "three"
## vec2 "1"   "2"   "3"
data.frame(rbind(vec1,vec2))
##       X1  X2    X3
## vec1 one two three
## vec2   1   2     3
  • 이번에는, 두 벡터를 각각 column으로 하는 dataframe을 만들고 싶으면? : cbind
vec1 <- c('one','two','three')
vec2 <- c(1,2,3)

cbind(vec1, vec2)
##      vec1    vec2
## [1,] "one"   "1" 
## [2,] "two"   "2" 
## [3,] "three" "3"
df <- data.frame(cbind(vec1,vec2))
str(df)
## 'data.frame':    3 obs. of  2 variables:
##  $ vec1: Factor w/ 3 levels "one","three",..: 1 3 2
##  $ vec2: Factor w/ 3 levels "1","2","3": 1 2 3
  • 그런데 위의 방법은 str(df)에서 보듯이, 숫자든, 문자든 모두 factor로 인식하게 됩니다. 그럴땐, cbind.data.frame이라는 함수를 사용합니다.
cbind.data.frame(vec1, vec2)
##    vec1 vec2
## 1   one    1
## 2   two    2
## 3 three    3
df <- cbind.data.frame(vec1, vec2, stringsAsFactors = F)
str(df)
## 'data.frame':    3 obs. of  2 variables:
##  $ vec1: chr  "one" "two" "three"
##  $ vec2: num  1 2 3

apply 함수 이해하기

행렬 혹은 data.frame에서 각 row, column에 대해 평균을 계산한다든지, 특정 함수를 적용하고 싶을 때가 있죠. 이럴 때, 가장 기본적으로 생각하는 게 for loop를 활용하여 각 row(혹은 column) 별로 함수를 적용합니다.

예를 들어,

mat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow=3)

#각 row의 평균을 계산하고 싶다면
for (i in seq(1:nrow(mat))){
  print(mean(mat[i,]))
}
## [1] 4
## [1] 5
## [1] 6

그런데 많은 양의 데이터를 for loop 하는 것은 비효율적입니다. 매번 for loop를 돌때마다 함수를 불러와야 하기 때문이죠. 따라서 최대한 for loop를 줄이는 것이 중요합니다!! 그 때 사용하는 함수가 바로 apply입니다. apply는 한 번만 함수를 불러와서 모든 데이터에 적용하기 때문에 훨씬 시간을 줄일 수 있습니다.

mat <- matrix(c(1,2,3,4,5,6,7,8,9), nrow=3)
apply(mat, 1, mean) #mean이라는 함수를 row(1)로 적용
## [1] 4 5 6
apply(mat, 2, mean) #mean이라는 함수를 column(2) 별로 적용
## [1] 2 5 8
apply(mat, 1, range) #range 함수는 각행의 최소, 최댓값 2개를 반환함
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    7    8    9

Quiz

iris 데이터 셋에 적용해보자
  1. apply를 활용하여 iris의 Species를 제외한 4개 변수에 대해 평균을 아래와 같이 계산하세요.
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
##     5.843333     3.057333     3.758000     1.199333
  1. apply를 활용하여 Sepal.Length, Sepal.Width의 최소, 최대값을 아래와 같이 구하세요. (최소, 최댓값을 구하는 함수는 range)
##      Sepal.Length Sepal.Width
## [1,]          4.3         2.0
## [2,]          7.9         4.4

list, vector에 대한 for loop 계산

데이터 프레임과 마찬가지로 list, vector에 대해서도 for loop를 최소화 하는 것이 좋습니다. 대신, apply와 비슷하게 lapply, sapply를 사용합니다. 좀 더 구체적으로 예를 들어보면, 리스트 (1,2,3)을 제곱한 값을 반환하고 싶다고 합시다. 그래서 아래와 같이 계산하면 실행이 안되죠. list는 vector처럼 연산 함수가 적용되지 않습니다.

lst <- list(1,2,3)
lst
lst^2

이럴때, for loop를 쓰지 말고, apply의 사촌격인 lapply, sapply를 사용합니다.

lapply(벡터 혹은 리스트, 함수)
sapply(벡터 혹은 리스트, 함수)

앞에 예를 들었듯이, 벡터 c(1,2,3)을 제곱하고 싶다면,

#lapply 이용하면
lst <- list(1,2,3)
lapply(lst, function(x){x^2})
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 4
## 
## [[3]]
## [1] 9

근데 lapply는 결과값이 list로 나오기 때문에, 벡터로 나오게 하고 싶다면 sapply를 이용하면 됩니다.

sapply(lst, function(x){x^2})
## [1] 1 4 9
  • lapply, sapply도 data.frame 에 적용할 수 있는데, apply는 결과값이 data.frame인 반면, lapply, sapply는 결과값이 각각 list, vector 라는 차이가 있습니다. 그리고 기본적으로 각 column에 대해 함수가 적용됩니다.
lst <- lapply(iris[,1:4], sum)
class(lst)
## [1] "list"
vec <- sapply(iris[,1:4], sum)
class(vec)
## [1] "numeric"

좀 더 예를 들어보죠,

#iris 데이터의 각 데이터 타입을 보고 싶다면?
sapply(iris, class)
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
##    "numeric"    "numeric"    "numeric"    "numeric"     "factor"
#3보다 큰 값만 추출하고 싶으면
y <- sapply(iris[, 1:4], function(x){ x > 3 })

Quiz

  1. iris 데이터를 0~1 사이 값으로 바꿔라

hint: 서로 다른 변수의 데이터가 scale이 다를 경우(어떤 변수는 -10~0 사이인데, 다른 변수는 10~1000인 경우), 정규분포를 활용한 정규화 뿐만 아니라, min, max를 활용하여 0~1사이로 바꾸는 방법도 있습니다. 즉, 다음 함수를 각 row에 적용하면 됩니다. \(\frac{x-min(x)}{max(x)-min(x)}\)

##      Sepal.Length Sepal.Width Petal.Length Petal.Width
## [1,]   0.22222222   0.6250000   0.06779661  0.04166667
## [2,]   0.16666667   0.4166667   0.06779661  0.04166667
## [3,]   0.11111111   0.5000000   0.05084746  0.04166667
## [4,]   0.08333333   0.4583333   0.08474576  0.04166667
## [5,]   0.19444444   0.6666667   0.06779661  0.04166667
## [6,]   0.30555556   0.7916667   0.11864407  0.12500000

apply의 사촌들

이제부터는 apply와 비슷한 원리지만, 각 상황에 맞게 tapply, mapply 가 있는데, 자주 사용되지는 않지만, 한 번 보고 갈게요.

#tapply : 각 집단에 따라 데이터를 처리하고 싶을때
str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#예를 들어, iris 데이터에서 각 종별로 Sepal.Length의 평균을 알고 싶으면?
#tapply(데이터, 색인, 함수) #여기서 색인은 factor!
tapply(iris$Sepal.Length, iris$Species, mean)
##     setosa versicolor  virginica 
##      5.006      5.936      6.588

Quiz

  1. Species 별 Sepal.Width 의 분산은?
##     setosa versicolor  virginica 
## 0.14368980 0.09846939 0.10400408

mapply

여러 벡터에 동일한 함수를 적용하고 싶을때 사용합니다. 아래와 같이 최대공약수를 구하는 함수 gcd가 있다고 합시다.

gcd <- function(a,b) {
  if (b==0) return(a)
  else return(gcd(b, a%%b))
}

gcd(6,4)
## [1] 2
#그러나, 아래와 같이 두 벡터의 각 원소간 값을 input으로 하고 싶을때 아래와 같은 문법은 오류가 발생합니다.
gcd(c(3,6,9), c(12,15,18))
## Warning in if (b == 0) return(a) else return(gcd(b, a%%b)): length > 1 이라
## 는 조건이 있고, 첫번째 요소만이 사용될 것입니다

## Warning in if (b == 0) return(a) else return(gcd(b, a%%b)): length > 1 이라
## 는 조건이 있고, 첫번째 요소만이 사용될 것입니다

## Warning in if (b == 0) return(a) else return(gcd(b, a%%b)): length > 1 이라
## 는 조건이 있고, 첫번째 요소만이 사용될 것입니다
## [1] 3 6 9
#이 경우 mapply 활용
mapply(gcd, c(3,6,9), c(12,15,18))
## [1] 3 3 9

참고 : Sampling

기계학습 모델링을 사용하다 보면, 무작위로 데이터를 추출해야할 경우가 생깁니다. 이럴 때 sample 함수를 사용하죠.

#1~10에서 무작위로 5개 추출
sample(1:10, 5) #중복 허락 하지 않고.
## [1] 4 8 9 5 7
sample(1:10, 5, replace=T) #중복을 허락해서 추출
## [1]  4  5  9  7 10
  • iris 데이터에서 임의로 전체의 15% 데이터 추출하기
index <- 1:nrow(iris) # 1부터 iris행의 개수
train_idx <- sample(index, round(nrow(iris)*0.15))
head(iris[train_idx,])
##     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 99           5.1         2.5          3.0         1.1 versicolor
## 56           5.7         2.8          4.5         1.3 versicolor
## 43           4.4         3.2          1.3         0.2     setosa
## 44           5.0         3.5          1.6         0.6     setosa
## 135          6.1         2.6          5.6         1.4  virginica
## 139          6.0         3.0          4.8         1.8  virginica


Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.