String(문자열)
string을 다루는 데 익숙해지는 것은 꽤나 많은 시간을 필요로 하고 난이도도 있다.
Exercise를 풀어보면서 익히는 것이 좋아보인다.
library(tidyverse)
x <- c('\'','\\')
writeLines(x)
특수문자를 표시하는 경우에는 \를 사용해준다.
x <- '\u00b5'
x
요런 숨은 문자를 사용하는 코드도 있다. 그 외에
- \n : 엔터를 치겠다.
- \t : 간격을 띄우겠다.
- 즉, \는 특정한 명령을 위한 커맨드라고 보면 된다.
- ?'"' <-을 통해 다양한 명령어를 확인할 수 있다.
- str_lenght()
str_length(c('a', 'R for data science', NA))
str_length()는 string별 길이를 반환해준다. NA는 당연히 NA를 반환한다.
- str_c()
문자열을 합쳐보자.
str_c("x","y")
"xy"
str_c("x","y","z")
"xyz"
str_c("x","y", sep = ", ")
"x, y"
매우 쉬우니 빠르게 넘어가자.. 갈 길이 멀다.
x <- c("abc", NA)
str_c("|-", x, "-|")
"|-abc-|" NA
NA는 당연히 그냥 NA로 반환된다. 하지만 NA에도 같은 패턴을 입히고 싶을 수 있다. 그럴 땐
- str_replace_na()
str_c("|-",str_replace_na(x), "-|")
"|-abc-|" "|-NA-|"
str_replace_na()는 replacement 인자를 갖는데 default 값이 string type의 "NA"이다.
str_c()는 벡터연산이 적용된다. 뭔 말인지 모르겠으면 코드로 보자.
str_c(rep('prefix-',3), c('a','b','c'), rep('-suffix',3))
rep()함수로 prefix를 3번 반복해서 c('a', 'b', 'c')와 연산이 되게끔 만들었다. 뒤에 -suffix도 마찬가지다.
그 결과는
"prefix-a-suffix" "prefix-b-suffix" "prefix-c-suffix"
하지만 이렇게 rep()함수를 사용할 필요가 없다는 것이다.
str_c("prefix-", c("a", "b", "c"), "-suffix")
"prefix-a-suffix" "prefix-b-suffix" "prefix-c-suffix"
같은 값을 반환한다. 이해 오케이?!
vector를 단일 string으로 축소해보자.
str_c("x","y","z"))
"x" "y" "z"
str_c(c("x","y","z"), collapse = "")
"xyz"
str_c(c("x", "y", "z"), collapse = ", ")
"x, y, z"
str_c()가 사용되는 예시에 대해서 차이를 느껴보자.
- str_sub()
x <- c("Apple", "Banana", "Pear")
str_sub(x, 1, 3)
"App" "Ban" "Pea"
x에서 첫번째에서 세번째 문자까지만 뽑기.
str_sub(x, -3, -1)
"ple" "ana" "ear"
뒤에서 3번문자부터 뒤에서 1번문짜가지 뽑기.
우리는 strings을 수정하기 위해서 str_sub()를 사용할 수 있다. 어떻게 사용하는지는 코드를 보자.
x
"Apple" "Banana" "Pear"
str_sub(x, 1, 1)
첫번째 문자만 뽑기
str_to_lower(str_sub(x, 1, 1))
"apple" "banana" "pear"
- exercise
- In code that doesn’t use stringr, you’ll often see paste() and paste0(). What’s the difference between the two functions? What stringr function are they equivalent to? How do the functions differ in their handling of NA?
paste()와 paste0() 중 str_c()와 비슷한 함수는 무엇이며 NA값에 대해서 어떻게 다르게 적용되는지 확인해보자.
paste("foo", "bar")
paste0("foo", "bar")
"foo bar" : paste()는 기본적으로 string을 공백으로 구분하여 반환해준다.
"foobar" : paste)()는 공백없이 반환해준다.
str_c("foo", "bar")
"foobar" : str_c()도 공백없이 반환하기 때문에 str_c와 비슷한 함수는 paste0()라고 할 수 있겠다.
또 NA에 대해서는 어떻게 처리할까?
paste("foo", NA)
paste0("foo", NA)
str_c('foo', NA)
x <- NA
str_c("foo", str_replace_na(x))
요러면
"fooNA " 를 반환할 것이다. (복습)!
- 가운데 chracter 뽑기
mystring <- 'abcdefg'
mid <- (str_length(mystring)+1)/2
str_sub(mystring, mid, mid)
-str_trim()은 무엇을 하는가?
str_trim(' a ')
'a'
를 반환한다. 공백을 제거해주는 함수.
str_trim(' a ', side = 'left')
side를 인자를 쓰면
'a ' 요런식으로 반환이 된다.
- Write a function that turns (e.g.) a vector c(“a”, “b”, “c”) into the string a, b, and c. Think carefully about what it should do if given a vector of length 0, 1, or 2.
벡터 c("a", "b", "c")를 a, b, and c로 바꾸는 함수를 써보자. vector의 길이가 0, 1, 2인 경우에 대비해 주의하자.
vector_to_string <- function(v) {
n <- length(v)
if(n == 0) {
return("")
} else if(n == 1) {
return(v[1])
} else if(n == 2) {
return(paste(v[1], "and", v[2]))
} else {
main_part <- paste(v[-n], collapse = ", ")
last_part <- paste(", and", v[n])
return(paste(main_part, last_part, sep=""))
}
}
a <- c('a','b','c','d','e')
vector_to_string(a)
[1] "a, b, c, d, and e"
- str_view()
이제 regular expression을 알아보자. str_view(), str_view_all()과 함께 사용할 수 있다. 앞에 함수들은 character와 regular expression이 어떻게 매칭되는지 보여준다.
코드로 한 가지 예시를 들어보겠다.
x <- c("apple", "banana", "pear")
str_view(x, 'an')
이제 다양한 regular expressions을 알아보자.
- .
.은 모든 문자, any character를 의미한다.
뭔 말인지 모르겠으면 코드를 보자.
str_view(x, '.a.')
a라는 문자 앞뒤로 어떠한 문자 하나가 있으면 패턴으로 인식하고 반환한다.
때문에 apple은 a뒤에는 문자가 있지만 앞에 없기 때문에 반환하지 않는다.
- ^, $
'^a' : a로 시작하는 것
'a$' : a로 끝나는 것
x <- c("apple", "banana", "pear")
str_view(x, '^a')
a로 시작하는 것 apple밖에 없다.
x <- c("apple pie", "apple", "apple cake")
str_view(x, "apple")
이런 상황에서 apple만을 찾고 싶은 경우가 있다.
x <- c("apple pie", "apple", "apple cake")
str_view(x, "^apple$")
요러면 apple만 반환하겠지?
- exercise
stringr::words
stringr 패키지의 words dataset에서 regular expression을 사용해 특정 패턴을 가진 단어를 모두 찾아보자.
- Start with 'y'
- End with 'x'
- Are exactly three letters long.
- Have seven letters or more.
str_view(a, '^y')
str_view(a, 'x$')
str_view(a, '^...$')
str_view(a, '.......')
- \d, \s
\d : matches any digit(숫자)
\s : matches any whitespace (space, tab, newline)
'[abc]' : matches a, b, or c
'[^abc]' : matches anything except a, b, or c
\d , \s를 포함한 regular expression을 사용하려면 string에서 escape하기 위해서 \\d, \\s로 써야한다고 한다.
예제를 통해 사용해보자.
str_view(c("abc", "a.c", "a*c", "a c"), "a[.]c")
[]안에 들어간 . 은 진짜 .으로 인식한다.
<a.c>
str_view(c("abc", "a.c", "a*c", "a c"), ".[*]c")
<a*c>
str_view(c("abc", "a.c", "a*c", "a c"), "a[ ]")
<a >c
str_view(c('grey', 'gray'), 'gr[ea]y')
## [1] │ <grey>
## [2] │ <gray>
str_view(c('grey','gray'), 'gr[^e]y')
## [2] │ <gray>
str_view(c('grey', 'gray'), 'gr(e|a)y')
## [1] │ <grey>
## [2] │ <gray>
str_view(c("abc", "deaf","gray","grey"), "abc|d..f")
## [1] │ <abc>
## [2] │ <deaf>
- Exercises
1. start with a vowel(모음) aeiou
str_view(words, ^[aeiou])
2. End with ed, but not with eed.
str_view(words, '[^e]ed$')
3. End with ing or ise.
str_view(words, '(ing|ise)$')
4. Is "q" always followed by a 'u'?
str_view(words, 'q[^u]')
- ?, +, *
? : 0 or 1
+ : 1 or more
* : 0 or more
x <- "1888 is the longest year in Roman numerals: MDCCCLXXXVIII"
str_view(x, 'CC?')
## [1] │ 1888 is the longest year in Roman numerals: MD<CC><C>LXXXVIII
str_view(x, "LL?")
## [1] │ 1888 is the longest year in Roman numerals: MDCCC<L>XXXVIII
str_view(x, "CC+")
## [1] │ 1888 is the longest year in Roman numerals: MD<CCC>LXXXVIII
str_view(x, "LL+")
## [1]
str_view(x, 'C[LX]+')
## [1] │ 1888 is the longest year in Roman numerals: MDCC<CLXXX>VIII
str_view(x, 'C[XL]+')
## [1] │ 1888 is the longest year in Roman numerals: MDCC<CLXXX>VIII
- {n}, {n,}, {, m}, {n, m} | Repetiton
'{n}' : exactly n
'{n,}' : n or more
'{,m}' at most m
'{n,m}' : beween n and m
str_view(x, "C{2}")
## [1] │ 1888 is the longest year in Roman numerals: MD<CC>CLXXXVIII
str_view(x, "C{2,}")
## [1] │ 1888 is the longest year in Roman numerals: MD<CCC>LXXXVIII
str_view(x, "C{2,3}")
## [1] │ 1888 is the longest year in Roman numerals: MD<CCC>LXXXVIII
- Exercises
-?, +, *을 "{m,n}" 형식으로 설명해보자.
?, +, *을 "{m,n}" 형식으로 설명해보자.
? <- {0,1}
+ <- {1,}
* <- {0,}
"^.*$" - > 모든 단어 다고를듯?
"\{.+\}" - > \{아무문자 1개이상 \}
"\d{4}-\d{2}-\d{2}" - > 숫자4개-숫자2개-숫자2개
Create regular expressions to find all words that:
- start with three consonants(자음)
str_view(words, '^[^aeiou]{3}')
- Have three or more vowels in a row.
str_view(words, '[aeiou]{3,}')
- Have two or more vowel-consonant pairs in a row.
str_view(words, '([aeiou][^aeiou]){2,}')
- (...)
괄호는 괄호안에 정규 표현식의 부분과 일치하는 문자열을 저장한다. \1,\2 같은 이름으로 이전의 (..)과 일치하는 동일한 텍스트를 찾을 수 있다. 뭔 말인지 모르겠으면 코드를 보자.
str_view(fruit, "(..)\\1", match = TRUE)
(..) <- 아무 문자 두개 ab, cd, fg,... 즉 두개의 문자가 연속으로 두번있는 단어를 찾는거다.
an이니까 anan -> banana 요런식..!
str_view(fruit, "(.)(.)\\2\\1", match = TRUE)
bell p<eppe>r
chili p<eppe>r
str_view(fruit, "(.).\\1.\\1", match = TRUE)
## [4] │ b<anana>
## [56] │ p<apaya>
-Exercise
Construct regular expressions to match words that:
- Start and end with the same character.
같은글짜로 시작하고 끝나는 단어를 찾아보자.
str_view(words, "^(.).*\\1$", match = TRUE)
- Contain a repeated pair of letters (e.g 'church' contains 'ch' repeated twice.)
한 쌍의 문자 두 번 반복 반복
str_view(words,"(..).*\\1")
- Contain one letter repeated in at least three places(e.g. 'eleven' contains three 'e's.)
한 문자가 적어도 3번이상 존재. eleven처럼.
str_view(words, '(.).*\\1.*\\1', match = TRUE)
-str_detect()
chracter vector가 pattern과 매칭이 되는지 확인하고 싶다면 str_detect()함수를 사용하면 된다.
x <- x('apple', 'banana', 'pear')
str_detect(x,'e')
TRUE FALSE TRUE
- How many common words starts with t?
t로 시작하는 단어가 몇 개인지 확인해보자.
sum(str_detect(words, '^t'))
65
65개 확인.
- What proportion of common words end with a vowel?
모음으로 끝나는 단어의 비율이 얼마나 되는지도 확인해보자. 모음은 aeuiou가 있따.
mean(str_detect(words, '[aeiou]$'))
0.2765306
-str_subset()
패턴과 일치하는 단어를 뽑아내기 위해서
words[str_detect(words, 'x$')]
요런식으로 boolean값을 넣는데, 이런 방법말고 str_subset()함수를 사용하면 된다.
str_subset(words, 'x$')
df <- tibble(
word = words,
i = seq_along(word)
)
df %>%
filter(str_detect(word, 'x$'))
## # A tibble: 4 × 2
## word i
## <chr> <int>
## 1 box 108
## 2 sex 747
## 3 six 772
## 4 tax 841
-str_count()
str_count는 str_detect의 변형 함수이다. 문자열에 매칭되는 문자가 몇 개가 있는지 알려준다.
x <- c('apple', 'banana', 'pear')
str_count(x, 'a')
1 3 1
word 데이터에서 평균적으로 단어당 모음이 몇개 존재하는지 알아보자.
mean(str_count(words, '[aeiou]'))
## [1] 1.991837
2개 정도 존재한다.
df 데이터에 단어의 모음의 개수, 자음의 개수를 추가해보자.
df %>%
mutate(
vowels = str_count(word, '[aeiou]'),
consonants = str_count(word, '[^aeiou]')
)
- str matchs never overlap
str_count("abababa", "aba")
## [1] 2
어떤 걸 매칭한 것인지는 str_view_all()함수로 확인할 수 있다.
str_view_all("abababa", "aba")
## [1] │ <aba>b<aba>
가운데있는 aba는 중복으로 인지해 match으로 보지 않는다.
- exercise
- Find all words that start or end with x.
x로 시작하거나 끝나는 모든 단어를 찾아라.
words[str_detect(words, "^x") | str_detect(words, "x$")]
- Find all words that start with a vowel and end of each different vowel?
모음으로 시작하고 자음으로 끝나는 모든 단어를 찾자.
words[str_detect(words, '^[aeiou]') & str_detect(words, '[^aeiou]$')]
- Are there any words that contain at least one of each different vowel?
각각의 다른 모음을 모두 적어도 하나를 포함하는 단어가 있는지 확인하자.
words[str_detect(words, 'a') & str_detect(words, 'e') &
str_detect(words, 'i') & str_detect(words, 'o') &
str_detect(words, 'u')]
결과는 하나도 없당..
What word has the highest number of vowels? What word has the highest proportion of vowels? (Hint: what is the denominator?)
모음 수가 가장 많은 단어는 무엇인가? 모음의 비율이 가장 높은 단어는 무엇인가 ?
모음 수가 가장 많은 단어.
max(str_count(words, '[aeiou]'))
max(str_count(words, '[aeiou]')/str_length(words))
-str_extract()
일치하는 내용이 있을 때, 내용에서 텍스트를 추출할 때 사용하는 함수 str_extract()이다.
colours <- c("red", "orange", "yellow", "green", "blue", "purple")
colour_match <- str_c(colours, collapse = "|")
colour_match
## [1] "red|orange|yellow|green|blue|purple"
has_colour <- str_subset(sentences, colour_match)
matches <- str_extract(has_colour, colour_match)
head(matches)
"blue" "blue" "red" "red" "red" "blue"
more <- sentences[str_count(sentences, colour_match) > 1]
str_view_all(more, colour_match)
## [1] │ It is hard to erase <blue> or <red> ink.
## [2] │ The <green> light in the brown box flicke<red>.
## [3] │ The sky in the west is tinged with <orange> <red>.
str_extract_all(more, colour_match)
## [[1]]
## [1] "blue" "red"
##
## [[2]]
## [1] "green" "red"
##
## [[3]]
## [1] "orange" "red"
str_extract_all()함수에서 simplify 인자를 사용하면 결과를 행렬로 반환 받을 수 있다.
str_extract_all(more, colour_match, simplify = TRUE)
## [,1] [,2]
## [1,] "blue" "red"
## [2,] "green" "red"
## [3,] "orange" "red"
x <- c("a", "a b", "a b c")
str_extract_all(x, "[a-z]", simplify = TRUE)
## [,1] [,2] [,3]
## [1,] "a" "" ""
## [2,] "a" "b" ""
## [3,] "a" "b" "c"
이전의 예에서 flickered가 red와 매칭된 것을 확인할 수 있다. 이는 오류이며, 이 문제를 해결하는 정규 표현식 짜보자.
str_view(sentences, '[^a-z]red[^a-z]' )
sentences data에 str_extract()함수를 사용하여 ing로 끝나는 모든 단어를 extract해보자.
str_extract(sentences, '[a-zA-Z]+ing[^a-z]') %>%
str_trim()
- str_replace()
x <- c('apple', 'pear', 'banana')
str_replace(x, '[aeiou]','-')
"-pple" "p-ar" "b-nana"
str_replace_all(x, "[aeiou]", "-")
"-ppl-" "p--r" "b-n-n-"
x <- c("1 house", "2 cars", "3 people")
str_replace_all(x, c("1" = "one", "2" = "two", "3" = "three"))
"one house" "two cars" "three people"
sentences %>%
str_replace("([^ ]+) ([^ ]+) ([^ ]+)", "\\1 \\3 \\2") %>%
head(5)
## [1] "The canoe birch slid on the smooth planks."
## [2] "Glue sheet the to the dark blue background."
## [3] "It's to easy tell the depth of a well."
## [4] "These a days chicken leg is a rare dish."
## [5] "Rice often is served in round bowls."
요런식으로 단어의 순서를 바꿀 수 있다.
-exercise
- Switch the first and last letters in words. Which of those strings are still words?
단어의 첫문자와 마지막문자를 위치를 바꿨을 때 어떤 문자열이 여전히 단어인지 보자.
replaced <- str_replace(words, "^(.)(.*)(.)$", '\\3\\2\\1')
replaced[is.element(replaced, words)]
- str_split()
문자열을 split내보자.
sentences %>%
head(5) %>%
str_split(" ")
## [[1]]
## [1] "The" "birch" "canoe" "slid" "on" "the" "smooth"
## [8] "planks."
##
## [[2]]
## [1] "Glue" "the" "sheet" "to" "the"
## [6] "dark" "blue" "background."
##
## [[3]]
## [1] "It's" "easy" "to" "tell" "the" "depth" "of" "a" "well."
##
## [[4]]
## [1] "These" "days" "a" "chicken" "leg" "is" "a"
## [8] "rare" "dish."
##
## [[5]]
## [1] "Rice" "is" "often" "served" "in" "round" "bowls."
"a|b|c|d" %>%
str_split("\\|")
## [[1]]
## [1] "a" "b" "c" "d"
str_split에도 행렬로 반환하는 인자 simplify가 있다.
sentences %>%
head(5) %>%
str_split(" ", simplify = TRUE)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,] "The" "birch" "canoe" "slid" "on" "the" "smooth" "planks."
## [2,] "Glue" "the" "sheet" "to" "the" "dark" "blue" "background."
## [3,] "It's" "easy" "to" "tell" "the" "depth" "of" "a"
## [4,] "These" "days" "a" "chicken" "leg" "is" "a" "rare"
## [5,] "Rice" "is" "often" "served" "in" "round" "bowls." ""
## [,9]
## [1,] ""
## [2,] ""
## [3,] "well."
## [4,] "dish."
## [5,] ""
x <- c('appels pears,and bananas')
x %>% str_split(
'(, and )|, ')
# Not!
x %>% str_split(
',|(, and)') # 앞에꺼만 찾는다.
'R > Exploratory data analysis' 카테고리의 다른 글
R for Data Science:: datetime (0) | 2023.06.16 |
---|---|
R for Data Science:: Relational data (0) | 2023.06.10 |
R for Data Science:: tidy data (1) | 2023.06.09 |
R for Data Science::tibbles and data import (0) | 2023.06.08 |
R for Data Science::transformation 3 ; Exercise 5.7 (1) | 2023.06.08 |