[빅응보 4주차 실습] Text mining
WHID(Web Hacking Incident Database)에 저장된 데이터를 이용해서 text mining으로 분석할 계획이다.
이 분석을 통해 document 내의 중요한 keyword를 뽑아낼 것이다.
필요한 패키지 : tm, corrplot, randomForest, lubridate
inspect가 안 될 경우 as.matrix()로 대체한다.
library(help=tm) : tm 라이브러리에 대한 설명을 보여준다.
rm(list=ls()) #Start with a clean slate: remove any and all objects
#Load libraries
library(tm) #for text mining functions
library(corrplot) #for creating plots of correlation matrices
library(randomForest) #for random forest decision tree analysis
library(lubridate)
#See complete description of tm package, along with an index of all functions
library(help=tm)
rawData <- read.csv("DefaultWHIDView2.csv",header=TRUE)
head(rawData) #view first few rows of data
colnames(rawData) #show the column names
data <- Corpus(VectorSource(rawData[,"IncidentDescription"]))
#Cleanup text
data2 = tm_map(data, stripWhitespace)
#data2 = tm_map(data2, stemDocument)
data2 = tm_map(data2, tolower)
stopWords = c(stopwords("english"))
data2 = tm_map(data2, removeWords, stopWords)
data2 = tm_map(data2, removePunctuation)
data2 = tm_map(data2, removeNumbers)
inspect(data2[1:5])
cleanup 작업은 데이터들을 조금 더 구조화시켜주는 작업이다.
stripWhiteSpace : space가 여러 개 있을 경우 하나로 만들어주는 작업
stemDocument : study, studying, studed와 같은 경우 study만으로 끊어주는 작업
tolower : 소문자로 변환해주는 작업
stopWords : 관사,조동사,접미사 등과 같은 text 중에서 불필요한 단어
removePunctuation : 콤마 같은 것들을 제거하는 작업
removeNumbers : 숫자를 제거하는 작업
이런 식으로 IncidientDescription에 있던 문장들의 단어가 cleanup된다.
#Make a word frequency matrix, with documents as rows, and terms as columns
dtm = DocumentTermMatrix(data2)
inspect(dtm[1:5,1:5])
#Remove and sparse terms a given percentage of sparse (i.e., 0) occurence
dtm = removeSparseTerms(dtm, 0.90)
inspect(dtm[1:5,1:5])
inspect(dtm)
summary(inspect(dtm[,1:3]))
DcumentTermMatrix로 행은 document, 열은 word(token, term)의 matrix형식으로 바꿔준다.
Sparsity(희소성)이 80%이고 non-sparse, 의미있는 데이터는 5개이고, sparse한 데이터는 20개다.
removeSparseTerms(dtm, 0.90) : threshold를 90%로 설정한 것으로 희소성이 90% 이상인 것은 제거한다.
threshold가 너무 높으면 희소성이 적은 값들이 너무 많기 때문에 중요한 패턴을 알기 어렵다.
threshold가 너무 낮으면 너무 많은 값들을 제거하기 때문에 중요한 의미를 놓칠 수 있다.
non-sparse가 7개로 늘어난 것을 확인 할 수 있다.
summary() : 중심화 경향과 퍼짐정도에 대해서 빠르게 볼 수 있는 통계량들을 제공한다.
- 1st Qu : 하위 25%의 값
- median : 중앙값
- 3rd Qu : 상위 25%의 값
이렇게 제공되는 정보를 data profile(데이터가 어떤 의미를 갖는지를 알기 위한 통계)이라고 한다.
#Find terms that occur at least n times
findFreqTerms(dtm, 100)
#Find associated terms with the term, "attack", and a correlation of at least r
findAssocs(dtm, "attack", 0.1)
#Find associated terms with the term, "service", and a correlation of at least r
findAssocs(dtm, "service", 0.1)
findFreqTerms() : n 번 이상 나온 column 값을 찾는다.
findAssocs() : 주어진 단어와 상관관계가 n 이상인 단어들을 찾는다.
이제 앞에서 구한 dtm을 년도 별로 어떤 단어들이 많이 나오는지를 구할 계획이다.
#Make a word frequency matrix, with terms as rows, and documents as columns
#Note that the findings are the same, but the layout is visually different
tdm = TermDocumentMatrix(data2)
inspect(tdm[1:5,1:5])
tdm = removeSparseTerms(tdm, 0.90)
inspect(tdm[1:5,1:5])
findAssocs(tdm, "attack", 0.1)
#Convert to date format
dateVector <- as.Date(rawData[,"DateOccured"], "%m/%d/%Y")
mnth <- month(dateVector)
yr <- year(dateVector)
dtmAndDates <- data.frame(dateVector,mnth,yr,as.matrix(dtm))
head(dtmAndDates)
dtmAndYr <- data.frame(yr,as.matrix(dtm))
(sumByYear <- aggregate(dtmAndYr[,-1], by=list(dtmAndYr$yr), sum))
#Prepare data for correlation analysis
selTermsByYr <- sumByYear[,-1] #remove the year column
rownames(selTermsByYr) <- sumByYear[,1] #make the years into rownames
selTermsByYr #show the result
#Create a correlation matrix on trended data
(corData <- cor(selTermsByYr))
#Create a correlation plot on trended data
png("Figure1.png")
corrplot(corData, method="ellipse")
dev.off()
as.Date() : DateOccured 의 값들을 월/일/년 형식으로 바꿔준다.
data.frame() : data들을 matrix형태로 만들어 준다.
dtmAndYear는 yr과 dtm으로 만든 matrix다.
aggregate(dtmAndYear[,-1], yr, sum): 데이터의 yr 컬럼을 기준으로 합의 통계량을 구해준다.
dtmAndYear[,-1]은 첫번째 열을 제거한 것이다.
+ 명령어에 ( ) 를 붙히면 자동으로 결과를 보여준다
[,-1]을 하지 않으면 다음과 같은 결과가 나온다.
selTermsByYr : 1번째 열인 연도를 제거한 matrix
rownames() : 행의 이름을 sumByYear의 1행 값인 년도로 바꿔준다.
cor() : 해당 데이터들의 상관관계를 보여준다. (상관관계는 -1~1 사이의 값을 같고 0은 상관관계가 없는 것을 의미한다)
corrplot() : 상관관계를 그래프로 그린다. 이 때 ellipse의 width가 작을 수록 강하고 color에 따라서도 다르다.
#Create a dictionary: a subset of terms
d = inspect(DocumentTermMatrix(data2, list(dictionary = c("attack", "security", "site", "web"))))
#Correlation matrix
cor(d) #correlation matrix of dictionary terms only
d는 딕셔너리를 이용해서 특정 데이터에 관해 DocumentTermMatrix를 생성한 거싱다.
#Visually compare the terms, "attack", and "Security" in a barplot
par(mfrow=c(2,1)) #group the plots together, one on top of the other
barplot(d[,"attack"],main="Term Frequency: Attack", xlab="Incident", ylab="Frequency")
barplot(d[,"security"],main="Term Frequency: Security", xlab="Incident", ylab="Frequency")
par(mfrow=c(2,1)) : 2행 1열의 plot
barplot() : 바 형식의 plot으로 생성한다.
#Create a scatterplot comparing "site" and "web"
png("Figure2.png")
plot(jitter(d[,"site"])~jitter(d[,"web"]), main="Scatterplot: 'site' vs 'web'",xlab="term: web", ylab="term: site")
abline(lm(d[,"site"]~d[,"web"]))
dev.off()
jitter 형식으로 attack과 security의 plot을 보여준다.
lm은 linear regression으로 값을 예측한다.
#Hierarchical cluster analysis
png("Figure3.png")
hClust <- hclust(dist(dtm))
plot(hClust, labels=FALSE)
dev.off()
Hierarchical cluster는 top-down 형식의 클러스터 방법이다.
#K-means cluster analysis
kmClust <- kmeans(dtm,centers=3)
print(kmClust)
#Assign cluster membership to the orginal data
dtmWithClust <- data.frame(inspect(dtm), kmClust$cluster)
print(dtmWithClust)
rfClust <- randomForest(kmClust.cluster~., data=dtmWithClust, importance=TRUE, proximity=TRUE)
print(rfClust)
importance(rfClust)
3개를 k개로 kemans를 적용한 결과다. 각 값은 1 2 3에 들어갈 확률이다.
dtmWidthClust는 cluster값과 dtm을 매트릭스로 만든 것이다.
randomForest() : 여러 개의 decision tree를 연결해서 더 유용한 모델을 만드는데 classfication과 regression으로 나뉜다.
importance가 클 수록 더 중요한 데이터이다.
IncMSE : 평균제곱오차(예측-실제)로 작을수록 정확성이 높으며 그 데이터가 없다면 값이 증가할 것이다.
IncNodePurity : 순도로 같은 클래스로 나누게 분기할 때의 순도, 즉 잘 분류되었는지를 의미한다.