엑셀의 “텍스트 나누기” 기능을 R에서 구현하는 방법을 설명하고자 한다.
여기서 가장 중요한 함수는 [ 함수이다.
일반적으로 리스트 데이터 유형을 다룰 때 주로 사용하는 기호인데, [기호는 실제로 함수이다. 일반적으로 리스트 원소를 추출할 때 mylist[1]과 같이 작성하는데, 실제로 ’내부’에서 일어나는 일은 측면 대괄호 안에 있는 번호 또는 이름이 지정된 항목 (이 경우 하나만)이 추출되어 ’mylist’의 [함수에 전달된다. 여기서는 첫 번째 함수 인수이므로 다음과 같다고 할 수 있다.
[(list, 1) 즉, 이것은 list[[1]]과 같음.
[ 를 대신하는 magtrittr::extract() 추가
library(dplyr) # %>% 연산자를 사용하기 위해 필요함.
library(stringr) # str_split 등 string을 처리하기 위해 필요함.
v1 <- c("ASUSTeK Computer Inc.","ASUSTeK Computer Inc.","Altos Computing Inc.","China Academy of Technology","Cisco Systems","Dell Inc" )
v2 <- c(72,72,40,96,224,96)
data<-data.frame(v1,v2)
data %>% str()
'data.frame': 6 obs. of 2 variables:
$ v1: chr "ASUSTeK Computer Inc." "ASUSTeK Computer Inc." "Altos Computing Inc." "China Academy of Technology" ...
$ v2: num 72 72 40 96 224 96
data
v1 v2
1 ASUSTeK Computer Inc. 72
2 ASUSTeK Computer Inc. 72
3 Altos Computing Inc. 40
4 China Academy of Technology 96
5 Cisco Systems 224
6 Dell Inc 96
v1 컬럼의 문자열을 공백(white space)을 기준으로 나누어서 첫번째 문자열만 ’Company’라는 컬럼에 넣어보자.
k<-data$v1 %>% str_split("\\s+")
k
[[1]]
[1] "ASUSTeK" "Computer" "Inc."
[[2]]
[1] "ASUSTeK" "Computer" "Inc."
[[3]]
[1] "Altos" "Computing" "Inc."
[[4]]
[1] "China" "Academy" "of" "Technology"
[[5]]
[1] "Cisco" "Systems"
[[6]]
[1] "Dell" "Inc"
출력을 확인하면 리스트 유형임을 알 수 있다.
이 리스트의 원소를 추출하는 방법은 여러가지가 있다.
대표적으로 다음과 같다.
k[[1]]
[1] "ASUSTeK" "Computer" "Inc."
k[[1]][[1]]
[1] "ASUSTeK"
k[[4]][[4]]
[1] "Technology"
그런데, %>% 연산자를 사용할 때는 이런 방식으로 추출이 불가능하고, 특히 각 리스트의 1th 원소들만 한번에 추출하는 것은 불가능하다.
예를 들어 다음과 같이 수행하면 에러가 발생한다.
data$v1 %>% str_split("\\s+") %>% .[[1]] # 에러 발생하지 않음
[1] "ASUSTeK" "Computer" "Inc."
data$v1 %>% str_split("\\s+") %>% .[[1]][[1]] # 에러 발생
Error in .[[.[[1]], 1]]: 첨자들의 개수가 올바르지 않습니다
data$v1 %>% str_split("\\s+") %>% .[[1]] %>% .[[1]] # 에러 발생하지 발생
[1] "ASUSTeK"
data$v1 %>% str_split("\\s+") %>% .[[4]] %>% .[[4]] # 에러 발생하지 않음
[1] "Technology"
data$v1 %>% str_split("\\s+") %>% .[[]] %>% .[[1]] # NULL 값 출력
NULL
각 리스트의 1th 원소들만 추출하는 방법이 필요하다.
여기에 사용된 것이 [ 기호의 함수이다.
아래를 보자.
data %>%
mutate(Company=data$v1 %>% # "Company" 컬럼을 아래의 내용으로 추가
str_split("\\s+") %>% # 공백을 기준으로 분리
sapply(`[`,1), # 리스트의 첫번째 항목에 대해 sapply 적용
.before=v1) # "Company" 컬럼을 v1 컬럼 이전에 삽입
Company v1 v2
1 ASUSTeK ASUSTeK Computer Inc. 72
2 ASUSTeK ASUSTeK Computer Inc. 72
3 Altos Altos Computing Inc. 40
4 China China Academy of Technology 96
5 Cisco Cisco Systems 224
6 Dell Dell Inc 96
[,1): 이 의미는 리스트의 첫번째 항목에 대해 sapply를 적용하라는 뜻이다. 리스트의 두번째 항목을 적용하고 싶을 때는 2를 사용하면 된다.이번에는 v1 컬럼의 각 문자열을 공백을 기준으로 분리해서 분리된 문자열을 모두 각각의 컬럼에 삽입해 보자.
먼저 리스트의 구조가 어떻게 되는지 위에서 다시한번 살펴보자.
data$v1 %>% str_split("\\s+") %>% sapply(length) # 각 리스트의 원소 개수 파악
[1] 3 3 3 4 2 2
data$v1 %>% str_split("\\s+") %>% sapply(length) %>% max() # 최대 원소 개수 파악
[1] 4
최대 원소 개수가 4개다. 따라서 4개의 컬럼이 추가될 것이다.
data %>%
mutate(com1=data$v1 %>%
str_split("\\s+") %>%
sapply(`[`,1),
com2=data$v1 %>%
str_split("\\s+") %>%
sapply(`[`,2),
com3=data$v1 %>%
str_split("\\s+") %>%
sapply(`[`,3),
com4=data$v1 %>%
str_split("\\s+") %>%
sapply(`[`,4),
.before=v1) # "Company" 컬럼을 v1 컬럼 이전에 삽입
com1 com2 com3 com4 v1 v2
1 ASUSTeK Computer Inc. <NA> ASUSTeK Computer Inc. 72
2 ASUSTeK Computer Inc. <NA> ASUSTeK Computer Inc. 72
3 Altos Computing Inc. <NA> Altos Computing Inc. 40
4 China Academy of Technology China Academy of Technology 96
5 Cisco Systems <NA> <NA> Cisco Systems 224
6 Dell Inc <NA> <NA> Dell Inc 96
위와 같이 v1 컬럼의 문자열이 공백을 기준으로 분리되어 com1, com2, com3, com4에 삽입되었고, 문자열이 없는 셀은 NA로 처리된 것을 볼 수 있다.
library(magrittr)
data %>%
mutate(com1=data$v1 %>%
str_split("\\s+") %>%
sapply(extract,1),
com2=data$v1 %>%
str_split("\\s+") %>%
sapply(extract,2),
com3=data$v1 %>%
str_split("\\s+") %>%
sapply(extract,3),
com4=data$v1 %>%
str_split("\\s+") %>%
sapply(extract,4),
.before=v1)
com1 com2 com3 com4 v1 v2
1 ASUSTeK Computer Inc. <NA> ASUSTeK Computer Inc. 72
2 ASUSTeK Computer Inc. <NA> ASUSTeK Computer Inc. 72
3 Altos Computing Inc. <NA> Altos Computing Inc. 40
4 China Academy of Technology China Academy of Technology 96
5 Cisco Systems <NA> <NA> Cisco Systems 224
6 Dell Inc <NA> <NA> Dell Inc 96