텍스트 처리 함수
Another widely used data structure for data analyzing
텍스트 처리 함수
- toupper() #안에: vector
tolower()
- nchar() #문자열또는 문자열 vector만 들어감
- 문자열의 길이 알려준다
- mean함수에 적용 시 평균 어휘길이 찾을 수 있다
- Factor은 nchar함수 적용 불가능 하다
텍스트 가독성 (readability)
텍스트 수준 평가 기준 (몇학년정도) ex: Lexile
연습문제 2
#make Freq with 03_WhatIsR.txt > head(Freq) Freq Length and 27 3 of 18 2 the 17 3 is 14 2 r 14 1 a 13 1
- 소문자 변환
- 빈도표 빈도 내림차순
- 빈도표 데이터프레임으로 변환
- 행제목의 각 어휘에 대한 어휘길이 새로운 열로 추가
- 열제목 : Freq, Length
답:
> TEXT <- tolower(TEXT) #1 > Freq <- sort(table(TEXT), decreasing = T) #2 > Freq <- data.frame(row.names= names(Freq), Freq = as.vector(Freq), Length = nchar(names(Freq))) #3, 4, 5
문자열 연결
- paste 함수: 각자 다른 애들을 하나의 문자열로 연결
> paste( 1,2,3,4,5 ) [1] "1 2 3 4 5" > paste("a", "b", "c", "d", "e") [1] "a b c d e" > paste("a", 1, 2, "d", 3) [1] "a 1 2 d 3"
- paste는 데이터 구조 가리지 않는다
> paste( "a", 1:5 )
[1] "a 1" "a 2" "a 3" "a 4" "a 5"
> paste("a", "b", 1:5)
[1] "a b 1" "a b 2" "a b 3" "a b 4" "a b 5"
> paste( c("a", "b"), 1:5 ) #교차 pasting
[1] "a 1" "b 2" "a 3" "b 4" "a 5"
> paste(1:12, month.abb)
[1] "1 Jan" "2 Feb" "3 Mar" "4 Apr" "5 May" "6 Jun" "7 Jul" "8 Aug" "9 Sep" "10 Oct" "11 Nov" "12 Dec"
함수 paste: sep 이용
> paste( "I", "dont", "know", sep = "") [1] "Idontknow" > paste( "I", "dont", "know", sep = " ") [1] "I dont know" > paste( "I", "dont", "know", sep = "\t") [1] "I\tdont\tknow" > paste( "I", "dont", "know", sep = "\n") [1] "I\ndont\nknow"
- COLLAPSE
> String <- paste(Sample, collapse = " ") > String [1] "What is R? Introduction to R R is a language and.." > length(String) [1] 1
- sep: 서로 다른 논항을 연결할 때 사용
- sep 미존재 시 : “ “ <- default
- collapse:
> paste( "a", "b", "c", sep= ":" ) [1] "a:b:c" > paste( "a", "b", "c", 1:3, sep= ":" ) [1] "a:b:c:1" "a:b:c:2" "a:b:c:3" > paste( "a", "b", "c", collapse = ";" ) #효과X, "a b c"가 하나기 떄문에...????뭐래는거야 [1] "a b c" > paste( "a", "b", "c", collapse = ";" , sep=":" ) #효과X [1] "a:b:c" > paste( "a", "b", "c", 1:3, collapse = ";" , sep=":" ) [1] "a:b:c:1;a:b:c:2;a:b:c:3"
N-Gram 만들기
> bi.gram <- paste(Sample[1:(length(Sample)-1)], Sample[2:length(Sample)], sep = " " )
# [1] "What is" "is R?"
# [3] "R? Introduction" "Introduction to"
# [5] "to R" "R a"
- 1 ~ n-1 : 2 ~ n 이렇게 만들기
trigram
도 같은 원리로 작성
문자열 분리: strsplit, unlist
- a = “I do not know”
> strsplit(a, " ") #두번째 인자 기준
[[1]]
[1] "I" "do" "not" "know"
> strsplit(a, "" )
[[1]]
[1] "I" " " "d" "o" " " "n" "o" "t" " " "k"
[11] "n" "o" "w"
- list 로 출력한다
> b <- c( "하나 둘 셋", "넷 다섯 여섯"); b;
[1] "하나 둘 셋" "넷 다섯 여섯"
> strsplit(b, " " )
[[1]]
[1] "하나" "둘" "셋"
[[2]]
[1] "넷" "다섯" "여섯"
> unlist( strsplit(b, " "))
[1] "하나" "둘" "셋" "넷" "다섯" "여섯"
함수 substr, substring
- R에서 문자열 indexing 안됨 => substring 사용
> a <- c( 'apple', 'banana', 'orange')
> substr(a, 2, 5)
[1] "pple" "anan" "rana"
> substring(a, 2, 5)
[1] "pple" "anan" "rana"
> substr(a, 2, 10)
[1] "pple" "anana" "range"
> substring(a, 2, 10)
[1] "pple" "anana" "range"
> substr(a, 2)
ERROR...
> substring(a, 2)
[1] "pple" "anana" "range"
- substring(a, 시작위치, 끝위치) 중 끝 위치보다 적으면 그냥 있는대까지 출력
substr()
은 반드시 3가지 인자substring()
은 마지막 인자 생략 시 끝까지인것으로 간주- 응용문제
> substr(a, 1, 1) <- toupper(substr(a, 1, 1)); a; [1] "Apple" "Banana" "Orange"
연습문제
whatisR 소문자로 변환 뒤 어휘문자열의 마지막 알파벳 또는 문장부호만 추출, 빈도 내림차순의 빈도표 Final 산출
> Final <- substring( tolower(TEXT), nchar(TEXT)) > Final <- sort(table(Final), decreasing = T) > Final Final e s d n r , t . a f y h l o g c ) w k m u " ? + x 79 69 46 45 41 33 29 22 19 19 18 15 15 9 7 4 3 3 2 2 2 1 1 1 1
정규표현 I
함수 grep : INDEX
- 정규표현 = 문자열 부분 일치
비교연산자 = 완전 일치
- a = “the first”, “the second”, “the third”
> grep( 찾고자하는String, SampleString ) > grep( "i", a ) [1] 1 3
-
index를 반환 - value = T 속성을 넣으면 index가 아닌, 값을 반환함
> grep( "i", a, value = T ) [1] "the first" "the third"
함수 grepl : T/F 값
> grepl("i", c("the first", "the second", "the third"))
[1] TRUE FALSE TRUE
-
TRUE, FALSE 반환 - 대괄호안에서 사용 가능(grep, grepl)
- value = T 속성 사용 불가능
함수 gsub : 문자열 치환 (바꾸기)
> gsub( 바꿀문자열, 목표문자열, 전체문자열)
> gsub( "the", "a", a ) # a 벡터안 문자열들 중 "the" -> "a"
[1] "a first" "a second" "a third"
문자열 시작과 끝
^x
: x로 시작하는 stringy$
: y로 끝나는 stringignore.case = T > grep("^T", a, value= T, ignore.case = T) [1] "the first" "the second" "the third"
정규표현 or
a ← c (“gray”, “grey”, “grant” )
> grep ("ra|re", a, value = T)
[1] "gray" "grey" "grant"
- SPACE Matters
> unlist( strsplit( a, "th" ))
[1] "" "" "e first" "" "e second" "" "e " "ird"
> unlist( strsplit( a, "t|h" ))
[1] "" "" "e firs" "" "" "e second" "" "" "e " "" "ird"
연습문제 #1 : WhatIsR의 단어 중 ‘w’ 또는 ‘W”로 시작하거나 끝나는 문자열 추출
답안 (3가지 방법)
1. TEXT[ grep("^w|^W|w$|W$", TEXT)] 2. TEXT[ grepl("^w|w$", TEXT, ignore.case=T)] 3. grep("^w|w$", TEXT, ignore.case=T, value=T)
반복 문자 및 매칭 문자
정규표현 문자 | 의미 | 예 |
---|---|---|
* | 0 or 1 more time | ca*t = ct, cat, caat, caaaaaat, … |
+ | at least 1 time | ca+t = cat, caat, caaaaaat, … |
? | 0 or 1 time | ca?t = ct, cat |
. | _하나 들어감 | ca.t = caat, cabt; ca..t = caaat, caabt 등등 |
> a <- c( "ac", "abc", "abbc", "abbbc", "abbbbc")
1. grep( "ab*c", a, value= T )
[1] "ac" "abc" "abbc" "abbbc" "abbbbc"
2. grep( "ab+c", a, value = T )
[1] "abc" "abbc" "abbbc" "abbbbc"
3. grep( "ab?c", a, value = T )
[1] "ac" "abc"
4. grep( "ab.c", a, value = T )
[1] "abbc"
5. grep( "ab..c", a, value = T )
[1] "abbbc"
> a <- c( "uneasy", "unexpected", "unbiased", "uned" )
6. grep( "un.*ed", a, value= T)
[1] "unexpected" "unbiased" "uned"
7. grep( "un.?ed", a, value= T)
[1] "uned"
8. grep( "un.+ed", a, value= T)
[1] "unexpected" "unbiased"
- 연습문제 #2:
문자열 끝이 "ed" 또는 "e"인 경우 출력 && 문자열 중간에 '-' 포함
TEXT[ grep("^.+-.+(ed$|e$)", TEXT)]
또는grep("^.+-.+(ed$|e$)", TEXT, value = T)
문자 목록 중 하나 일치
- [kbp] = k,b,p 중 하나 일치
- [A-Z] / [a-z] / [a-zA-Z]
- [가-힣]
[^가] : [ ] 안에 있는 ‘^’는
not
임NOT 개념 제대로 이해하기
> a <- c("Korea", "대한민국", "ㄹ수록","ㄹㄹㄹ") > grep("[가-힣]", a, value=T) [1] "대한민국" "ㄹ수록" > grep("[^가-힣]", a, value=T) [1] "Korea" "ㄹ수록" "ㄹㄹㄹ" #이 char안에 하.나.도. 없어야 함
이스케이프 문자
- 정규표현 메타문자
- . $ * ? | ^ [] ()
문제:
> a <- c( '3.45', '10+4=14', '$15') > grep('.', a, value = T) [1] "3.45", "10+4=14", "$15" > grep('.++', a, value = T) Error > grep( '^$', a, value = T) character(0)
해결:
\\
또는[]
사용> grep( '\\.', a, value = T ) [1] "3.45" > grep( '[.]', a, value = T) [1] "3.45" > grep( '.+\\+', a, value = T ) [1] "10+4=14" > grep( '.+[.+]', a, value = T ) [1] "3.45" "10+4=14" > grep( '^\\$', a, value = T ) [1] "$15"
- 연습문제: 문장부호 (.?!) 기준으로 WhatIsR의 문장 추출 (총 23줄)
답
```R > sentences <- unlist(strsplit(paste(TEXT, collapse = " "), "[?.!]" )) ```
정규표현 II
반복 문자 및 매칭 문자
문자유형 | 설명 | 예 | |
---|---|---|---|
[:digit:] | 0 1 2 3 4 5 6 7 8 9 | ||
[:alpha:] | 자연언어 문자 | ||
[:upper:] | 대문자 | ||
[:lower:] | 소문자 | ||
[:punct:] | ! “ # $ % & ‘ ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ | |
[:space:] | 탭, 스페이스, 엔터 | ||
[:blank:] | 탭, 스페이스 | ||
[:alnum:] | 문자와 숫자 | ||
[:graph:] | 문자, 숫자, 문장부호 |
a <- c( "apple", "orange", " ", "\t", "\n", ";", "123", "123 apple")
1. grep("[[:space:]]", a, value = T )
[1] " " "\t" "\n" "123 apple"
2. grep("[^[:space:]]", a, value = T )
[1] "apple" "orange" ";" "123" "123 apple"
3. grep("[[:alpha:]]", a, value = T )
[1] "apple" "orange" "123 apple"
4. grep("[[:digit:]]", a, value = T )
[1] "123" "123 apple"
5. grep("[[:punct:]]", a, value = T )
[1] ";"
6. grep("[[:punct:][:digit:]]", a, value = T )
[1] ";", "123", "123 apple"
어휘 경계 \b
a <- c( "motor car", "car", "cartoon", "bicarbonate", " car", "car\n", "123car", "!car.")
#부분매칭
> grep( "car", a, value = T )
[1] "motor car" "car" "cartoon" "bicarbonate" " car"
[6] "car\n" "123car" "!car."
##car 앞 공백............???
> grep( "\\bcar", a, value = T )
[1] "motor car" "car" "cartoon" " car" "car\n" "!car."
##car 뒤 .....
> grep( "car\\b", a, value = T )
[1] "motor car" "car" " car" "car\n" "123car" "!car."
##
> grep( "\\bcar\\b", a, value = T )
[1] "motor car" "car" " car" "car\n" "!car."
##
> grep( "^car$", a, value = T )
[1] "car"
최소 매칭
문자 | 설명 |
---|---|
*? | * 와 같으나 문자열을 최소로 매치 |
+? | + 와 같으나 문자열을 최소로 매치 |
?? | ? 와 같으나 문자열을 최소로 매치 |
> b
[1] "<a href=\"in.html\">HERE</a><a href=\"out.html\">"
> gsub('href=".*"', "문자열", b)
[1] "<a 문자열>"
> gsub('href=".*?"', "문자열", b)
[1] "<a 문자열>HERE</a><a 문자열>"
> gsub('href=".+"', "문자열", b)
[1] "<a 문자열>"
> gsub('href=".+?"', "문자열", b)
[1] "<a 문자열>HERE</a><a 문자열>"
- 연습문제 #1
1. What Is R의 문장부호 제거 및 소문자 변환
2. 빈도표 내림차순 추출 및 데이터프레임 변환 (행명= 어휘)
3. 상대빈도 열 추가 뒤 파일 저장답:
> text <- gsub("[[:punct:]]", "", tolower(TEXT)) > text <- sort(table(text), decreasing = T) > text.Freq <- data.frame(row.names=names(text), Freq = as.vector(text)) > text.Freq<- data.frame(text.Freq, Rel.Freq = round(text.Freq$Freq/sum(text),3)) > write.table(text.Freq, file = "freq.txt", quote=F, sep="\t", col.names=NA)
기본적인 영문 텍스트 전처리 작업
- 대문자의 소문자 변환
- 모든 문장부호 및 숫자 제거
- 소유격
's
, 부정n't
,I'm
,you're
,you've
등 분리/제거 - 불용어 stop word 목록 제거
- 길이 2 또는 3 이하 어후 ㅣ제거 (약자, a, an, in, on..etc)
- the, in, what 등 기능어/문법어 (say, people) 등 텍스트 주제어가 될 가능성 적은 고빈도 어휘 제거
-
stemming :
walked
=>walk
와 같이 어미 제거 -
lemmatizing :
am, are, ...
=>be
와 같이 기본형 복원
* 기본일 뿐, 맹목적으로 따르지 않아야 한다 (절대적 기준은 존재하지 않으며, 관찰에 따라 가공 과정이 다르다)
- 연습문제 #2
1. 07_data01.txt 소문자 변환
2. 어휘 앞뒤 문장부호연쇄 제거
3. 빈도표 추출 후 빈도 내림차순 => dataframe 변환답:
> text <- tolower(TEXT) > TEXT <- gsub("^[[:punct:]]+|[[:punct:]]+$", "", text) > TEXT.tab <- sort(table(TEXT), decreasing = T) > Freq.text <- data.frame(row.names=names(TEXT.tab), Freq = as.vector(TEXT.tab))
워드클라우드 WordCloud
- 텍스트형 데이터 시각화
패키지 packages
- library같은, 특정 기능 (함수 집합) 제공 (ex: wordcloud)
#한번만 다운로드
install.packages('패키지명')
#사용 시 매번 불러오기
library(패키지명)
##wordcloud 사용 예시
wordcloud(rownames(Freq.text), Freq.text$Freq, #여기까지만 하면 흑백으로 출력
scale=c(3, 0.8), min.freq=2, max.words=90,
random.order=F, rot.per=0.4, color = brewer.pal(8, "Dark2"))
- WORDCLOUD 설명
> wordcloud( 단어들(텍스트형벡터), 수치형벡터, scale=(최대폰트사이즈, 가장작은 폰트사이즈), min.freq = 가장 작은 수치 max.words = 출력할 최대 단어들 random.order = F (빈도순으로 중간에 몰림) rot.per = 0.4 (세로로 출력하는 단어; 40%, 가로: 60%), colors = brewer.pal(최대색상들, "Dark2") #팔레트 종류중 하나 )
연습문제 #3
1. TEXT에 대해 bigram 생성
2. 빈도표 추출
3. 빈도표 데이터프레임 변환 (컬럼명: bigrams, Freq)답:
```R > bigram <- paste(TEXT[1:length(TEXT)-1], TEXT[2:length(TEXT)], sep=" ") > bigram.tab <- table(bigram) > bi.grams <- data.frame(bi.grams = rownames(bigram.tab), Freq = as.vector(bigram.tab)) ```
- 연습문제 #4
bi.grams 활용하여 wordcloud 만들기답:
> wordcloud( bi.grams$bi.grams, bi.grams$Freq, scale = c(3, 0.8), min.freq =2, max.words=90, random.order=F, rot.per = 0.4, color=brewer.pal(8, "Dark2"))