본문 바로가기

R/R로 만드는 추천 시스템

사례 연구 : 나만의 추천 시스템 만들기 - 03

반응형

앞서 봤듯이, 이제 predict 함수를 사용해 아이템을 추천할 수 있다.

 

recc_predicted <- predict(object = recc_model,
                          newdata = recc_data_test,
                          n = n_recommended)

 

recc_predicted의 itemLabels 슬롯에는 아이템 이름, 즉 웹사이트 영역 번호가 들어있다.

 

head(recc_predicted@itemLabels)
[1] "1038" "1026" "1034" "1008" "1056" "1032"

 

웹사이트 영역에 대한 설명을 표시하기 위해 table_items 객체를 사용할 수 있다. itemLabels에 포함된 번호들과 동일하게 table_items를 정렬하는 것이다. 이를 위해 웹사이트 영역 번호가 포함된 data.frame을 생성하고, table_items 테이블과 조인시킨다. 다음 단계를 통해 확인해본다.

  1. 웹사이트 영역 번호 열을 갖는 데이터 프레임을 생성한다.
  2. table_labels와 table_items를 왼쪽 테이블 기준 결합(LEFT JOIN)한다. sort = FALSE로 지정함으로써 정렬 순서를 동일하게 둔다.
  3. description 열의 데이터 타입을 factor형에서 character형으로 변환한다.
table_labels <- data.frame(id = recc_predicted@itemLabels)
table_labels <- merge(table_labels, table_items,
                      by = "id", all.x = TRUE, all.y = FALSE,
                      sort = FALSE)
descriptions <- as(table_labels$description, "character")

 

이제 table_labels를 살펴본다.

head(table_labels)
    id                               description          url category
1 1038            SiteBuilder Network Membership   /sbnmember  product
2 1026 Internet Site Construction for Developers /sitebuilder  product
3 1034                         Internet Explorer          /ie  product
4 1008                            Free Downloads  /msdownload  product
5 1056                                    sports      /sports  product
6 1032                                     Games       /games  product

 

이제 우리는 추천하고자 하는 웹사이트 영역을 뽑을 수 있다. 예를 들어 첫 번째 사용자에 대한 추천 영역을 뽑아보자.

recc_user_1 <- recc_predicted@items[[1]]
items_user_1 <- descriptions[recc_user_1]
head(items_user_1)
[1] "Support Desktop"                          
[2] "Internet Explorer"                        
[3] "Knowledge Base"                           
[4] "Microsoft.com Search"                     
[5] "Products "                                
[6] "Internet Site Construction for Developers"

 

이제 모든 사용자에 대한 추천 웹사이트 영역이 정리된 테이블을 만들 수 있다. 각 열은 사용자에 해당하고 각 행은 추천 영역에 해당한다. n_recommended를 10으로 설정하면 테이블은 10개의 행을 갖게 된다. 이를 위해 sapply 함수를 사용함으로써 recc_predicted@items의 각 요소에 대한 descriptions를 식별한다.

 

그러나 사용자당 추천 웹사이트 영역의 수는 한 개에서 10개 사이며, 사용자마다 개수가 다르다. 10개의 행이 있는 구조화된 테이블을 정의하려면 각 사용자에 대해 같은 수의 값이 필요하다. 따라서 빠진 개수만큼의 추천 영역은 빈 문자열로 대체한다. 빈 문자열로 대체하는 작업은 빈 문자열을 rep 함수로 복제해 수행한다.

 

recc_matrix <- sapply(recc_predicted@items, function(x){
  recommended <- descriptions[x]
  c(recommended, rep("", n_recommended - length(recommended)))
})
dim(recc_matrix)
[1]  10 198

 

처음 세 사용자에 대한 추천 결과를 살펴본다.

 

head(recc_matrix[, 1:3])
     10047                                       10089                                       10129                                      
[1,] "Support Desktop"                           "Free Downloads"                            "Internet Explorer"                        
[2,] "Internet Explorer"                         "Microsoft.com Search"                      "Windows Family of OSs"                    
[3,] "Knowledge Base"                            "Windows95 Support"                         "Products "                                
[4,] "Microsoft.com Search"                      "Windows Family of OSs"                     "Windows95 Support"                        
[5,] "Products "                                 "Products "                                 "Internet Site Construction for Developers"
[6,] "Internet Site Construction for Developers" "Internet Site Construction for Developers" "SiteBuilder Network Membership"  

 

추천된 웹사이트 영역을 보면, Products와 Internet Site Construction for Developers 가 세 사람에게 공통으로 추천된 것을 알 수 있다. 따라서 몇몇 영역은 추천될 확률이 더 높으리라 추정해볼 수 있다.

 

3장. '추천 시스템'에서 했던 것처럼 결과를 탐색해본다. 각 영역이 사용자들에게 몇 번 추천됏는지 확인해볼 수 있다.

 

table_recomm_per_item <- table(recc_matrix)
recomm_per_item <- as(table_recomm_per_item, "numeric")

 

결과를 시각화하기 위해 cut 함수를 사용해 구간 단위로 묶어준다.

 

bin_recomm_per_item <- cut(recomm_per_item, breaks = c(0, 10, 20, 100, max(recomm_per_item)))

 

qplot을 사용하면 recomm_per_item의 분포를 시각화할 수 있다.

 

qplot(bin_recomm_per_item) + ggtitle("Recommendations per item")

다음 그림은 웹사이트 영역의 추천 수를 표시한다.

대부분은 10번 이하로 추천됐으며, 일부 영역은 100번 이상 추천됐다. 즉, 롱테일 분포를 따르고 있다.

또한 우리는 recomm_per_item을 정렬해 가장 인기 있는 추천 영역을 확인할 수 있다.

 

recomm_per_item_sorted <- sort(table_recomm_per_item, decreasing = TRUE)
recomm_per_item_top <- head(recomm_per_item_sorted, n = 4)
table_top <- data.frame(name = names(recomm_per_item_top),
                        n_recomm = recomm_per_item_top)
table_top[, c(1,3)]
                   name n_recomm.Freq
1     Internet Explorer           126
2 Windows Family of OSs           125
3  Microsoft.com Search           118
4     Windows95 Support           118

 

이 장에서는 하이브리드 추천 모델을 만들고 탐색해봤다. 다음 단계는 만들어본 추천 모델을 평가하고 매개변수를 최적화하는 것이다.

 

모델 평가 및 최적화

이 장에서는 추천 시스템의 성능을 평가하는 방법을 설명한다. 모델을 평가하는 것부터 시작해서, 매개변수를 조정하고 최고의 성능을 내는 매개변수의 선택 과정을 다룰 것이다. 자세한 내용은 전 글 '추천 시스템의 평가'를 참고한다.

 

다음 모델을 평가하고 최적화하는 과정이다.

  • 주어진 매개변수를 조정해 모델을 평가하는 함수를 생성한다.
  • 함수를 사용해 매개변수를 다양하게 조정하면서 테스트하고, 최고 성능을 내는 설정을 찾는다.

이러한 단계를 자세히 살펴본다.

 

모델을 평가하는 함수 만들기

이 절에서는 다음과 같은 기능을 하는 함수를 정의할 것이다.

  1. k-fold를 사용해 교차 검증을 할 수 있도록 설정한다.
  2. 하이브리드 IBCF를 만든다.
  3. 테스트 세트의 사용자에게 아이템을 추천한다.
  4. 추천 결과를 평가한다.

함수의 입력 데이터는 다음과 같다.

  • 데이터 : 웹사이트 영역의 내용 정보를 결합해서 만든 평점 매트릭스
  • k-fold 매개변서 : K 겹의 수, 테스트 데이터 세트에 포함할 아이템의 수
  • 모델 매개변수 : 최근접 이웃의 수, 아이템 설명 정보 기반 거리에 대한 가중치, 추천할 아이템 개수

이제 함수의 인자들을 정의해본다. 인자 옆에 주석으로 설명을 추가했다.

evaluateModel <- function(
  # 입력데이터
  ratings_matrix, # 평점 매트릭스(rating matrix)
  table_items, # 아이템 설명 정보 테이블
  #K-fold 매개변수
  n_fold = 10, # 겹의 개수
  items_to_keep = 4, # TEST 데이터 세트에 포함할 아이템 개수
  # 모델 매개변수
  number_neighbors = 30, # 최근접 이웃의 수
  weight_description = 0.2, # 아이템 설명 정보 기반 거리에 대한 가중치
  items_to_recommend = 10 # 추천 아이템의 개수
){
  # 평가 (evalueate) 모델 파트
}

 

이제 함수의 바디에 들어갈 내용을 단계별로 살펴본다. 좀 더 자세한 설명을 위해 이전 글 '추천 시스템의 평가'를 참조할 수 있다.

 

1. 먼저 evaluationScheme 함수를 사용해 k-fold를 설정한다. 매개변수 k와 given은 각각 n_fold와 items_to_keep에 입력된 조건에 따라 설정된다. set.seed(1) 명령은 예제를 재현할 수 있게 하기 위해 입력한다. 즉, set.seed(1)을 지정하면 명령어를 반복 수행했을 때 임의의 구성 요소들이 동일하게 적용된다.

 

set.seed(1)
eval_sets <- evaluationScheme(data = ratings_matrix,
                              method = "cross-validation",
                              k = n_fold,
                              given = items_to_keep)

 

2. 그다음에는 Recommender 함수를 사용해 거리 계산 방법을 Jaccard로 정의하고, k 인자를 최근접 이웃의 숫자로 정의하는 IBCF 모델을 만든다.

recc_model <- Recommender(data = getData(eval_sets, "train"),
                          method = "IBCF",
                          parameter = list(method = "Jaccard",
                                           k = number_neighbors))

 

3. 이제 모델에서 평점 기반 거리 매트릭스를 추출한다.

 

dist_ratings <- as(recc_model@model$sim, "matrix")
vector_items <- rownames(dist_ratings)

 

4. table_items 입력으로부터 아이템 설명 정보 기반 거리 매트릭스도 정의한다.

 

dist_category <- table_items[, 1 - as.matrix(dist(category == "product"))]
rownames(dist_category) <- table_items[, id]
colnames(dist_category) <- table_items[, id]
dist_category <- dist_category[vector_items, vector_items]

 

5. dist_ratings와 dist_category를 조합해 거리 매트릭스를 정의한다. 조합은 가중 평균을 사용하며, 가중치는 weight_description 입력 값에 의해 정의한다.

 

dist_tot <- dist_category * weight_description + dist_ratings * (1 - weight_description) 
recc_model@model$sim <- as(dist_tot, "dgCMatrix")

 

6. recc_model을 이용해서 테스트 세트의 사용자들에 대해 예측한다. 우리는 0과 1의 평점만을 가진 테이블을 사용하기 대문에 type = "topNList" 인수로 상위 n개의 추천 아이템을 구하도록 지정할 수 있다. 추천 아이템 수를 정의하는 인수 n은 items_to_recommended 입력으로 정의한다.

 

eval_prediction <- predict(object = recc_model,
                           newdata = getData(eval_set, "known"),
                           n = items_to_recommend,
                           type = "topNList")

 

7. calcPredictionAccuracy() 를 사용해 모델 성능을 평가한다. byUser = FALSE를 지정해 정확도와 재현력 같은 평균적인 지표를 구한다.

 

eval_accuracy <- calcPredictionAccuracy(x = eval_prediction,
                                        data = getData(eval_sets, "unknown"),
                                        byUser = FALSE,
                                        given = items_to_recommend)

 

8. 함수의 출력 값은eval_accuracy 테이블이 된다.

return(eval_accuracy)

 

9. 이제 함수를 테스트해본다.

model_evaluation <- evaluateModel(ratings_matrix = ratings_matrix,
                                  table_items = table_items)
model_evaluation
          TP           FP           FN           TN    precision       recall          TPR          FPR 
  1.68269231   8.31730769   1.04807692 144.95192308   0.16826923   0.67772057   0.67772057   0.05416236 

 

지표에 대한 자세한 설명은 '추천 시스템의 평가'에서 확인할 수 있다.

이 절에서는 주어진 설정을 통해 모델을 평가하는 함수를 정의했다. 이 함수는 매개변수 최적화에 도움을 줄 것이다.

반응형