## 텍스트 분석에 필요한 라이브러리 설치
# install.pakages('tidyverse')
# install.packages("devtools")
# library(devtools)
# devtools::install_github("shineware/RKOMORAN")
# devtools::install_github("shineware/RKOMORAN",INSTALL_opts=c("--no-multiarch"))
## 각종 라이브러리 구동
library('RKOMORAN')
library ('tm')
library ('stringr')
library('tidyverse')
library('dplyr')
library('tidytext')
library('tidyr')
# set env
#my.text.location <- "Olym_nar_25"
#my.text.location <- "Olym_info_25"
user_dic_N <- "user_dic_nar.txt"
user_dic_I <- "user_dic_info.txt"
lexicon <- read.csv("wordlist_easyword_5000.csv", stringsAsFactors = FALSE)
# helper
mytempfunct <- function(myobject, oldexp, newexp) {
newobject <- tm_map(myobject,
content_transformer(function(x,pattern) gsub(pattern,newexp,x)), oldexp)
newobject
}
### 문학 텍스트 분석하기
# 문학 텍스트(narrative text)에는 동화, 소설, 수필 등이 포함됨
func_nar = function(my.text.location, user_dic, lexicon){
## 분석 대상 텍스트 불러오기
# 올림피아드 평가 25회 국어 시험에 사용된 문학 텍스트를 예시로 분석
#my.text.location <- "C:/Users/cheon/Desktop/Olym_nar_25"
mytext <- VCorpus(DirSource(my.text.location))
#mytext
## 문단, 문장, 단어의 개수 세기
# 문단의 개수
size.para <- rep(NA, length(mytext))
mypara <- list(rep(NA, length(mytext)))
mypara.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)){
mypara[[i]] <- strsplit(mytext[[i]]$content, split='\n')
mypara.count[i] <- length(unlist(mypara[[i]]))
size.para[i] <- mypara.count[i]
}
#size.para
# 문장의 개수
size.sent <- rep(NA, length(mytext))
mysent <- list(rep(NA, length(mytext)))
mysent.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)) {
mypara[[i]] <- unlist(mypara[[i]])
mysent[[i]] <- strsplit(mypara[[i]], split='\\. |\\? |\\! ')
mysent.count[i] <- length(unlist(mysent[[i]]))
size.sent[i] <- mysent.count[i]
}
#size.sent
# 단어의 개수
size.word <- rep(NA, length(mytext))
myword <- list(rep(NA, length(mytext)))
myword.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)) {
mysent[[i]] <- unlist(mysent[[i]])
myword[[i]] <- strsplit(mysent[[i]],split=' ')
myword.count[i] <- length(unlist(myword[[i]]))
size.word[i] <- myword.count[i]
}
#size.word
## 평균 문장 길이 계산
# <평균 문장 길이>는 한 문장이 평균 몇 개의 단어로 이루어졌는지를 나타냄
# 이 값이 클수록, 문장이 길고 복잡함
sent.leng <- round(size.word/size.sent, 1)
#sent.leng
## 텍스트의 파일 형식 바꾸기
# 문단별로 구분된 원래의 텍스트를 한 줄로 변환
mytext.new = mytext
for (i in 1:length(mytext)){
mytext.new[[i]]$content = paste(mytext[[i]]$content, collapse=" ")
#print("*******************")
#print(mytext[[i]]$content)
#print("*******************")
#print(mytext.new[[i]]$content)
#print("*******************")
}
## 텍스트 전처리(text preprocessing)
# 분석에 불필요한 특수문자 제거하기
mycorpus <- mytext.new
#mytempfunct <- function(myobject, oldexp, newexp) {
# newobject <- tm_map(myobject,
# content_transformer(function(x,pattern) gsub(pattern,newexp,x)), oldexp)
# newobject
#}
mycorpus <- mytempfunct(mycorpus, "[[:lower:]]","")
mycorpus <- mytempfunct(mycorpus, "[[:upper:]]","")
mycorpus <- mytempfunct(mycorpus, "\\("," ")
mycorpus <- mytempfunct(mycorpus, "\\)","")
mycorpus <- mytempfunct(mycorpus, "‘","")
mycorpus <- mytempfunct(mycorpus, "’","")
mycorpus <- mytempfunct(mycorpus, "“","")
mycorpus <- mytempfunct(mycorpus, "”","")
mycorpus <- mytempfunct(mycorpus, "·",", ")
mycorpus <- mytempfunct(mycorpus, "·",", ")
mycorpus <- mytempfunct(mycorpus, "ㆍ",", ")
mycorpus <- mytempfunct(mycorpus, "/","")
mycorpus <- mytempfunct(mycorpus, "-","")
mycorpus <- mytempfunct(mycorpus, "-","")
mycorpus <- mytempfunct(mycorpus, "『","")
mycorpus <- mytempfunct(mycorpus, "』","")
mycorpus <- mytempfunct(mycorpus, "「","")
mycorpus <- mytempfunct(mycorpus, "」","")
mycorpus <- mytempfunct(mycorpus, "O","")
mycorpus <- mytempfunct(mycorpus, "○","")
mycorpus <- mytempfunct(mycorpus, "♡"," ")
mycorpus <- mytempfunct(mycorpus, ":","")
mycorpus <- mytempfunct(mycorpus, "…","")
mycorpus <- mytempfunct(mycorpus, "<","")
mycorpus <- mytempfunct(mycorpus, ">","")
mycorpus <- mytempfunct(mycorpus, "~","")
mycorpus <- mytempfunct(mycorpus, "。","")
mycorpus <- mytempfunct(mycorpus, "\"","")
mycorpus <- mytempfunct(mycorpus, "―","")
## 품사별 단어 추출
# 주요 품사별 단어 추출하기
# 일반명사, 고유명사, 의존명사, 대명사, 수사, 동사, 형용사, 보조용언, 관형사, 일반부사, 접속부사, 감탄사, 어근
# RKOMORAN 형태소 분석기 사용하기
# KOMORAN - KOrean MORphological ANalyzer
# 형태소 분석 결과를 튜닝하기 위하여 사용자 사전(user dictionary)을 활용 (user_dic_nar)
komoran = RKOMORAN::RKOMORAN$new(model_type = "STABLE")
#komoran$set_user_dic("C:/Users/cheon/Desktop/user_dic_nar.txt")
komoran$set_user_dic(user_dic)
my.POS.func <- function(mytext) {
myobject = komoran$get_plain_text(mytext)
mylocation = gregexpr(pattern ='[가-힣]+(/NNG|/NNP|/NNB|/NP|/NR|/VV|/VA|/VX|/MM|/MAG|/MAJ|/IC|/XR)', myobject)
new.myobject = regmatches(myobject, mylocation)
new.myobject = unlist(new.myobject)
new.myobject
}
#my.POS.func(mycorpus[[1]]$content)
## 추출한 단어들을 문서별로 데이터프레임으로 만들기
myresult=data.frame(my.POS.func(mycorpus[[1]]$content))
colnames(myresult)="word"
myresult$id=1
for (i in 2:length(mytext)){
mydf=data.frame(my.POS.func(mycorpus[[i]]$content))
colnames(mydf)="word"
mydf$id=i
myresult=rbind(myresult,mydf)
}
myresult=myresult[,c("id","word")]
#myresult
##어려운 단어의 개수 세기
# 쉬운 단어 목록에 없는 어려운 단어의 수를 세기
# 약 5천개의 쉬운 단어 목록 불러오기
#lexicon <- read.csv("C:/Users/cheon/Desktop/wordlist_easyword_5000.csv", stringsAsFactors = FALSE)
colnames(lexicon) <- c("word", "count")
#lexicon
myresult <- myresult %>% mutate(word=as.character(word))
df_ID <- tibble(id=unique(myresult$id))
# 고유명사(NNP)는 한차례만 어려운 단어로 세기
# 일반부사(MAG), 접속부사(MAJ), 감탄사(IC)는 제외하기
myresult.difficult.word <- myresult %>%
anti_join(lexicon, by="word") %>%
mutate(
number = 1
) %>%
count(id, word, number) %>%
mutate(
freq = ifelse(str_detect(word, "/NNP"), 1 ,n)
) %>%
filter(str_detect(word, "[가-힣]+(/MAG|/MAJ|/IC)", negate = TRUE)) %>%
full_join(df_ID, by="id") %>%
arrange(id)
#myresult.difficult.word
# 문서별로 어려운 단어의 수를 합하기
new.myresult <- myresult.difficult.word %>%
group_by(id) %>%
summarize(
count.freq = sum(freq,na.rm=TRUE))
#new.myresult
# 어려운 단어의 비율 계산하기
new.myresult.1 = new.myresult %>%
mutate(
difficult.word = round(count.freq/size.word, 2)
)
#new.myresult.1
# <어려운 단어의 수> 및 <어려운 단어의 비율>을 저장하기
# write.csv(new.myresult.1, "nar_word_count.csv", row.names = FALSE)
difficult_word = new.myresult.1$difficult.word
## 텍스트의 <학년 수준> 추정하기
# 예를 들어, '3.0 학년' 수준은 3학년 학생이 읽기에 적합한 텍스트임
# 회귀방정식을 통하여 학년 수준 추정
# <어려운 단어의 비율>과 <평균 문장 길이>를 언어적 변수로 하여 학년 수준 추정
# 언어적 변수들을 로그값으로 변환하기
grade.level = round(-7.914 + 66.481*log((difficult_word + 1), 10) + 10.731*log((sent.leng + 1), 10), 1)
#grade.level
#학년 수준 추정 결과 저장하기
# write.csv(grade.level, "narrative_grade.csv", row.names = FALSE)
### 추가적인 텍스트 지수 산출하기
## 타입-토큰 비율(Type-Token Ratio, TTR) 계산하기
# TTR은 어휘의 다양성을 나타냄
# TTR 값이 1에 가까울수록, 텍스트에서 다양한 어휘가 사용됨
# 문서별 타입의 개수
size.type <- rep(NA, length(mycorpus))
for(j in 1:length(mycorpus)){
size.type[j] <- nrow(table(my.POS.func(mycorpus[[j]]$content)))
}
#size.type
# 문서별 토큰의 개수
size.token <- rep(NA, length(mycorpus))
for(k in 1:length(mycorpus)){
size.token[k] <- sum(table(my.POS.func(mycorpus[[k]]$content)))
}
#size.token
# 타입-토큰 비율
tibble.ttr <- tibble(size.type, size.token) %>%
mutate(
ttr = round(size.type/size.token, 2)
)
#tibble.ttr
### 텍스트 분석 결과를 종합하기
text.anlaysis.result <- tibble(para_count=size.para, sent_count=size.sent, word_count=size.word,
mean_sent_length=sent.leng, diffcult_word_count=new.myresult.1$count.freq,
difficult_word_proportion=new.myresult.1$difficult.word, grade_level=grade.level,
ttr=tibble.ttr$ttr)
#text.anlaysis.result %>% print(n=3)
# 변수 이름 재설정
mylabels = c("문단수", "문장수", "단어수", "평균문장길이", "어려운단어수", "어려운단어비율",
"학년수준", "타입토큰비율")
names(text.anlaysis.result) = mylabels
#text.anlaysis.result
# 텍스트 분석 결과를 저장하기
#write.csv(text.anlaysis.result, "narrative_text_analysis_result.csv", row.names = FALSE)
return(text.anlaysis.result)
}
#func_nar(my.text.location, user_dic_N, lexicon)
### 정보전달 텍스트 분석하기
# 정보전달 텍스트(informational text)에는 설명문, 논설문 등이 포함됨
func_info = function(my.text.location, user_dic, lexicon){
## 분석 대상 텍스트 불러오기
# 올림피아드 평가 25회 국어 시험에 사용된 정보전달 텍스트를 예시로 분석
#my.text.location <- "C:/Users/cheon/Desktop/Olym_info_25"
mytext <- VCorpus(DirSource(my.text.location))
#mytext
## 문단, 문장, 단어의 개수 세기
# 문단의 개수
size.para <- rep(NA, length(mytext))
mypara <- list(rep(NA, length(mytext)))
mypara.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)){
mypara[[i]] <- strsplit(mytext[[i]]$content, split='\n')
mypara.count[i] <- length(unlist(mypara[[i]]))
size.para[i] <- mypara.count[i]
}
#size.para
# 문장의 개수
size.sent <- rep(NA, length(mytext))
mysent <- list(rep(NA, length(mytext)))
mysent.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)) {
mypara[[i]] <- unlist(mypara[[i]])
mysent[[i]] <- strsplit(mypara[[i]], split='\\. |\\? |\\! ')
mysent.count[i] <- length(unlist(mysent[[i]]))
size.sent[i] <- mysent.count[i]
}
#size.sent
# 단어의 개수
size.word <- rep(NA, length(mytext))
myword <- list(rep(NA, length(mytext)))
myword.count <- rep(NA, length(mytext))
for (i in 1:length(mytext)) {
mysent[[i]] <- unlist(mysent[[i]])
myword[[i]] <- strsplit(mysent[[i]],split=' ')
myword.count[i] <- length(unlist(myword[[i]]))
size.word[i] <- myword.count[i]
}
#size.word
## 평균 문장 길이 계산
# <평균 문장 길이>는 한 문장이 평균 몇 개의 단어로 이루어졌는지를 나타냄
# 이 값이 클수록, 문장이 길고 복잡함
sent.leng <- round(size.word/size.sent, 1)
#sent.leng
## 텍스트의 파일 형식 바꾸기
# 문단별로 구분된 원래의 텍스트를 한 줄로 변환
mytext.new = mytext
for (i in 1:length(mytext)){
mytext.new[[i]]$content = paste(mytext[[i]]$content, collapse=" ")
#print("*******************")
#print(mytext[[i]]$content)
#print("*******************")
#print(mytext.new[[i]]$content)
#print("*******************")
}
## 텍스트 전처리(text preprocessing)
# 분석에 불필요한 특수문자 제거하기
mycorpus <- mytext.new
#mytempfunct <- function(myobject, oldexp, newexp) {
# newobject <- tm_map(myobject,
# content_transformer(function(x,pattern) gsub(pattern,newexp,x)), oldexp)
# newobject
#}
mycorpus <- mytempfunct(mycorpus, "[[:lower:]]","")
mycorpus <- mytempfunct(mycorpus, "[[:upper:]]","")
mycorpus <- mytempfunct(mycorpus, "\\("," ")
mycorpus <- mytempfunct(mycorpus, "\\)","")
mycorpus <- mytempfunct(mycorpus, "‘","")
mycorpus <- mytempfunct(mycorpus, "’","")
mycorpus <- mytempfunct(mycorpus, "“","")
mycorpus <- mytempfunct(mycorpus, "”","")
mycorpus <- mytempfunct(mycorpus, "·",", ")
mycorpus <- mytempfunct(mycorpus, "·",", ")
mycorpus <- mytempfunct(mycorpus, "ㆍ",", ")
mycorpus <- mytempfunct(mycorpus, "/","")
mycorpus <- mytempfunct(mycorpus, "-","")
mycorpus <- mytempfunct(mycorpus, "-","")
mycorpus <- mytempfunct(mycorpus, "『","")
mycorpus <- mytempfunct(mycorpus, "』","")
mycorpus <- mytempfunct(mycorpus, "「","")
mycorpus <- mytempfunct(mycorpus, "」","")
mycorpus <- mytempfunct(mycorpus, "O","")
mycorpus <- mytempfunct(mycorpus, "○","")
mycorpus <- mytempfunct(mycorpus, "♡"," ")
mycorpus <- mytempfunct(mycorpus, ":","")
mycorpus <- mytempfunct(mycorpus, "…","")
mycorpus <- mytempfunct(mycorpus, "<","")
mycorpus <- mytempfunct(mycorpus, ">","")
mycorpus <- mytempfunct(mycorpus, "~","")
mycorpus <- mytempfunct(mycorpus, "。","")
mycorpus <- mytempfunct(mycorpus, "\"","")
mycorpus <- mytempfunct(mycorpus, "―","")
## 품사별 단어 추출
# 주요 품사별 단어 추출하기
# 일반명사, 고유명사, 의존명사, 대명사, 수사, 동사, 형용사, 보조용언, 관형사, 일반부사, 접속부사, 감탄사, 어근
# RKOMORAN 형태소 분석기 사용하기
# KOMORAN - KOrean MORphological ANalyzer
# 형태소 분석 결과를 튜닝하기 위하여 사용자 사전(user dictionary)을 활용 (user_dic_info)
komoran = RKOMORAN::RKOMORAN$new(model_type = "STABLE")
#komoran$set_user_dic("user_dic_info.txt")
komoran$set_user_dic(user_dic)
my.POS.func <- function(mytext) {
myobject = komoran$get_plain_text(mytext)
mylocation = gregexpr(pattern ='[가-힣]+(/NNG|/NNP|/NNB|/NP|/NR|/VV|/VA|/VX|/MM|/MAG|/MAJ|/IC|/XR)', myobject)
new.myobject = regmatches(myobject, mylocation)
new.myobject = unlist(new.myobject)
new.myobject
}
#my.POS.func(mycorpus[[1]]$content)
## 추출한 단어들을 문서별로 데이터프레임으로 만들기
myresult=data.frame(my.POS.func(mycorpus[[1]]$content))
colnames(myresult)="word"
myresult$id=1
for (i in 2:length(mytext)){
mydf=data.frame(my.POS.func(mycorpus[[i]]$content))
colnames(mydf)="word"
mydf$id=i
myresult=rbind(myresult,mydf)
}
myresult=myresult[,c("id","word")]
#myresult
##어려운 단어의 개수 세기
# 쉬운 단어 목록에 없는 어려운 단어의 수를 세기
# 약 5천개의 쉬운 단어 목록 불러오기
#lexicon <- read.csv("wordlist_easyword_5000.csv", stringsAsFactors = FALSE)
colnames(lexicon) <- c("word", "count")
#lexicon
myresult <- myresult %>% mutate(word=as.character(word))
df_ID <- tibble(id=unique(myresult$id))
# 고유명사(NNP)는 한차례만 어려운 단어로 세기
myresult.difficult.word <- myresult %>%
anti_join(lexicon, by="word") %>%
mutate(
number = 1
) %>%
count(id, word, number) %>%
mutate(
freq = ifelse(str_detect(word, "/NNP"), 1 ,n)
) %>%
full_join(df_ID, by="id") %>%
arrange(id)
#myresult.difficult.word
# 문서별로 어려운 단어의 수를 합하기
new.myresult <- myresult.difficult.word %>%
group_by(id) %>%
summarize(
count.freq = sum(freq,na.rm=TRUE))
#new.myresult
# 어려운 단어의 비율 계산하기
new.myresult.1 = new.myresult %>%
mutate(
difficult.word = round(count.freq/size.word, 2)
)
#new.myresult.1
# <어려운 단어의 수> 및 <어려운 단어의 비율>을 저장하기
# write.csv(new.myresult.1, "nar_word_count.csv", row.names = FALSE)
difficult_word = new.myresult.1$difficult.word
## 텍스트의 <학년 수준> 추정하기
# 예를 들어, '3.0 학년' 수준은 3학년 학생이 읽기에 적합한 텍스트임
# 회귀방정식을 통하여 학년 수준 추정
# <어려운 단어의 비율>과 <평균 문장 길이>를 언어적 변수로 하여 학년 수준 추정
grade.level = round(-3.5357 + 10.9363*difficult_word + 0.6723*sent.leng, 1)
#grade.level
#학년 수준 추정 결과 저장하기
# write.csv(grade.level, "informational_grade.csv", row.names = FALSE)
### 추가적인 텍스트 지수 산출하기
## 타입-토큰 비율(Type-Token Ratio, TTR) 계산하기
# TTR은 어휘의 다양성을 나타냄
# TTR 값이 1에 가까울수록, 텍스트에서 다양한 어휘가 사용됨
# 문서별 타입의 개수
size.type <- rep(NA, length(mycorpus))
for(j in 1:length(mycorpus)){
size.type[j] <- nrow(table(my.POS.func(mycorpus[[j]]$content)))
}
#size.type
# 문서별 토큰의 개수
size.token <- rep(NA, length(mycorpus))
for(k in 1:length(mycorpus)){
size.token[k] <- sum(table(my.POS.func(mycorpus[[k]]$content)))
}
#size.token
# 타입-토큰 비율
tibble.ttr <- tibble(size.type, size.token) %>%
mutate(
ttr = round(size.type/size.token, 2)
)
#tibble.ttr
### 텍스트 분석 결과를 종합하기
text.anlaysis.result <- tibble(para_count=size.para, sent_count=size.sent, word_count=size.word,
mean_sent_length=sent.leng, diffcult_word_count=new.myresult.1$count.freq,
difficult_word_proportion=new.myresult.1$difficult.word, grade_level=grade.level,
ttr=tibble.ttr$ttr)
#text.anlaysis.result %>% print(n=3)
# 변수 이름 재설정
mylabels = c("문단수", "문장수", "단어수", "평균문장길이", "어려운단어수", "어려운단어비율",
"학년수준", "타입토큰비율")
names(text.anlaysis.result) = mylabels
#text.anlaysis.result
# 텍스트 분석 결과를 저장하기
#write.csv(text.anlaysis.result, "informational_text_analysis_result.csv", row.names = FALSE)
return(text.anlaysis.result)
}
#func_info(my.text.location, user_dic_I, lexicon)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.