school

[빅응보 4주차 실습] Text mining

동로시 2021. 3. 25. 20:54

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 : 순도로 같은 클래스로 나누게 분기할 때의 순도, 즉 잘 분류되었는지를 의미한다.