inst/KorText/global.R

## 텍스트 분석에 필요한 라이브러리 설치

# 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)
rinseo/KorText documentation built on March 26, 2020, 12:10 a.m.