아이템 속성 추출하기
이 실습 초반에 생성한 table_in 객체에는 첫 번째 열에 입력된 코드 값이 A인 행들이 잇으며, 이 행들에는 웹사이트의 영역 번호와 해당 영역을 설명하는 간단한 요약정보가 들어있다. 이러한 행들만 따로 추출하기 위해 table_in 객체의 데이터 타입을 data.table형으로 변환하고, 첫 번재 열의 코드 값이 A인 행들만 따로 분리한다.
table_in <- data.table(table_in)
table_items <- table_in[V1 == "A"]
head(table_items)
V1 V2 V3 V4 V5
1: A 1277 1 NetShow for PowerPoint /stream
2: A 1253 1 MS Word Development /worddev
3: A 1109 1 TechNet (World Wide Web Edition) /technet
4: A 1038 1 SiteBuilder Network Membership /sbnmember
5: A 1205 1 Hardware Supprt /hardwaresupport
6: A 1076 1 NT Workstation Support /ntwkssupport
table_item에 포함된 주요한 열은 다음과 같다.
- V2 : 웹사이트 영역 번호
- V4 : 웹사이트 영역 요약 정보
- V5 : 웹사이트 영역 고유 URL 주소
좀 더 명확한 테이블을 만들기 위해 ㅣㅍㄹ요한 열만 추출하고 이름을 다시 부여한다. 도한 웹사이트 영역 번호를 기준으로 테이블을 정렬한다.
table_items <- table_items[, c(2,4,5), with = FALSE]
setnames(table_items, 1:3, c("id", "description", "url"))
table_items <- table_items[order(id)]
head(table_items)
id description url
1: 1000 regwiz /regwiz
2: 1001 Support Desktop /support
3: 1002 End User Produced View /athome
4: 1003 Knowledge Base /kb
5: 1004 Microsoft.com Search /search
6: 1005 Norway /norge
우리는 웹사이트 영역들이 갖는 특징을 살펴봐야 한다. 테이블을 보면 두 가지 범주의 웹사이트 영역이 있는 것을 알 수 있다.
- 마이크로소프트 제품 관련 영역
- 지리적 위치 관련 영역
테이블에서 지리적 위치가 포함된 행을 찾을 수 잇으면, 나머지는 제품과 관련된 영역으로 간줄할 수 있다. 이를 위해 먼저 category라는 이름의 열을 추가하고, 전체 행에 product라는 공통된 값을 부여한다.
table_items[, category := "product"]
앞서 소개한 countrycode 패키지는 대부분의 국가명이 포함된 codelist 객체를 제공한다. codelist 객체를 사용해 국가명이 포함된 name_countries라는 이름의 벡터를 정의한다. 그리고 table_items의 description 열에 있는 값과 name_countries 벡터의 값을 비교해, 값이 일치하는 모든 행을 region 카테고리로 분류한다.
name_countries <- c(codelist$country.name, "Taiwan", "UK", "Russia", "Venezuela",
"Slovenija", "Caribbean", "Netherlands (Holland)", "Europe", "Central America", "MS North Africa")
table_items[description %in% name_countries, category := "region"]
그런데 결과를 자세히 보면 description 열에 국가명과 함게 region이라는 단어가 붙어있는 행들이 있다. 이런 행들은 countrycode 패키지를 이용해 분류해낼 수 없었으므로, grepl 함수를 사용한 정규 표현식을 통해 region 카테고리로 분류한다.
table_items[grepl("Region", description), category := "region"]
head(table_items)
id description url category
1: 1000 regwiz /regwiz product
2: 1001 Support Desktop /support product
3: 1002 End User Produced View /athome product
4: 1003 Knowledge Base /kb product
5: 1004 Microsoft.com Search /search product
6: 1005 Norway /norge product
이제 웹사이트 영역을 각 category별로 몇 개식 분류했는지 확인해본다.
table_items[, list(n_items = .N), by = category]
category n_items
1: product 282
2: region 12
웹 사이트의 약 80%는 제품과 관련한 영역이고, 나머지 20%는 지역에 관한 영역임을 알 수 있다.
이제 드디어, 추천 모델을 만들 준비가 됐다.
모델 만들기
이 절에서는 웹사이트 영역의 내용 정보와 사용자의 조회 정보를 이용해 추천 모델을 만든다. 이 모델은 아이템 기반 협업 필터링(IBCF)과 웹사이트 영역의 내용 정보를 결합한다. 우리는 웹사이트 영역의 특징들을 조합해서 IBCF의 평점 매트릭스에 반영할 것이다. 이 모델은 서로 다른 두 가지 데이터를 통해 만들어진다.
먼저, 3장에서 설명한 방식에 따라 데이터를 학습 데이터와 트레이닝 데이터로 나눈다.
which_train <- sample(x = c(TRUE, FALSE),
size = nrow(ratings_matrix),
replace = TRUE,
prob = c(0.8, 0.2))
recc_data_train <- ratings_matrix[which_train, ]
recc_data_test <- ratings_matrix[!which_train, ]
이제 recommenderlab 라이브러리의 Recommender 함수를 이용해서 IBCF 모델을 만들 수 있다. 평점 매트릭스가 이진(binary)데이터로 이뤄져 있기 때문에 사용자 간 거리 측정 방법을 Jaccard로 지정한다. 자세한 내용은 3장의 '이진 데이터에 대한 협업 필터링' 절에서 설명했다. 나머지 매개변수는 기본값으로 지정한다.
recc_model <- Recommender(data = recc_data_train,
method = "IBCF",
parameter = list(method = "Jaccard"))
IBCF 방식의 추천 시스템은 아이템에 대한 거리 매트릭스를 기반으로 한다. 아이템 간의 거리는 아이템에 대한 조회 정보를 이용해 계산한다. 아이템 간에 같이 구매한 사용자가 많을수록 아이템들이 더 유사하다는 개념이다.
앞서 생성한 모델의 sim 속성에는 웹사이트 영역 간의 거리 매트릭스가 포함돼 있다.
확인해보자.
class(recc_model@model$sim)
[1] "dgCMatrix"
attr(,"package")
[1] "Matrix"
dim(recc_model@model$sim)
[1] 166 166
유사도 매트릭스는 dcCMatrix 클래스에 속하며, 166x166의 정방 매트릭스 형태다. 이를 image 함수를 사용해 시각화해볼 수 있다.
image(recc_model@model$sim)
다음 그림은 위 코드의 결과다.
아직 웹사이트 영역 번호가 정렬되지 않았으므로 명확한 패턴을 발견할 수 없다. 일단 값의 범위를 살펴본다.
range(recc_model@model$sim)
[1] 0 1
모든 거리가 0에서 1 사이인 것을 확인했다.
우리의 목표는 다음 단계를 통해 거리 매트릭스와 웹사이트 영역에 대한 내용 정보를 결합하는 것이다.
- 사용자의 조회 정보를 기반으로 아이템 간의 유사도 매트릭스를 정의한다.
- 웹사이트 영역의 내용 정보를 기반으로 아이템 간의 유사도 매트릭스를 정의한다.
- 두 매트릭스를 결합한다.
먼저 recc_model을 이용해서, 아이템 간의 조회 유사도 매트릭스를 정의할 수 있다. 처음으로 필요한 것은 dgCMatrix 객체를 매트릭스 타입의 데이터로 변환하는 것이다.
dist_rating <- as(recc_model@model$sim, "matrix")
다음으로 웹사이트 영역에 대한 내용 정보를 기반으로 유사도 매트릭스를 만들기 위해 dist함수를 호출한다. 우리는 category 열에 포함된 정보만 사용하므로, 다음과 같은 방법으로 거리를 계산한다.
- 두 웹사이트 영역이 같은 카테고리에 속하면 1을 부여한다.
- 두 웹사이트 영역이 다른 카테고리에 속하면 0을 부요한다.
우리는 거리 매트릭스를 생성했기 때문에 이를 유사도 매트릭스로 변환한다. 거리가 0에서 1 사이이므로, 1 - dist()를 적용해 기준을 바꿔준다.
dist_category <- table_items[, 1 - dist(category == "product")]
class(dist_category)
[1] "dist"
앞서 생성한 dist_category 객체의 클래스는 dist이므로, as 함수를 이용해 매트릭스 형태로 쉽게 변환할 수 있다.
dist_category <- as(dist_category, "matrix")
이제 dist_category 매트릭스의 차원 크기를 dist_ratings 매트릭스와 비교해본다.
dim(dist_category)
[1] 294 294
dim(dist_rating)
[1] 166 166
dist_category 테이블은 모든 웹사이트 영역 간의 유사도 매트릭스를 포함하고 있으므로, 조회 내역이 적은 아이템 등을 제거하고 유사도 매트릭스를 생성한 data_ratings 보다 많은 행과 열이 있다.
dist_category와 dist_ratings를 결합하려면 행과 열의 수가 동일해야 하며, 두 테이블의 정렬 기준이 같아야 한다. 다음 과정을 거쳐서 웹사이트의 영역 번호를 기준으로 두 테이블을 매칭시킬 수 있다.
- 두 매트릭스의 행과 이름과 열 이름에 웹사이트 영역 번호가 들어가 있는지 확인한다.
- dist_ratings에서 행과 열 이름을 추출한다.
- dist_ratings에서 추출한 이름에 따라 dist_category를 정렬하고 일치하는 항목만 추출한다.
dist_ratings테이블에는 이미 행과 열 이름이 들어있다. 앞서 생성한 table_items로부터 웹사이트 영역 번호를 호출해 dist_category 객체의 행과 열 이름에 붙여준다.
rownames(dist_category) <- table_items[, id]
colnames(dist_category) <- table_items[, id]
이제는 dist_ratings에서 웹사이트 영역 번호를 추출해 dist_category에서 같은 번호를 가진 웹사이트 영역만 분리한다.
vector_items <- rownames(dist_rating)
dist_category <- dist_category[vector_items, vector_items]
두 매트릭스가 일치하는지 확인해본다.
identical(dim(dist_category), dim(dist_rating))
[1] TRUE
identical(rownames(dist_category), rownames(dist_rating))
[1] TRUE
identical(colnames(dist_category), colnames(dist_rating))
[1] TRUE
모든 것이 같다. dist_category의 값을 그림을 통해 다시 살펴본다.
image(dist_category)
다음 그림은 위 코드의 결과다.
매트릭스에는 0 또는 1의 값만 들어있고, 웹사이트 영역은 두 개의 카테고리로만 분류되므로 명확한 패턴을 발견할 수 있다. 또한 매트릭스가 대칭적이다.
이제 두 테이블을 결합해야 하며, 결합 방식으로는 두 매트릭스 간 평점의 가중평균을 이용한다. dist_category 매트릭스에서는 아이템끼리 카테고리가 일치하는지만 고려했으므로 가중치를 비교적 낮게 잡는 것이 좋다. 예를 들어 가중치를 25%로 설정한다.
weight_category <- 0.25
dist_tot <- dist_category * weight_category + dist_rating * (1 - weight_category)
그림을 사용해 dist_tot 매트릭스를 살펴본다.
image(dist_tot)
다음 그림은 위 코드의 결과다.
매우 유사한 아이템을 나타내는 점들이 보인다. 게다가 배경에서 dist_category의 패턴을 볼 수 있다.
이제 recc_model 내에 새 유사도 매트릭스를 포함시킬 수 있다. 이를 위해 dist_tot 객체의 데이터 타입을 dgCMatrix로 변환하고 recc_model에 삽입한다.
recc_model@model$sim <- as(dist_tot, "dgCMatrix")
다음 글에서 계속 작성하겠습니다.
'R > R로 만드는 추천 시스템' 카테고리의 다른 글
사례 연구 : 나만의 추천 시스템 만들기 - 04 (0) | 2020.04.03 |
---|---|
사례 연구 : 나만의 추천 시스템 만들기 - 03 (0) | 2020.04.01 |
사례 연구 : 나만의 추천 시스템 만들기 - 01 (0) | 2020.03.30 |
추천 시스템의 평가 - 04 (0) | 2020.03.29 |
추천 시스템의 평가 - 03 (0) | 2020.03.24 |