패키지 stringr 아주 편리한 문자열 도구
R 사용자들의 가장 큰 불만 중의 하나는...?
아마 상당히 불편한 character 데이터 처리 방법이라고 생각합니다.
문자열을 가지고 흔히 하는 일을 생각해봅시다.
아마 상당히 불편한 character 데이터 처리 방법이라고 생각합니다.
문자열을 가지고 흔히 하는 일을 생각해봅시다.
- 문자열 합치고 나누기
- 문자열의 어떤 부분을 추출하기
- 분자열의 일부를 바꾸기
- 빈 문자들(white space) 지우기
- 공백 문자 채우기
이외에도
- 정규식을 적용하여 어떤 패턴이 있나 확인하기
- 정규식을 적용하여 어떤 패턴에 해당되는 부분 추출하기
정도는 해줘야 하지요.
R의 {base}는 sub(), gsub(), regex() 등의 함수를 제공합니다만... 너무 느리고 사용이 어렵습니다. 우리의 구세주는 Rice University 통계학과의 Hadley Wickham 교수입니다. 그가 개발한 {stringr}은 빠르고 간편합니다. 이제 구체적인 사례들을 생각하며 {stringr}을 배워봅시다.
경우에 따른 stringr 함수들
문자열 관련
- str_c(): 합치기
- str_count(): 세어 보기
- str_dup(): 반복해서 덧붙이기
- str_length(): 문자 길이
- str_pad(): 빈 문자 속에 끼우기
- str_split(): 나누기
- str_split_fixed(): 고정해서 나누기
- str_trim(): 빈문자들 제거
- str_sub(): 시작과 끝 위치에 해당되는 부분 끊어오기
- word(): 단어 추출
패턴 추출
- str_detect(): 패턴 있나 검사
- str_extract(): 패턴에 해당되는 것 추출
- str_extract_all(): 패턴에 해당되는 것 모두 추출해서 list로 반환
- str_locate(): 패턴의 위치 추출
- str_locate_all(): 패턴의 위치 모두 추출해서 list로 반환
- str_match(): 해당되는 그룹 패턴 추출
- str_replace(): 패턴에 해당되는 부분 교체
- str_replace_all(): 패턴에 해당되는 부분 모두 교체
패턴
- fixed(): 정규식 패턴 무시하기
- ignore_case(): 패턴에 대소문자 무시하기
- perl(): POSIX 정규식 대신 Perl의 정규식 표현 쓰기
연습 과제
백문이 불여일타.
다음 과제들을 많이 연습해서 함수들의 사용법을 익혀 봅시다.
함수: fixed
인자: string
설명: 정규식을 사용하지 않은 고정된 패턴, 속도 높이는 효과
> pattern <- "a.b"
> strings <- c("abc","a.b")
> str_detect(strings,pattern)
[1] FALSE TRUE
> str_detect(strings, fixed(pattern))
[1] FALSE TRUE
함수: ignore.case
인자: string
설명: 패턴을 matching할 때 대소문자 구분을 하지 않도록 함
> str_detect(strings, ignore.case(pattern))
[1] FALSE TRUE
함수: perl
인자: 펄정규식
설명: 펄 정규식을 사용할 수 있도록 한다.
> pattern <- "(?x)a.b"
> strings <- c("abb","a.b")
> str_detect(strings,perl(pattern))
[1] TRUE TRUE
>
함수: str_c
인자: 연결할 문자 벡터들
sep: 연결하는 문자 벡터들 사이를 이어준다.
collapse: 연결한 다음 한 문자열로 합칠 때 삽입할 문자
설명: 벡터 연산을 하여 문자들을 연결시킨다.
> str_c("Letter: ",letters)
[1] "Letter: a" "Letter: b" "Letter: c" "Letter: d" "Letter: e" "Letter: f" "Letter: g"
[8] "Letter: h" "Letter: i" "Letter: j" "Letter: k" "Letter: l" "Letter: m" "Letter: n"
[15] "Letter: o" "Letter: p" "Letter: q" "Letter: r" "Letter: s" "Letter: t" "Letter: u"
[22] "Letter: v" "Letter: w" "Letter: x" "Letter: y" "Letter: z"
> str_c(letters, " is for", "...")
[1] "a is for..." "b is for..." "c is for..." "d is for..." "e is for..." "f is for..."
[7] "g is for..." "h is for..." "i is for..." "j is for..." "k is for..." "l is for..."
[13] "m is for..." "n is for..." "o is for..." "p is for..." "q is for..." "r is for..."
[19] "s is for..." "t is for..." "u is for..." "v is for..." "w is for..." "x is for..."
[25] "y is for..." "z is for..."
> str_c("Letter", letters, sep = ": ")
[1] "Letter: a" "Letter: b" "Letter: c" "Letter: d" "Letter: e" "Letter: f" "Letter:
...
> str_c(letters, collapse = ", ")
[1] "a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z"
함수: str_count()
인자: string: 문자열
pattern: 패턴
설명: 패턴이 몇 개 일치하나 숫자를 반환
> fruit <- c("apple", "banana", "pear", "pineapple")
> str_count(fruit, "a")
[1] 1 3 1 1
# 각 문자 벡터에서 일치하는 것의 수를 반환
> str_count(fruit, "p")
[1] 2 0 1 3
> str_count(fruit, "e")
[1] 1 0 1 2
> str_count(fruit, c("a", "b", "p", "p"))
[1] 1 1 1 3
함수: str_detect
인자: string, pattern
설명: 패턴이 존재하면 TRUE, 아니면 FALSE
> fruit <- c("apple", "banana", "pear", "pinapple")
> str_detect(fruit, "a")
[1] TRUE TRUE TRUE TRUE
> str_detect(fruit, "^a")
[1] TRUE FALSE FALSE FALSE
> str_detect(fruit, "a$")
[1] FALSE TRUE FALSE FALSE
> str_detect(fruit, "b")
[1] FALSE TRUE FALSE FALSE
> str_detect(fruit, "[aeiou]")
[1] TRUE TRUE TRUE TRUE
함수: str_dup
인자: string, times
설명: times 벡터에 지정된 것만큼 원소를 반복해서 뒤에 붙인다.
> fruit <- c("apple", "pear", "banana")
> str_dup(fruit, 2)
[1] "appleapple" "pearpear" "bananabanana"
> str_dup(fruit, 1:3)
[1] "apple" "pearpear" "bananabananabanana"
> str_c("ba", str_dup("na", 0:5))
[1] "ba" "bana" "banana" "bananana" "banananana"
[6] "bananananana"
함수: str_extract
인자: string, pattern
설명: 일치하는 최초의 패턴을 뽑아 보여준다.
> str_extract(shopping_list, "\\d")
[1] "4" NA NA "2"
> str_extract(shopping_list, "[a-z]+")
[1] "apples" "flour" "sugar" "milk"
> str_extract(shopping_list, "[a-z]{1,4}")
[1] "appl" "flou" "suga" "milk"
> str_extract(shopping_list, "\\b[a-z]{1,4}\\b")
[1] NA NA NA "milk"
함수: str_extract_all
인자: string, pattern
설명: 일치하는 모든 경우를 다 뽑아 list 객체로 반환한다.
> shopping_list <- c("apples x4", "bag of flour", "bag of sugar", "milk x2")
> str_extract_all(shopping_list, "[a-z]+")
[[1]]
[1] "apples" "x"
[[2]]
[1] "bag" "of" "flour"
[[3]]
[1] "bag" "of" "sugar"
[[4]]
[1] "milk" "x"
> str_extract_all(shopping_list, "\\b[a-z]+\\b")
[[1]]
[1] "apples"
[[2]]
[1] "bag" "of" "flour"
[[3]]
[1] "bag" "of" "sugar"
[[4]]
[1] "milk"
> str_extract_all(shopping_list, "\\d")
[[1]]
[1] "4"
[[2]]
character(0)
[[3]]
character(0)
[[4]]
[1] "2"
함수: str_length
인자: string
설명: 벡터의 문자 길이를 반환한다.
> str_length(letters)
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
> str_length(c("i", "like", "programming", NA))
[1] 1 4 11 NA
함수: str_locate
인자: string, pattern
설명: pattern의 시작과 끝 위치를 반환한다.
> fruit <- c("apple", "banana", "pear", "pinapple")
> str_locate(fruit, "a")
start end
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
> str_locate(fruit, "an")
start end
[1,] NA NA
[2,] 2 3
[3,] NA NA
[4,] NA NA
> str_locate(fruit, "e")
start end
[1,] 5 5
[2,] NA NA
[3,] 2 2
[4,] 8 8
> str_locate(fruit, c("a", "b", "p", "p"))
start end
[1,] 1 1
[2,] 1 1
[3,] 1 1
[4,] 1 1
함수: str_locate_all
매치되는 것들의 전체 리스트를 반환한다.
함수: str_match
인자: string,pattern
설명: ()로 묶인 패턴 그룹을 뽑아 matrix 반환
> strings <- c(" 219 733 8965", "329-293-8753 ", "banana", "595 794 7569",
+ "387 287 6718", "apple", "233.398.9187 ", "482 952 3315",
+ "239 923 8115", "842 566 4692", "Work: 579-499-7527", "$1000",
+ "Home: 543.355.3679")
> phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"
> str_extract(strings, phone)
[1] "219 733 8965" "329-293-8753" NA "595 794 7569" "387 287 6718"
[6] NA "233.398.9187" "482 952 3315" "239 923 8115" "842 566 4692"
[11] "579-499-7527" NA "543.355.3679"
> str_match(strings, phone)
[,1] [,2] [,3] [,4]
[1,] "219 733 8965" "219" "733" "8965"
[2,] "329-293-8753" "329" "293" "8753"
[3,] NA NA NA NA
[4,] "595 794 7569" "595" "794" "7569"
[5,] "387 287 6718" "387" "287" "6718"
[6,] NA NA NA NA
[7,] "233.398.9187" "233" "398" "9187"
[8,] "482 952 3315" "482" "952" "3315"
[9,] "239 923 8115" "239" "923" "8115"
[10,] "842 566 4692" "842" "566" "4692"
[11,] "579-499-7527" "579" "499" "7527"
[12,] NA NA NA NA
[13,] "543.355.3679" "543" "355" "3679"
str_match_all()도 있다.
함수: str_pad
인자: string, width, side
side = c("left","right","both") 빈 칸의 기준 위치를 정함
설명: 빈 칸을 넣어서 적절히 배치한다.
> rbind(
+ str_pad("hadley", 30, "left"),
+ str_pad("hadley", 30, "right"),
+ str_pad("hadley", 30, "both")
+ )
[,1]
[1,] " hadley"
[2,] "hadley "
[3,] " hadley "
함수: str_replace, str_replace_all
인자: string, pattern, replace
설명: 정규식에 해당되는 부분을 replace로 치환한다.
> fruits <- c("one apple", "two pears", "three bananas")
> str_replace(fruits, "[aeiou]", "-")
[1] "-ne apple" "tw- pears" "thr-e bananas"
> str_replace_all(fruits, "[aeiou]", "-")
[1] "-n- -ppl-" "tw- p--rs" "thr-- b-n-n-s"
> str_replace(fruits, "([aeiou])", "")
[1] "ne apple" "tw pears" "thre bananas"
> str_replace(fruits, "([aeiou])", "\\1\\1")
[1] "oone apple" "twoo pears" "threee bananas"
함수: str_split
인자: string, pattern, n=Inf
몇 개의 split 파트를 반환하는가를 n으로 정해준다.
설명: 입력값은 문자열 벡터, 결과값은 list, 각 원소는
> fruits <- c(
+ "apples and oranges and pears and bananas",
+ "pineapples and mangos and guavas"
+ )
> str_split(fruits, " and ")
[[1]]
[1] "apples" "oranges" "pears" "bananas"
[[2]]
[1] "pineapples" "mangos" "guavas"
함수: str_split_fixed
설명: str_split과 마찬가지, 결과를 matrix로 뽑고 빈 곳은 ""로 채운다.
> fruits <- c(
+ "apples and oranges and pears and bananas",
+ "pineapples and mangos and guavas"
+ )
> str_split_fixed(fruits, " and ", 3)
[,1] [,2] [,3]
[1,] "apples" "oranges" "pears and bananas"
[2,] "pineapples" "mangos" "guavas"
> str_split_fixed(fruits, " and ", 4)
[,1] [,2] [,3] [,4]
[1,] "apples" "oranges" "pears" "bananas"
[2,] "pineapples" "mangos" "guavas" ""
함수: str_sub
인자: string, start=1L, end=-1L
설명: 문자열에서 start와 end로 끊어온다.
> hw <- "Hadley Wickham"
> str_sub(hw, 1, 6)
[1] "Hadley"
> str_sub(hw, end = 6)
[1] "Hadley"
> str_sub(hw, 8, 14)
[1] "Wickham"
> str_sub(hw, 8)
[1] "Wickham"
> str_sub(hw, c(1, 8), c(6, 14))
[1] "Hadley" "Wickham"
> str_sub(hw, -1)
[1] "m"
# 뒤에서부터 따온다.
> str_sub(hw, -7)
[1] "Wickham"
# 뒤에서 7개
> str_sub(hw, end = -7)
[1] "Hadley W"
# 처음부터 뒤에서 7번째 땡겨온 것만큼 뽑는다.
> x <- "BBCDEF"
# 해당되는 부분을 치환할 수 있다.
> str_sub(x, 1, 1) <- "A"; x
[1] "ABCDEF"
> str_sub(x, -1, -1) <- "K"; x
[1] "ABCDEK"
> str_sub(x, -2, -2) <- "GHIJ"; x
[1] "ABCDGHIJK"
> str_sub(x, 2, -2) <- ""; x
[1] "AK"
함수: str_trim
인자: string, side = c("left","right","both")
기본값은 both
> str_trim(" String with trailing and leading white space\t")
[1] "String with trailing and leading white space"
> str_trim("\n\nString with trailing and leading white space\n\n")
[1] "String with trailing and leading white space"
함수: word
인자: string, start=1L, end=start, sep=fixed(" ")
설명: 단어를 뽑는다.
start와 end는 단어의 순서를 알려준다.
end가 -1이면 뒷 첫 번째.
recycling rule이 적용된다.
> sentences <- c("Jane saw a cat", "Jane sat down")
> word(sentences, 1)
[1] "Jane" "Jane"
> word(sentences, 2)
[1] "saw" "sat"
> word(sentences, -1)
[1] "cat" "down"
> word(sentences, 2, -1)
[1] "saw a cat" "sat down"
> # Also vectorised over start and end
> word(sentences[1], 1:3, -1)
[1] "Jane saw a cat" "saw a cat" "a cat"
> word(sentences[1], 1, 1:4)
[1] "Jane" "Jane saw" "Jane saw a" "Jane saw a cat"
정규표현식에 관하여 궁금한 점이 많을 것 같습니다.
자세한 사항은 "정규 표현식"이나 regular expression으로 구글링 하세요. ㅋㅋㅋㅋ
자세한 사항은 "정규 표현식"이나 regular expression으로 구글링 하세요. ㅋㅋㅋㅋ
댓글
댓글 쓰기