Practice makes perfect

[R] 텍스트 마이닝 분석 (토픽분석) 본문

빅데이터/R

[R] 텍스트 마이닝 분석 (토픽분석)

kerpect 2020. 7. 9. 16:30

토픽 분석 ( 빈도 분석 ) 

: 텍스트 데이터를 대상을 단어를 추출하고, 이를 단어 사전과 비교하여 단어의 출현 빈도수를 분석하는 텍스팅 마이닝 분석 과정을 의미  

+ 또한 단어구름(word cloud) 패키지를 적용하여 분석 결과를 시각화 하는 과정도 포함 

 

 

1. 텍스트 자료 가져오기 

facebook <- file("C:/workspaces/R/data/facebook_bigdata.txt",encoding = "UTF-8")

facebook_data <- readLines(facebook)

file( ) : 텅키로 파일을 읽어 옴

readLines( ) : 줄 단위 데이터 생성

 

facebook 

 

facebook_data 의 데이터 내용, 종류 

str(facebook_data) 출력값 : chr [1:76] // 76줄

head(facebook_data) # 앞부분 6줄 보기 - 줄 단위 데이터 생성

 

 

2. 세종 사전에 신규 단어 추가 

userDic <- data.frame(term=c("R 프로그래밍", "페이스북", "소셜네트워크", "얼죽아"), tag='ncn') 

term( ) :추가 단어 저장 

tag( ) :저장된 문자의 형태 저장
('ncn') : 명사 

 

 

- 신규 단어 사정 추가 함수 

buildDictionary(ext_dic = 'sejong', user_dic = userDic) 

buildDictionary (ext_dic = '저장할 사전 이름', user_dic = 변수 이름 )

 

 

3. 단어 추출 위한 사용자 정의 함수 

 

- R 제공 함수로 단어 추출하기 - Sejong 사전에 등록된 신규 단어 테스트 

paste(extractNoun("홍길동은 얼죽아를 최애로 생각하는, 빅데이터에 최대 관심을 가지고 있으면서, 
                   페이스북이나 소셜네트워크로부터 생성 수집되어진 빅데이터 분석에 많은 관심을 
                   가지고 있어요."),collapse=" ")
                   
출력값:
[1] "홍길동은 얼죽아 최애로 생각 빅데이터에 최대 관심 페이스북 
     소셜네트워크 생성 수집 빅데이터 분석 관심"

paste( ) : 나열된 원소 사이에 공백을 두고 결과값을 출력
extractNoun( ) : 명사를 추출 
collapse=" " : 찾은 단어 사이 ( )넣기

 

 

4. 단어 추출을 위한 사용자 정의 함수 정의하기

 

(1) 사용자 정의 함수 작성

[문자형 변환] -> [명사 단어 추출] -> [" "으로 데이터 연결하여 하나의 문자열로 출력] 

exNouns <- function(x){ 
  paste(extractNoun(as.character(x)), collapse = " ")  
}

- 텍스트 마이닝에서 기본적인 전처리 과정으로 많이 사용되는 형태. 

 

 

(2) exNouns 함수 이용 단어 추출

facebook_nouns <- sapply(facebook_data, exNouns) # 명사 단어 추출 
facebook_nouns[1] # 단어가 추출된 첫 줄 보기 

 

위의 문장을 밑의 문장으로 처리 된 결과를 출력해줍니다(명사형) 

 

sapply(list, function)
sapply 는 list 대신 행렬 or 벡터로 반환

Apply

함수는 행렬의 행 또는 열 방향으로 특정 함수를 적용
apply(matrix, 1 or 2, 함수) - 1: 행, 2: 열

lapply
apply 함수의 단점은 input 으로 array 만 입력할 수 있다는 것

일반적으로 vector 를 input 넣는 경우가 많은데, 이를 위해 lapply 가 존재
입력으로 vector 또는 list 를 받아 list 를 반환

 

 

5.  추출된 단어 대상 전처리 

 

①  추출된 단어 이용 말뭉치(Corpus) 생성

myCorpus <- Corpus(VectorSource(facebook_nouns))
myCorpus

출력값 

 <<SimpleCorpus>>
 Metadata:  corpus specific: 1, document level (indexed): 0
 Content:  documents: 76
 
 - 76개의 말뭉치 단위로 포장

Corpus() : 단어 처리의 단위
VectorSource() : vector 형으로 변환 

 

 

② 데이터 전처리 

myCorpusPrepro <- tm_map(myCorpus,removePunctuation) # 문장부호 제거 
# - myCorpus 안에 들어있는 문장 부호를 삭제 한다. 

myCorpusPrepro <-tm_map(myCorpusPrepro, removeNumbers) # 수치 제거
# - myCorpusPrepro 안에 들어있는 숫자 삭제 한다.

myCorpusPrepro <-tm_map(myCorpusPrepro, tolower) #영문자 소문자 변경
# - myCorpusPrepro 안에 들어있는 영문자 소문자 변경.

myCorpusPrepro <-tm_map(myCorpusPrepro, removeWords,stopwords('english')) 
# 불용어(for, very, and, of, are...)제거 

 tm_map() : Corpus로 처리된 데이터를 받아서 필터링을 해준다.
 removePunctuation() : 문장부호 삭제 
 removeNumbers() : 수치 제거 
 tolower() : 영문자 소문자 변경 
 removeWords , stopwords('english') :  불용어(for, very, and, of, are...)제거 

 

 

③  전처리 결과 확인

inspect(myCorpusPrepro[1])

 

 

6. 단어 선별 

- 단어 2음절 ~ 8음절 사이 단어 선택하기 

- Corpus 객체를 대상으로 TermDocumentMatrix() 함수를 이용하여 분석에 필용한 단어 선별하고 단어/문서 행렬을 

   만듭니다. 
- 한글 1음절은 2byte에 저장(2음절 = 4byte , 8음절 = 16byte)

myCorpusPrepro_term <- TermDocumentMatrix(myCorpusPrepro,control=list(wordLengths=c(4,16)))

myCorpusPrepro_term

- 출력값- 
 <<TermDocumentMatrix (terms: 696, documents: 76)>>
   Non-/sparse entries: 1256/51640
 Sparsity           : 98%
 Maximal term length: 12
 Weighting          : term frequency (tf)

- 텍스트를 숫자로 표현하는 대표적인 방법 

 

- matrix 자료구조를 data.frame 자료 구조로 변경

myTerm_df <- as.data.frame(as.matrix(myCorpusPrepro_term))
dim(myTerm_df) 출력값: [1] 696  76

 

 

7. 단어 출현 빈도수 구하기

- - 빈도수 높은 순서대로 내림차순 정렬

wordResult <- sort(rowSums(myTerm_df), decreasing = T)

wordResult[1:10]

- 출력값 -
데이터  분석   빅데이터   처리     사용     수집   시스템     저장     결과     노드 
91      41       33      31        29      27      23       16       14       13 

빈도수로 내림차순 정렬
decreasing = T : 내림차순 정렬

 

사용이 빅데이터와 관련 없는 단어가 출력될 수 있습니다.

 

 

8. 불필요한 용어 제거 시작 

 

① 데이터 전처리

myCorpusPrepro <- tm_map(myCorpus,removePunctuation) # 문장부호 제거 
# - myCorpus 안에 들어있는 문장 부호를 삭제 한다. 

myCorpusPrepro <-tm_map(myCorpusPrepro, removeNumbers) # 수치 제거
# - myCorpusPrepro 안에 들어있는 숫자 삭제 한다.

myCorpusPrepro <-tm_map(myCorpusPrepro, tolower) #영문자 소문자 변경
# - myCorpusPrepro 안에 들어있는 영문자 소문자 변경.

myCorpusPrepro <-tm_map(myCorpusPrepro, removeWords,stopwords('english')) 
# 불용어(for, very, and, of, are...)제거 

myStopwords <- c(stopwords('english'),"사용","하기")

myCorpusPrepro <-tm_map(myCorpusPrepro, removeWords,myStopwords) # 불용어 제거 

inspect(myCorpusPrepro[1:5]) # 데이터 전처리 결과 확인 

 

②  단어 선별 - 단어 길이 2 ~ 8 개 이상 단어 선별.

myCorpusPrepro_term <- TermDocumentMatrix(myCorpusPrepro,control=list(wordLengths=c(4,16)))

myTerm_df <- as.data.frame(as.matrix(myCorpusPrepro_term))
dim(myTerm_df) # 출력값 : [1] 696  76

wordResult <- sort(rowSums(myTerm_df), decreasing = T)

wordResult[1:10]

 - 출력값 -
 
 데이터   분석   빅데이터    처리     수집    시스템     저장     결과     노드     얘기 
   91      41      33        31       27       23       16       14       13       13 

 

 

9. 단어 구름(wordcloud) 시각화 

 

디자인 적용전 

myName <- names(wordResult) # 단어 이름 축출
wordcloud(myName, wordResult) # 단어 구름 시각화 

 

단어 구름에 디자인 적용 (빅도수, 색상, 위치, 회전등)

1) 단어 이름과 빈도수로 data.frame 생성

word.df <- data.frame(word=myName, freq=wordResult)
str(word.df)

-출력값-
 'data.frame':	694 obs. of  2 variables:
 $ word: Factor w/ 694 levels "‘똑똑한","‘삶",..: 197 283 297 546 359 374 495 103 169 399 ...
 $ freq: num  91 41 33 31 27 23 16 14 13 13 ...

 

2) 단어 색상과 글꼴 지정

pal <- brewer.pal(12,"Paired") # 12가지 생상 pal
windowsFonts(malgun=windowsFont("맑은 고딕"))
brewer.pal(색상의 수)

 

3) 단어 구름 시각화 

x11() # 별도의 창을 띄우는 함수 
wordcloud(word.df$word, word.df$freq, scale = c(5,1), min.freq = 3, random.order = F,  
          rot.per = .1, colors = pal, famliy = "malgun")
          
random.order = F : 가장 큰 크기를 가운데 고정 

 

 

 

# 예제) 

hiphop.txt 을 이용하겠습니다. 

 

① 데이터 불러오기 

txt <- readLines("C:/workspaces/R/data/hiphop.txt")
head(txt)

- 출력값 - 
[1] "\"보고 싶다"                  "이렇게 말하니까 더 보고 싶다" "너희 사진을 보고 있어도"     
[4] "보고 싶다"                    "너무 야속한 시간"             "나는 우리가 밉다"   

 

 

② 특수문자 제거 

txt1 <- str_replace_all(txt, "\\W", " ")

head(txt1)
- 출력값 - 
[1] " 보고 싶다"                   "이렇게 말하니까 더 보고 싶다" "너희 사진을 보고 있어도"     
[4] "보고 싶다"                    "너무 야속한 시간"             "나는 우리가 밉다"            

\W(대문자) : 특수 문자 선택 

\w(소문자) : 특수 문자 제외 선택 

str_replace_all(변수, 변경 전 문자, 변경 후 문자) : 문자 변경 

 

 

 

③ 가사에서 명사 추출

nouns <- extractNoun(txt1)
head(nouns)

- 출력값 - 
[[1]]
[1] "싶"

[[2]]
[1] "말" "싶"

[[3]]
[1] "너희" "사진" "도"  

[[4]]
[1] "싶"

[[5]]
[1] "야속" "한"   "시"   "간"  

[[6]]
[1] "나"   "우리" "밉"  

 

 

④ 추출한 명사 list를 문자열 벡터로 변환, 단어별 빈도표 생성

wordcount <- table(unlist(nouns)) # unlist( ) : list -> vector 
head(wordcount);tail(wordcount) # 상위 6개 출력 ; 하위 6개 출력 


- 출력값 - 
         1  100 168  17 
12   2   8   3   1   1 


히   히트     힘   힘겹 힘내잔   힙합 
8      1      10     1      1      1 

 

⑤ 데이터 프레임으로 변환

df_word<-as.data.frame(wordcount,stringsAsFactors = F) 

tail(df_word)
- 출력값 - 
        Var1 Freq
 3078     히    8
 3079   히트    1
 3080     힘   10
 3081   힘겹    1
 3082 힘내잔    1
 3083   힙합    1

stringsAsFactors = F : 문자열 그대로 형변환 없이 출력

stringsAsFactors = T : factor 형으로 출력

 

 

⑥ 변수명 수정 

names(df_word) <- c('word', 'freq')

tail(df_word)
 
- 출력값 -
        word freq
 3078     히    8
 3079   히트    1
 3080     힘   10
 3081   힘겹    1
 3082 힘내잔    1
 3083   힙합    1

 

 

⑦ 상위 20개 내림차순으로 추출 

df_word <- filter(df_word,nchar(word) >= 2) 

top_20 <- df_word %>% arrange(desc(freq)) %>% head(20) # 내림차순으로 정렬(가장 많이 언급된 단어)
top_20

- 출력값 -
  word freq
1   you   89
2    my   86
3   YAH   80
4    on   76
5  하나   75
6  오늘   51
7   and   49
8  사랑   49
9  like   48
10 우리   48
11  the   43
12 시간   39
13 love   38
14   to   38
15   we   36
16   it   33
17   em   32
18  not   32
19 역사   31
20 flex   30

 nchar() :  length  제공 

 

 

⑧ 시각화 

pal <- brewer.pal(8,"Dark2") # Dark2 색상 목록에서 8개 색상 추출.

set.seed(1234)
wordcloud(word=df_word$word, freq = df_word$freq, min.freq = 2, max.words = 200, 
          random.order = F, rot.per = .1, scale = c(4,0.3), colors=pal) 

min.freq = 2 : 두번 이상 언급 된 것 출력 

max.words = 200 : 출력되는 단어 수 200개 까지만

random.order = F  : 가장 많이 언급된 단어 가운데 배치

rot.per = .1 :  단어의 회전각 0.1

scscale = c(4,0.3) : 텍스트 들의 비율 및 크기