R을 이용한 검색 랭킹과 검색 클러스터링 초간단 구현

KoNLP와 같이 쓰면 정말 좋은 R 패키지중에 tm이라는 아주 좋은 패키지가 있다. R에서 텍스트 분석을 한다면 이 패키지를 반드시 쓰게 되어 있다.

이 패키지의 가장 큰 장점은 텍스트를 숫자로 표현하는 대표적인 방법인 Term Document Matrix를 만들어 준다는 것이다. 이것으로 뭘 할지는 이후의 분석에 달려 있겠지만 일단 숫자로 변환된 텍스트는 다른 어떤 R패키지들을 활용하든지 적절한 통계적 분석 및 활용이 가능해지는 장점을 가진다.

이번 포스팅은 아주 작은 크기의 한글 검색 랭킹을 만들어 볼 것이다. 아마도 검색엔진의 랭킹이 어떻게 동작하는지 그 과정을 확인하는 작은 예제가 될 것 같다는 생각을 해본다.

얼마전에 r-bloggers에서 이번 주제와 상당히 유사한 영문 포스팅을 본것 같은데, 아마도 이 글을 쓴 중요한 동기가 되지 않았나 싶다.

배경 지식으로는 cosine 유사도에 대한 것이 전부이다. 이는 벡터스페이스 랭킹 모델을 사용할 거라는 의미이며, 자세한 내용은 관련 위키를 참고하길 바란다.

library(tm)
library(KoNLP)

docs <- 
    c("사랑은 달콤한 꽃이나 그것을 따기 위해서는 무서운 벼랑 끝까지 갈 용기가 있어야 한다.", 
    "진실한 사랑의 실체는 믿음이다.",
    "눈물은 눈동자로 말하는 고결한 언어.",
    "친구란 두 사람의 신체에 사는 하나의 영혼이다.",
    "흐르는 강물을 잡을수 없다면, 바다가 되어서 기다려라.",
    "믿음 소망 사랑 그중에 제일은 사랑이라.",
    "가장 소중한 사람은 가장 사랑하는 사람이다.",
    "사랑 사랑 사랑")

#편의상 검색어도 넣어준다. 
query <- "믿음을 주는 사랑"

names(docs) <- paste("doc", 1:length(docs), sep="")
docs <- c(docs, query=query)
docs.corp <- Corpus(VectorSource(docs))

#색인어 추출함수 
konlp_tokenizer <- function(doc){
  extractNoun(doc)
}

# weightTfIdf 함수 말고 다른 여러 함수들이 제공되는데 관련 메뉴얼을 참고하길 바란다. 
tdmat <- TermDocumentMatrix(docs.corp, control=list(tokenize=konlp_tokenizer,
                                                    weighting = function(x) weightTfIdf(x, TRUE),
                                                    wordLengths=c(1,Inf)))

tdmatmat <- as.matrix(tdmat)

# 벡터의 norm이 1이 되도록 정규화 
norm_vec <- function(x) {x/sqrt(sum(x^2))}
tdmatmat <- apply(tdmatmat, 2, norm_vec)

# 문서 유사도 계산 
docord <- t(tdmatmat[,9]) %*% tdmatmat[,1:8]

#검색 결과 리스팅 
orders <- data.frame(docs=docs[-9],scores=t(docord) ,stringsAsFactors=FALSE)
orders[order(docord, decreasing=T),]
##                                                                                     docs  scores
## doc6                                              믿음 소망 사랑 그중에 제일은 사랑이라. 0.38638
## doc8                                                                      사랑 사랑 사랑 0.34624
## doc2                                                      진실한 사랑의 실체는 믿음이다. 0.33481
## doc7                                          가장 소중한 사람은 가장 사랑하는 사람이다. 0.03595
## doc1 사랑은 달콤한 꽃이나 그것을 따기 위해서는 무서운 벼랑 끝까지 갈 용기가 있어야 한다. 0.02848
## doc3                                                 눈물은 눈동자로 말하는 고결한 언어. 0.00000
## doc4                                       친구란 두 사람의 신체에 사는 하나의 영혼이다. 0.00000
## doc5                                흐르는 강물을 잡을수 없다면, 바다가 되어서 기다려라. 0.00000

검색 결과 클러스터링

검색 결과를 스코어별로 클러스터링 하게 된다면 어떻게 표현될까?
아마도 아래 플로팅 결과가 그 힌트가 되지 않을까 한다. 물론 아래 함수는 유클리드언 거리를 클러스터링 하는데 사용했음에 유의하길 바란다.

fit <- hclust(dist(t(tdmatmat)), method = "ward")
plclust(fit)
rect.hclust(fit, k = 5)

plot of chunk unnamed-chunk-3

CC BY-NC 4.0 R을 이용한 검색 랭킹과 검색 클러스터링 초간단 구현 by from __future__ import dream is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.