데이터 다운로드 링크: https://www.kaggle.com/PromptCloudHQ/imdb-data
# 데이터 불러오기
DATA=read.csv("C:\\R/IMDB-Movie-Data.csv")
Ch4. 문자열 데이터 다루기 1
이번에는 문자열 데이터를 처리하는 방법에 대해 다루겠습니다.
- 문자열을 다룰 때 기본적으로 숙지하고 있어야 하는 명령어는 다음과 같습니다.
- 문자열 대체 : gsub()
- 문자열 분리 : strsplit()
- 문자열 합치기 : paste()
- 문자열 추출 : substr()
- 텍스트마이닝 함수: Corpus() & tm_map(), & tdm()
# 문자열 추출
substr(DATA$Actors[1],1,5) # 첫번째 obs의 Actors변수에서 1 ~ 5번째에 해당하는 문자열 추출
## [1] "Chris"
# 문자열 붙이기
paste(DATA$Actors[1],"_",'A') # 첫번째 obs의 Actors변수에서 _ A 붙이기, 기본적으로 띄어쓰기르 구분
## [1] "Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana _ A"
paste(DATA$Actors[1],"_",'A',sep="") # 띄어쓰기 없이 붙이기
## [1] "Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana_A"
paste(DATA$Actors[1],"_","Example",sep="|") # |로 붙이기
## [1] "Chris Pratt, Vin Diesel, Bradley Cooper, Zoe Saldana|_|Example"
# 문자열 분리
# Character로 씌우는 이유는, strsplit변수는 무조건 character형태의 변수만 받기 때문입니다.
# Actors는 현재 Factor로 되어 있음.
strsplit(as.character(DATA$Actors[1]), split= ",")
## [[1]]
## [1] "Chris Pratt" " Vin Diesel" " Bradley Cooper" " Zoe Saldana"
# 문자열 대체
DATA$Genre2=gsub(","," ",DATA$Genre) # , 를 띄어쓰기로 대체
텍스트마이닝의 절차는 다음과 같습니다.
- 코퍼스(말뭉치) 생성
- TDM(문서 행렬) 생성
- 문자 처리(특수문자 제거, 조사 제거, 숫자 제거 등..)
- 문자열 변수 생성
Genre 변수 TextMining
- 특정 단어를 변수로 만들어, 분석에 사용하기 위함이 목적
- 이를 통해, 특정 단어가 포함되어 있는 데이터만 따로 추출하거나, 특정 단어가 많이 등장하였을 때 이것이 다른 무언가와 상관성이 있는지 분석을 할 수 있게 되기 때문입니다.
데이터 결합하기 명령어
- cbind : 행이 동일하고, 순서도 같을 때 옆으로(변수) 합치기
- rbind : 열이 동일하고, 순서도 같을 때 아래로(obs) 합치기
- merge : 열과 행이 다른 두 데이터 셋을 하나의 기준을 잡고 합치고자 할 때 사용
Description 변수 TextMining
- 단어의 중복 등장
- 조사, 동사, 명사 등 등장
- 중복등장 단어 처리 결정
- 1안 : 특정 단어가 문장에 포함되어 있냐 없냐로 표시 -> 0 , 1로 코딩 (0: 포함 x, 1: 포함 o)
- 2안 : 특정 단어가 문장에서 몇번 등장했나를 표시 -> 등장 빈도로 코딩
- 문자열 데이터 시각화
Genre 변수는 영화에 대한 장르를 나타냅니다. 하지만 모든 영화가 하나의 장르에만 해당되는 것이 아니라, 여러 장르에 해당되는 것을 알 수 있습니다. 이를 분석하기 위해서는 각 영화가 어느 장르에 해당되는지 나타내줄 수 있는 변수를 만들어야 합니다. 해당 변수를 만들기 위해서 텍스트 마이닝 기법을 적용시켜보도록 하겠습니다.
# 1단계, 코퍼스 생성
# 영어의 경우, 대문자와 소문자가 다른 글자로 인식되기 때문에 대문자를 소문자로 바꿔주는 작업이 필요
library(tm) # tm 패키지 설치 필요
CORPUS = Corpus(VectorSource(DATA$Genre2)) # 코퍼스 생성
CORPUS_TM = tm_map(CORPUS,removePunctuation) # 특수문자 제거 (특수문자는 없지만...)
CORPUS_TM = tm_map(CORPUS_TM, removeNumbers) # 숫자 제거 (숫자도 없지만...)
CORPUS_TM = tm_map(CORPUS_TM, tolower) # 알파벳 모두 소문자로 바꾸기
Corpus는 말뭉치라는 의미로, 텍스트 마이닝을 하기 전에 문자열 데이터를 정리하는 과정이라고 생각하시면 될 것 같습니다.
# 2단계, 문서행렬 생성
TDM=DocumentTermMatrix(CORPUS_TM) # 문서행렬 생성
inspect(TDM)
## <<DocumentTermMatrix (documents: 1000, terms: 20)>>
## Non-/sparse entries: 2555/17445
## Sparsity : 87%
## Maximal term length: 9
## Weighting : term frequency (tf)
## Sample :
## Terms
## Docs action adventure comedy crime drama horror mystery romance scifi
## 1 1 1 0 0 0 0 0 0 1
## 10 0 1 0 0 1 0 0 1 0
## 11 0 1 0 0 0 0 0 0 0
## 12 0 0 0 0 1 0 0 0 0
## 2 0 1 0 0 0 0 1 0 1
## 4 0 0 1 0 0 0 0 0 0
## 5 1 1 0 0 0 0 0 0 0
## 6 1 1 0 0 0 0 0 0 0
## 7 0 0 1 0 1 0 0 0 0
## 9 1 1 0 0 0 0 0 0 0
## Terms
## Docs thriller
## 1 0
## 10 0
## 11 0
## 12 0
## 2 0
## 4 0
## 5 0
## 6 0
## 7 0
## 9 0
TDM = as.data.frame(as.matrix(TDM)) # 문서행렬을 데이터프레임 형태로 만들어주기.
head(TDM)
## action adventure scifi mystery horror thriller animation comedy family
## 1 1 1 1 0 0 0 0 0 0
## 2 0 1 1 1 0 0 0 0 0
## 3 0 0 0 0 1 1 0 0 0
## 4 0 0 0 0 0 0 1 1 1
## 5 1 1 0 0 0 0 0 0 0
## 6 1 1 0 0 0 0 0 0 0
## fantasy drama music biography romance history crime western war musical
## 1 0 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0
## 3 0 0 0 0 0 0 0 0 0 0
## 4 0 0 0 0 0 0 0 0 0 0
## 5 1 0 0 0 0 0 0 0 0 0
## 6 1 0 0 0 0 0 0 0 0 0
## sport
## 1 0
## 2 0
## 3 0
## 4 0
## 5 0
## 6 0
문서행렬을 만드는 이유는 다음과 같은 이유입니다.
즉, 문자열 데이터를 가지고 통계적인 분석을 하기 위한 준비과정이라고 생각하시면 될 것 같습니다.
이런식으로 action 장르에 해당되면, 1이 표시되고 그렇지 않은 경우에는 0 으로 표시되게 됩니다. 만약 1000개의 영화중에서 action 영화만 뽑고 싶으면, action == 1이란 조건을 주면 될 것입니다.
# 3단계, 기존데이터와 결합하기
DATA_GENRE = cbind(DATA,TDM)
기존에 있는 데이터와, 장르 변수들로 구성된 데이터를 합쳐야 합니다. 합쳐야 할 두 데이터가 같은 행을 가지고 순서도 같다면, cbind(Column bind) 명령어를 쓰면 됩니다. 만약, 반대로 합쳐야 할 두 데이터가 같은 열을 가지고, 순서도 같은데, 행을 합쳐야 한다면 rbind(row bind) 명령어를 쓰면 됩니다.
Genre 변수를 통해 간단하게 다룰어봤다면, 이번에는 Description 변수를 통해 복습도 할겸 다루어보도록 하겠습니다. Description 변수는 Genre 변수와 비교했을 때, 다음의 차이점이 존재합니다.
처음 단계는 비슷합니다.
# 1단계
library(tm)
CORPUS=Corpus(VectorSource(DATA$Description))
CORPUS_TM = tm_map(CORPUS,stripWhitespace)
CORPUS_TM = tm_map(CORPUS_TM,removePunctuation)
CORPUS_TM = tm_map(CORPUS_TM, removeNumbers)
CORPUS_TM = tm_map(CORPUS_TM, tolower)
DTM = DocumentTermMatrix(CORPUS_TM)
inspect(DTM)
## <<DocumentTermMatrix (documents: 1000, terms: 5960)>>
## Non-/sparse entries: 20465/5939535
## Sparsity : 100%
## Maximal term length: 23
## Weighting : term frequency (tf)
## Sample :
## Terms
## Docs and for from her his that the their who with
## 155 2 1 1 0 0 0 4 0 0 2
## 232 1 0 0 0 1 0 2 0 1 2
## 323 1 2 0 0 0 0 3 0 0 0
## 324 1 0 0 0 0 1 5 0 0 1
## 704 0 0 1 1 0 0 2 0 1 1
## 764 4 0 1 0 0 0 1 2 0 0
## 774 0 0 3 2 2 2 3 0 1 1
## 836 2 0 0 0 0 0 5 1 0 0
## 863 2 0 1 0 3 0 0 1 1 1
## 960 2 0 0 0 1 0 5 0 0 0
and, for, from, with 이런 단어들은 자주 쓰이는 단어이지만, 실제로 의미를 전달하는 단어는 아닙니다. 그러므로 텍스트마이닝 시에는 이런 단어들을 제거해주는 것이 더 원할한 분석을 진행할 수 있습니다.
CORPUS_TM = tm_map(CORPUS_TM, removeWords, c(stopwords("english"),"my","custom","words"))
stopwords 기능을 사용하면 and, his같은 단어들을 모두 삭제할 수 있습니다. 더 나아가 추가로 삭제하고 싶은 단어는 c( )명령어 안에 넣어주면 삭제를 시킬 수 있습니다. 현재는 'my', 'custom','words' 이 3가지 단어를 추가적으로 삭제시킨 상황입니다.
# 1안
convert_count = function(x) {
y <- ifelse(x > 0,1,0)
y = as.numeric(y)
y
}
# 2안
convert_count = function(x) {
y <- ifelse(x > 0,x,0)
y = as.numeric(y)
y
}
DESCRIPT_DATA=apply(DTM,MARGIN=2,convert_count) # 매트릭스 형태인 TDM에 convert_count를 하나씩 적용하여 값을 배출
DESCRIPT_DATA=as.data.frame(DESCRIPT_DATA)
# Temr Document Matrix 생성
TDM = TermDocumentMatrix(CORPUS_TM)
# 워드클라우드 생성
m <- as.matrix(TDM)
v <- sort(rowSums(m),decreasing=TRUE) # 빈도수를 기준으로 내림차순 정렬
d <- data.frame(word = names(v),freq=v)
library("SnowballC")
library("wordcloud")
library("RColorBrewer")
# min.freq -> 최소 5번 이상 쓰인 단어만 띄우기
# max.words -> 최대 200개만 띄우기
# random.order -> 단어 위치 랜덤 여부
wordcloud(words = d$word, freq = d$freq, min.freq = 5,
max.words=200, random.order=FALSE,
colors=brewer.pal(8, "Dark2"))
# 단어 빈도 그래프 그리기
barplot(d[1:10,]$freq, las = 2, names.arg = d[1:10,]$word,
col ="lightblue", main ="Most frequent words",
ylab = "Word frequencies")
텍스트 마이닝기법은 사실 통계적인 이용보다는 알고리즘에 기반한 Computer Science영역에 가깝습니다. 또한 텍스트를 제대로 분석하기위해서는 형태소분석을 기반으로 여러가지 알고리즘을 적용시켜야 그나마 깔끔하게 정리되는 경우가 많습니다. 현재는 R을 이용하여 비정형 데이터를 어떻게 가공하며, 이를 분석에서 사용하려면 어떻게 하는지에 집중을 하도록 하겠습니다. 기회가 된다면 후에 더 심화된 내용을 다루도록 하겠습니다.