11.4 stringr 패키지 함수

이전 장에서는 정규식을 위한 R 의 stringr 패키지의 함수들에 대하여 간략하게 살펴보았다.

앞에서 언급했듯이 모든 stringr 패키지의 함수들은 공통적인 함수의 구조를 공유한다.

`str_function(string, pattern)`

주요 두 인수는 처리 될 string 벡터와 일치하는 단일 pattern (예 : 정규 표현식)이다.

또한 모든 함수의 이름은 접두사 str_로 시작하고 처리할 행동의 이름이 온다.

예를 들어, 첫 번째 발생 위치를 찾으려면 str_locate(); 모든 일치하는 위치를 찾으려면 str_locate.all()을 사용한다.

11.4.1 str_detect() 함수를 이용한 패턴의 발견

string 벡터에 pattern이 있는지 여부를 감지하기 위해 str_detect() 함수를 사용할 수 있다.

실제로 이 함수는 grepl()와 유사하다. 즉, 결과는 논리형을 반환한다.

library(stringr)

# some objects
some_objs <- c("pen", "pencil", "marker", "spray")

# detect phones
str_detect(some_objs, "pen")
## [1]  TRUE  TRUE FALSE FALSE
# select detected macthes
some_objs[str_detect(some_objs, "pen")]
## [1] "pen"    "pencil"

str_detect() 함수의 출력은 지정된 string과 길이가 같은 이진 벡터(TRUE/FALSE)이다.

string에서 일치하는 항목이 발견되면 TRUE이고, 그렇지 않으면 FALSE이다.

다음은 patternday-month-year의 날짜와 일치하는 더 정교한 예이다.

# some strings
strings <- c("12 Jun 2002", " 8 September 2004 ", "22-July-2009 ",
             "01 01 2001", "date", "02.06.2000",
             "xxx-yyy-zzzz", "$2,600")

# date pattern (month as text)
dates <- "([0-9]{1,2})[- .]([a-zA-Z]+)[- .]([0-9]{4})"

# detect dates
str_detect(strings, dates)
## [1]  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE
# select detected macthes
strings[str_detect(strings, dates)]
## [1] "12 Jun 2002"        " 8 September 2004 " "22-July-2009 "

11.4.2 str_extract() 함수를 이용한 첫 번째 일치 추출

pattern이 포함된 string을 추출하기 위해 str_extract() 함수를 사용할 수 있다.

실제로 이 함수는 주어진 pattern과 일치하는 string의 첫 번째 부분을 추출한다.

예를 들어 Paris에 대한 트윗이있는 문자형 벡터가 있고 해시 태그를 추출한다고 가정하자.

# [a-zA-Z]{1}과 같은 #hashtag pattern을 정의하면 된다.

# tweets about 'Paris'
paris_tweets <- c(
  "#Paris is chock-full of cultural and culinary attractions",
  "Some time in #Paris along Canal St.-Martin famous by #Amelie",
  "While you're in #Paris, stop at cafe: http://goo.gl/yaCbW",
  "Paris, the city of light")

# hashtag pattern
hash <- "#[a-zA-Z]{1,}"

# extract (first) hashtag
str_extract(paris_tweets, hash)
## [1] "#Paris" "#Paris" "#Paris" NA
  • str_extract() 함수의 출력은 string 즉, paris_tweets와 길이가 같은 벡터이다.
  • pattern과 일치하지 않는 요소는 NA로 표시된다.
  • str_extract() 함수는 첫 번째 pattern하고만 일치한다. 두 번째 요소에 있는 "#Amelie" 해시 태그는 추출되지 않았다.

11.4.3 str_extract_all() 함수를 이용한 모든 일치 추출

str_extract() 함수이외에도 stringr 패키지는 str_extract_all() 함수를 제공한다.

함수의 이름에서 알 수 있듯이 str_extract_all() 함수를 사용하여 string 벡터의 모든 패턴을 추출한다.

출력 결과는 list 형이다.

이전 예제와 동일한 string을 사용하여 다음과 같이 모든 해시 태그 일치를 추출 할 수 있다.

# extract (all) hashtags
str_extract_all(paris_tweets, "#[a-zA-Z]{1,}")
## [[1]]
## [1] "#Paris"
## 
## [[2]]
## [1] "#Paris"  "#Amelie"
## 
## [[3]]
## [1] "#Paris"
## 
## [[4]]
## character(0)
  • str_extract() 함수와 비교하여 str_extract_all() 함수의 출력은 string과 동일한 길이의 list 형 이다.
  • 또한 pattern일치하지 않는 요소NA 대신 빈 문자형 벡터 character (0)로 표시된다.

11.4.4 str_match() 함수를 이용한 첫 번째 일치 추출

str_extract() 함수와 밀접한 관련이 있는 함수로 stringr 패키지가 제공하는 또 다른 추출 함수는 str_match() 함수이다.

이 함수는 일치하는 패턴을 추출 할 뿐만 아니라, 일치하는 각 그룹을 정규 표현식 문자 클래스 패턴으로 표시한다.

# string vector
strings <- c("12 Jun 2002", " 8 September 2004 ", "22-July-2009 ",
             "01 01 2001", "date", "02.06.2000",
             "xxx-yyy-zzzz", "$2,600")

# date pattern (month as text)
dates <- "([0-9]{1,2})[- .]([a-zA-Z]+)[- .]([0-9]{4})"

# extract first matched group
str_match(strings, dates)
##      [,1]               [,2] [,3]        [,4]  
## [1,] "12 Jun 2002"      "12" "Jun"       "2002"
## [2,] "8 September 2004" "8"  "September" "2004"
## [3,] "22-July-2009"     "22" "July"      "2009"
## [4,] NA                 NA   NA          NA    
## [5,] NA                 NA   NA          NA    
## [6,] NA                 NA   NA          NA    
## [7,] NA                 NA   NA          NA    
## [8,] NA                 NA   NA          NA
  • 출력은 벡터가 아니라 문자 행렬이다.
  • 각각의 행은 첫 번째 열은 strings 요소가 패턴과 일치하는 경우 그 요소 값을 표시하고, 다른 열은 각각의 포착된 요소들을 표기하고 있다.
  • dates 패턴과 일치하지 않는 요소의 경우는 NA로 출력이 된다.

11.4.5 str_match_all() 함수를 이용한 모든 일치 추출

우리가 찾고 있는 것이 string 벡터에서 모든 패턴을 추출하는 경우 str_extract() 함수 대신 str_extract_all() 함수를 사용해야 한다.

# tweets about 'Paris'
paris_tweets <- c(
  "#Paris is chock-full of cultural and culinary attractions",
  "Some time in #Paris along Canal St.-Martin famous by #Amelie",
  "While you're in #Paris, stop at cafe: http://goo.gl/yaCbW",
  "Paris, the city of light")

# match (all) hashtags in 'paris_tweets'
str_match_all(paris_tweets, "#[a-zA-Z]{1,}")
## [[1]]
##      [,1]    
## [1,] "#Paris"
## 
## [[2]]
##      [,1]     
## [1,] "#Paris" 
## [2,] "#Amelie"
## 
## [[3]]
##      [,1]    
## [1,] "#Paris"
## 
## [[4]]
##      [,1]
  • str_match () 함수와 비교하여 str_match_all() 함수의 출력은 list이다.
  • 또한 list의 각 요소는 해시 태그와 일치하는 행의 수를 갖는 행렬이다.
  • pattern과 일치하는 것이 없는 요소는 아무 것도 출력되지 않는다.

11.4.6 str_locate() 함수를 이용한 첫 번째 일치 위치 확인

정규 표현식 패턴을 감지, 추출 및 일치시키는 것 외에도 stringr 패키지는 패턴의 발생 위치를 찾을 수 있게 해준다.

string 벡터에서 pattern첫 번째 발생 위치를 찾으려면 str_locate() 함수를 사용해야 한다.

# tweets about 'Paris'
paris_tweets <- c(
  "#Paris is chock-full of cultural and culinary attractions",
  "Some time in #Paris along Canal St.-Martin famous by #Amelie",
  "While you're in #Paris, stop at cafe: http://goo.gl/yaCbW",
  "Paris, the city of light")

# locate position of (first) hashtag
str_locate(paris_tweets, "#[a-zA-Z]{1,}")
##      start end
## [1,]     1   6
## [2,]    14  19
## [3,]    17  22
## [4,]    NA  NA
  • str_locate() 함수의 출력은 두 개의 열과 (string) 벡터의 요소 만큼의 행을 가지는 행렬이다.
    • 출력의 첫 번째 열은 시작 위치(start)이고, 두 번째 열은 종료 위치(end)이다.
  • 앞의 예에서 결과는 4행 2열의 행렬이다.
    • 첫 번째 행은 첫 번째 트윗의 해시 태그에 해당하는데, 위치 1에서 시작하여 위치 6에서 끝나고 있음을 보여주고 있다.
    • 두 번째 행은 두 번째 트윗의 해시 태그에 해당하며, 시작 위치는 14 번째 문자이고 끝 위치는 19 번째 문자이다.
    • 네 번째 행은 네 번째 트윗에 해당하며, 해시 태그가 없으므로 해당 행의 값은 NA입니다.

11.4.7 str_locate_all() 함수를 이용한 모든 일치 위치 확인

string 벡터에서 첫 번째 패턴뿐만 아니라 모든 패턴의 발생 위치를 찾으려면 str_locate_all() 함수를 사용해야 한다.

# tweets about 'Paris'
paris_tweets <- c(
  "#Paris is chock-full of cultural and culinary attractions",
  "Some time in #Paris along Canal St.-Martin famous by #Amelie",
  "While you're in #Paris, stop at cafe: http://goo.gl/yaCbW",
  "Paris, the city of light")

# locate (all) hashtags in 'paris_tweets'
str_locate_all(paris_tweets, "#[a-zA-Z]{1,}")
## [[1]]
##      start end
## [1,]     1   6
## 
## [[2]]
##      start end
## [1,]    14  19
## [2,]    54  60
## 
## [[3]]
##      start end
## [1,]    17  22
## 
## [[4]]
##      start end
  • str_locate() 함수와 비교하여 str_locate_all() 함수의 출력은 제공된 string 벡터와 동일한 길이의 list 이다.
  • list의 요소는 차례로 두 개의 열을 갖는 행렬이다. pattern과 일치하지 않는 요소들은 NA 대신 아무것도 표시가 되지 않는다.
  • str_locate_all() 함수를 Paris 트윗에 적용한 결과를 보면,
    • 두 번째 요소에 #Paris#Amelie 해시 태그의 시작 및 끝 위치가 표시되어 있음을 알 수 있다.
    • 결과적으로 네 번째 요소는 연관된 트윗에 해시 태그가 없음을 보여 주고 있다.

11.4.8 str_replace() 함수를 이용한 첫 번째 일치 대체

string 벡터에서 처음 일치하는 패턴을 대체하기 위해서는 str_replace() 함수를 사용할 수 있다.

사용법은 다음과 같다:

`str_replace(string, pattern, replacement)`
  • str_replace() 함수에는 stringpattern 이라는 두 개의 인수 이외에도 replacement (대체)을 나타내는 세 번째 인수가 필요하다.

San Francisco, Barcelona, Naples 그리고 Paris 등의 도시 이름이 벡터로 있다고 가정해 보자.

각 이름의 첫 번째 모음을 세미콜론(;)으로 바꾸려고 한다고 가정하자.

이를 수행하는 방법은 다음과 같다:

# city names
cities <- c("San Francisco", "Barcelona", "Naples", "Paris")

# replace first matched vowel
str_replace(cities, "[aeiou]", ";")    # 각각의 도시명에서 첫번째 모음을 ;으로 바꿈
## [1] "S;n Francisco" "B;rcelona"     "N;ples"        "P;ris"

이제 각 이름에서 첫 번째 자음을 바꿔 보자. 부정 클래스(negated class)로 패턴을 수정하면 된다:

# replace first matched consonant
str_replace(cities, "[^aeiou]", ";")
## [1] ";an Francisco" ";arcelona"     ";aples"        ";aris"

11.4.9 str_replace_all() 함수를 이용한 모든 일치 대체

string에서 일치하는 pattern의 모든 항목을 바꾸려면 str_replace_all() 함수를 사용할 수 있다.

다시 한 번 도시 이름(cities)을 가진 벡터를 고려하고 각 이름에 있는 모든 모음을 바꾸고 싶다고 가정 해 보자:

# city names
cities <- c("San Francisco", "Barcelona", "Naples", "Paris")

# replace all matched vowel
str_replace_all(cities, pattern = "[aeiou]", ";")
## [1] "S;n Fr;nc;sc;" "B;rc;l;n;"     "N;pl;s"        "P;r;s"

다른 방법으로, 각 이름에 있는 모든 자음을 세미콜론(;)으로 바꾸려면 pattern부정 클래스(^)"[^aeiou]"로 변경하면 된다.

# replace all matched consonants
str_replace_all(cities, pattern = "[^aeiou]", ";")
## [1] ";a;;;;a;;i;;o" ";a;;e;o;a"     ";a;;e;"        ";a;i;"

11.4.10 str_split() 함수를 이용한 문자열 분할

strsplit() 함수와 유사하게 stringr 패키지는 문자 벡터를 여러 조각으로 분리하는 str_split() 함수를 제공한다.

이 함수의 사용은 다음과 같은 형식을 따른다:

`str_split(string, pattern, n = Inf)`
  • 인수 n은 분할할 최대의 개수이다.
  • 디폴트 값(n = Inf)은 가능한 모든 분할 위치가 사용됨을 의미한다.

하나의 문장을 개별 단어들로 나누고자 할 때, strsplit() 함수와 같은 예를 살펴보자:

# a sentence
sentence <- c("R is a collaborative project with many contributors")

# split into words
str_split(sentence, " ") %>% unlist()
## [1] "R"             "is"            "a"             "collaborative"
## [5] "project"       "with"          "many"          "contributors"

마찬가지로 “-”로 연결된 전화번호 숫자를 부분 부분 분리하여 보자.

# telephone numbers
tels <- c("510-548-2238", "707-231-2440", "650-752-1300")

# split each number into its portions
str_split(tels, "-")
## [[1]]
## [1] "510"  "548"  "2238"
## 
## [[2]]
## [1] "707"  "231"  "2440"
## 
## [[3]]
## [1] "650"  "752"  "1300"
  • 결과는 문자형 벡터의 list 이다. string 벡터의 각 요소는 결과 list의 요소에 해당한다.
  • list의 각 요소는 일치로부터 발생하는 분할 벡터 (즉, 분할 개수)를 포함할 것이다.

인수 n의 사용을 보여주기 위해, "chocolate", "vanilla", "cinnamon", "mint", 그리고 "lemon" 등을 요소로 하는 flavors벡터를 생각해 보자.

모음의 클래스([aeiou])를 pattern으로 정의하는 각 flavors 이름을 분할한다고 가정하자:

# string
flavors <- c("chocolate", "vanilla", "cinnamon", "mint", "lemon")

# split by vowels
str_split(flavors, "[aeiou]")
## [[1]]
## [1] "ch" "c"  "l"  "t"  ""  
## 
## [[2]]
## [1] "v"  "n"  "ll" ""  
## 
## [[3]]
## [1] "c"  "nn" "m"  "n" 
## 
## [[4]]
## [1] "m"  "nt"
## 
## [[5]]
## [1] "l" "m" "n"

이제 최대 개수를 n = 2로 수정한다.

이는 str_split() 함수가 각 요소를 최대 2 개로 분할한다는 의미이다.

우리는 다음과 같은 결과를 얻을 것이다:

# split by first vowel
str_split(flavors, "[aeiou]", n = 2)
## [[1]]
## [1] "ch"     "colate"
## 
## [[2]]
## [1] "v"     "nilla"
## 
## [[3]]
## [1] "c"      "nnamon"
## 
## [[4]]
## [1] "m"  "nt"
## 
## [[5]]
## [1] "l"   "mon"

11.4.11 str_split_fixed() 함수를 이용한 문자열 분할

str_split() 함수 이외에도 string고정된 수의 조각으로 나누는 str_ split_fixed() 함수도 있다.

사용 형식은 다음과 같다:

`str_split_fixed(string, pattern, n)`
  • 인수 n에는 기본값이 없다. 다시 말해, 조각의 수를 나타내기 위해 정수를 지정해야 한다.

동일한 flavors 벡터와 일치하는 pattern으로 문자 “n”을 다시 고려하기로 한다.

n = 2str_split_fixed() 함수의 동작을 살펴보기로 한다.

# string
flavors <- c("chocolate", "vanilla", "cinnamon", "mint", "lemon")

# split flavors into 2 pieces
str_split_fixed(flavors, "n", 2)
##      [,1]        [,2]   
## [1,] "chocolate" ""     
## [2,] "va"        "illa" 
## [3,] "ci"        "namon"
## [4,] "mi"        "t"    
## [5,] "lemo"      ""
  • 출력은 n = 2만큼 2개의 컬럼을 가진 문자 행렬이다.
  • "chocolate"에는 문자 "n"이 포함되어 있지 않으므로 두 번째 열의 해당 값은 ""로 유지된다.
  • 반대로 "lemon"과 관련된 두 번째 열의 값도 비어 있다. 그러나 이것은이 flavor"lemo"""로 분리되기 때문이다.

n의 값을 n = 3으로 변경하면 3 개의 열이있는 행렬이 생성된다.

# split favors into 3 pieces
str_split_fixed(flavors, "n", 3)
##      [,1]        [,2]   [,3]  
## [1,] "chocolate" ""     ""    
## [2,] "va"        "illa" ""    
## [3,] "ci"        ""     "amon"
## [4,] "mi"        "t"    ""    
## [5,] "lemo"      ""     ""