최근 텍스트 마이닝을 통한 SNA 분석이 유행인듯 해서 예제 하나를 공유하고자 한다.
이 예제는 모 대학교 교수님이 코드 얼개를 부탁해서 만들어본 코드 조각이다(도와 드릴 때 공개 가능에 대해서 이미 말씀을 드렸으니 문제 없으리라 본다).
여타 다른 텍스트 마이닝 툴에서 SNA를 하는것의 원리에 대해서는 잘 모르지만 대략 예상을 해보자면 한 문장에서 나오는 단어들의 관계를 연상하면 될거 같다는 생각을 해본다. 그리고 이들간의 관련도 동시성을 SNA그래프를 통해서 표현하면 그만이다.
원리상으로 두 단어 사이의 조건부 확률(confidence), 쌍 출현 확률(support)의 개념으로 보자면 association rule을 활용하면 될 거란 생각을 해본다.
따라서 문장에서 단어들을 추출하기 위해 내가 만든 KoNLP 패키지를 사용하고, arules는 연관분석을 위해 사용한다. 그리고 중요한 SNA 그래프는 igraph 패키지를 통해서 출력한다. 전부터 이야기 했지만 대부분 예상하는 기능을 가지는 패키지는 모두 R에 존재한다고 생각하면 되고 이를 어떻게 적재 적소에 배치해서 활용하는지는 사용자의 몫이다. ^^;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | library(KoNLP) library(arules) library(igraph) library(combinat) f <- file("다문화_utf8.txt", encoding="UTF-8") fl <- readLines(f) close(f) tran <- Map(extractNoun, fl) tran <- unique(tran) tran <- sapply(tran, unique) tran <- sapply(tran, function(x) {Filter(function(y) {nchar(y) <= 4 && nchar(y) > 1 && is.hangul(y)},x)} ) tran <- Filter(function(x){length(x) >= 2}, tran) names(tran) <- paste("Tr", 1:length(tran), sep="") wordtran <- as(tran, "transactions") #co-occurance table wordtab <- crossTable(wordtran) ares <- apriori(wordtran, parameter=list(supp=0.05, conf=0.05)) inspect(ares) rules <- labels(ares, ruleSep=" ") rules <- sapply(rules, strsplit, " ", USE.NAMES=F) rulemat <- do.call("rbind", rules) # ares <- apriori(wordtran, parameter=list(supp=0.05, conf=0.05)) # inspect(ares) # rules <- labels(ares, ruleSep="/", setStart="", setEnd="") # rules <- sapply(rules, strsplit, "/", USE.NAMES=F) # rules <- Filter(function(x){!any(x == "")},rules) # rulemat <- do.call("rbind", rules) # rulequality <- quality(ares) # ruleg <- graph.edgelist(rulemat,directed=F) #plot for important pairs ruleg <- graph.edgelist(rulemat[-c(1:16),],directed=F) plot.igraph(ruleg, vertex.label=V(ruleg)$name, vertex.label.cex=0.5, vertex.size=20, layout=layout.fruchterman.reingold.grid) #plot for all pairs # tranpairs <- sapply(tran, function(x){t(combn(x,2))}) # sapply(tran,function(x){x }) # edgelist <- do.call("rbind", tranpairs) # edgelist <- unique(edgelist) # g <- graph.edgelist(edgelist, directed=F) # plot(g) |
소스 코드는 위와 같다. 입력되는 데이터는 한 라인에 한 문장에 있는 파일이면 된다. 내 경우에는 아래와 같은 내용의 파일을 활용했다.
1 2 3 4 5 6 7 | > head(fl) [1] "한국·중국·베트남의 다문화 사회 인식 비교 분석" [2] "연구논문 : 다문화사회의 법적 기반에 관한 소고 -국제인권법을 중심으로-" [3] "다문화 공생의 정치원리로서 아렌트주의(Arendtianism)" [4] "전북지역 다문화가족 어린이의 구강건강 실태조사" [5] "특집 : 다문화 가정 상담" [6] "한국 문화 콘텐츠 개발의 필요성과 방향" |
물론 arules에서 룰 분석을 위해서 co-occurance table을 만들고 이에 대한 코드도 19번째 라인에 있다. 테이블을 보고 싶다면 이를 출력해 보면 된다.
그리고 이런 SNA 결과가 있으면 여러 중심성 측도에 대해서 알아볼 수 있는데, 근접 중심성(closeness)에 대해서 알아보면 아래와 같다.
1 2 3 4 | closen <- closeness(ruleg) plot(closen, col="red",xaxt="n", lty="solid", type="b", xlab="단어", ylab="closeness") points(closen, pch=16, col="navy") axis(1, seq(1, length(closen)), V(ruleg)$name, cex=5) |
예상 했던대로 ‘다문화’라는 단어의 중심성이 높게 나타난다. 그리고 관계 중심성(betweenness)을 구해도 역시 크게 다르지 않다. 만일 network star가 두 개 이상 존재한다면 관계 중심성을 알아보는게 더 효과적일 수 있다.
페이지 랭크도 역시 구해볼 수 있지만 네트워크가 작은지라 역시 생략하겠다.
다시 한번 언급하지만, R은 4000여개 가까이 되는 패키지를 어떻게 활용하는지가 관건이며, 그리고 여러 패키지를 유기적으로 연결하기 위해서는 R 문법에 대한 깊이 이는 이해, 플로팅 문법 등 여타 백 그라운드 지식이 필수적이란 생각이 든다.
텍스트 마이닝을 통한 SNA by from __future__ import dream is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.