Los sistemas recomendadores se agrupan en 2 grandes grupos:
Content based: toman en cuenta el contexto y características tanto de los usuarios como los ítems. Ej: modelos de clasificación para saber si un usuario elegirá o no una película en base a sus características, las características de la película y el comportamiento pasado del usuario.
Collaborative Filtering: modelos basados exclusivamente en el comportamiento de los usuarios con respecto a los ítems. Ej: rating dado por parte de los usuarios a las películas. Se pueden utilizar los ratings para encontrar usuarios (o películas) similares para recomendar en base a la similitud.
Recommenderlab es un paquete de R que entrega un framework de trabajo y evaluación de modelos recomendadores del tipo Collaborative Filtering.
En este documento se probarán los siguientes algoritmos incluidos en el paquete:
Cargamos los paquetes
library(recommenderlab)
library(dplyr)
El objeto que utiliza recommenderlab para entrenar los modelos son matrices usuario-ítem que pueden ser de tipo realRatingMatrix o binaryRatingMatrix
Esto se puede realizar a partir de una matriz ya creada o a partir de un data.frame con las con 3 columnas en orden: user | item | rating
df <- read.csv("datasets/ratings.csv")
df$timestamp <- NULL
head(df)
## userId movieId rating
## 1 1 1 4
## 2 1 3 4
## 3 1 6 4
## 4 1 47 5
## 5 1 50 5
## 6 1 70 3
Para crear el objeto de clase realRatingMatrix se utiliza la función as.
ui <- df %>% as("realRatingMatrix")
ui[1:10,1:10] %>% getRatingMatrix
## 10 x 10 sparse Matrix of class "dgCMatrix"
## [[ suppressing 10 column names '1', '2', '3' ... ]]
##
## 1 4.0 . 4 . . 4 . . . .
## 2 . . . . . . . . . .
## 3 . . . . . . . . . .
## 4 . . . . . . . . . .
## 5 4.0 . . . . . . . . .
## 6 . 4 5 3 5 4 4 3 . 3
## 7 4.5 . . . . . . . . .
## 8 . 4 . . . . . . . 2
## 9 . . . . . . . . . .
## 10 . . . . . . . . . .
Una matriz realRatingMatrix se puede parsear tanto a matrix, data.frame o list.
ui %>% as("matrix") %>% .[1:10,1:10]
## 1 2 3 4 5 6 7 8 9 10
## 1 4.0 NA 4 NA NA 4 NA NA NA NA
## 2 NA NA NA NA NA NA NA NA NA NA
## 3 NA NA NA NA NA NA NA NA NA NA
## 4 NA NA NA NA NA NA NA NA NA NA
## 5 4.0 NA NA NA NA NA NA NA NA NA
## 6 NA 4 5 3 5 4 4 3 NA 3
## 7 4.5 NA NA NA NA NA NA NA NA NA
## 8 NA 4 NA NA NA NA NA NA NA 2
## 9 NA NA NA NA NA NA NA NA NA NA
## 10 NA NA NA NA NA NA NA NA NA NA
ui %>% as("data.frame") %>% head
## user item rating
## 1 1 1 4
## 326 1 3 4
## 434 1 6 4
## 2108 1 47 5
## 2380 1 50 5
## 2860 1 70 3
Se puede binarizar una matriz, con binarize y entregando un mínimo ratig para evaluar la transformación.
ui_bin <- ui %>% binarize(minRating = 4)
ui_bin[1:10,1:10] %>% as("matrix")
## 1 2 3 4 5 6 7 8 9 10
## 1 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## 2 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 3 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 4 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 5 TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 6 FALSE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE FALSE
## 7 TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 8 FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 9 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 10 FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
Las matrices realRatingMatrix aceptan operaciones matriciales como rowSums, rowMeans, dim, indexar, etc.
Por ejemplo,a continuación se muestra el rating promedio de la primera película:
colMeans(ui[,1])
## 1
## 3.92093
La función normalize permite normalizar con los métodos “center” y “Z-score” tanto filas como columnas (row = FALSE).
ui %>% getRatings %>% hist(main = "Ratings")
ui %>% normalize %>% getRatings %>% hist(main = "Rating normalizados por usuario")
Para ejemplificar crearemos un recomendador de popularidad utilizando los primeros 600 usuarios y predeciremos el top 5 para los siguientes 2 usuarios.
rec_pop <- Recommender(ui, "POPULAR")
pred_pop <- predict(rec_pop, ui[601:602], type = "topNList", n = 5)
Para entrenar un modelo, siempre se utiliza la función Recommender, se le entrega la data de entrenamiento y el tipo de modelo a utilizar. Para ver el listado de modelos y parámetros se pueden consultar con recommenderRegistry$grep_entries().
La función predict funciona como con cualquier otro modelo, pero además se le debe decir qué retornar (“topNList” o “ratings”). En caso de retornar topNList se requiere ingresar el número n.
Para ver los resultados, se puede desplegar una lista como a continuación:
pred_pop %>% as("list")
## $`601`
## [1] "356" "296" "260" "593" "1196"
##
## $`602`
## [1] "2571" "2959" "1196" "858" "1198"
En la evaluación por rating, se busca predecir el rating que los usuarios asignarán a los ítems, es por esto que se mide con métricas de error para regresiones como RMSE, o el MAE.
La idea acá es no entregar mucho ruido al modelo, por lo que en primer lugar se verá cuál es el mínimo de películas rankiadas por usuario y el mínimo de ratings que tiene una película.
# Mínimo de ratings por usuario
rowCounts(ui) %>% as("matrix") %>% min
## [1] 20
# Mínimo de ratings por película
colCounts(ui) %>% as("matrix") %>% min
## [1] 1
El mínimo de ratings por usuarios es 20, mientras que el mínimo de ratings por película es 1, es decir hay al menos una película que sólo 1 usuario la rankeó. Para eliminar ruido en el modelo estableceremos el mínimo de ratings por película de 10.
ui <- ui[,colCounts(ui)>= 20]
Con la finalidad de realizar una evaluación de modelos, se realizará un split de 90% train y 10% test.
eval_scheme <- evaluationScheme(ui, method = "split", train = 0.9, given = 5)
Debido a que se predicen ratings de ítems en base a ratings sobre otros ítems que haya realizado el usuario, se debe asumir como “conocidos” solo una parte de los ratings. Esto está dado por el parámetro given. (En caso de que given sea negativo, representa “todos menos n”)
Luego, con getData se obtienen los siguientes datos:
train <- eval_scheme %>% getData("train")
known <- eval_scheme %>% getData("known")
unknown <- eval_scheme %>% getData("unknown")
Se entrenan diferentes recomendadores utilizando la data train
r1 <- Recommender(train, "RANDOM")
r2 <- Recommender(train, "UBCF")
r3 <- Recommender(train, "IBCF")
r4 <- Recommender(train, "SVD")
r5 <- Recommender(train, "ALS")
En este caso a la función predict es de tipo “ratings” ya que se está prediciendo el rating con el que el usuario valorará un ítem. La predicción se debe realizar utilizando la data know.
p1 <- predict(r1, known, type = "ratings")
p2 <- predict(r2, known, type = "ratings")
p3 <- predict(r3, known, type = "ratings")
p4 <- predict(r4, known, type = "ratings")
p5 <- predict(r5, known, type = "ratings")
Para calcular las métricas de error (MAE, MRSE, MSE) sólo es necesario utilzar la función calcPredictionAccuracy. Para calcular el error de la prediccin se ocupa la dara unknown
error <- rbind("random" = calcPredictionAccuracy(p1, unknown),
"ubcf" = calcPredictionAccuracy(p2, unknown),
"ibcf" = calcPredictionAccuracy(p3, unknown),
"svd" = calcPredictionAccuracy(p4, unknown),
"als" = calcPredictionAccuracy(p5, unknown))
error
## RMSE MSE MAE
## random 1.2843928 1.6496648 0.9736144
## ubcf 1.0972598 1.2039790 0.8512779
## ibcf 1.4058584 1.9764379 0.9993613
## svd 1.0491321 1.1006782 0.8067503
## als 0.9703985 0.9416733 0.7628789
La evaluación de predicción según topN predice el top de ítems que el usuario preferirá, pero la evaluación se realiza utilizando los ratings, por lo tanto es necesario establecer un criterio para los ratings para saber si el usuario lo prefiere o no.
En este ejemplo, dado que son ratings de películas de 1 a 5, se establecerá un buen rating mayor o igual a 4.
eval_scheme <- evaluationScheme(ui, method = "split", train = 0.9, given = 5, goodRating = 4)
algos <- list("random" = list(name = "RANDOM", param = NULL),
"UBCF_10nn" = list(name = "UBCF", param = list(nn = 10)),
"UBCF_50nn" = list(name = "UBCF", param = list(nn = 50)),
"IBCF_Pearson" = list(name = "IBCF", param = list(method = "Pearson")),
"SVD" = list(name = "SVD"),
"ALS" = list(name = "ALS"),
"ALS_5" = list(name = "ALS", param = list(n_factors = 5)))
Se evaluarán los algoritmos para n = 1,3,5,10,15,20. La función eval entrena los algoritmos, predice y entrega la evaluación para todos los algoritmos.
eval <- evaluate(eval_scheme, algos, type = "topNList", n = c(1,3,5,10,15,20))
## RANDOM run fold/sample [model time/prediction time]
## 1 [0sec/0.17sec]
## UBCF run fold/sample [model time/prediction time]
## 1 [0sec/0.55sec]
## UBCF run fold/sample [model time/prediction time]
## 1 [0.02sec/0.67sec]
## IBCF run fold/sample [model time/prediction time]
## 1 [18.41sec/0.03sec]
## SVD run fold/sample [model time/prediction time]
## 1 [0.15sec/0.1sec]
## ALS run fold/sample [model time/prediction time]
## 1 [0sec/60.04sec]
## ALS run fold/sample [model time/prediction time]
## 1 [0sec/58.89sec]
Luego, se puede graficar la curva ROC y un gráfico Precision / Recall
plot(eval)
plot(eval,"prec/rec")
getConfusionMatrix(eval[["SVD"]])
## [[1]]
## TP FP FN TN precision recall TPR
## 1 0.2459016 0.7540984 56.52459 1234.475 0.2459016 0.00479640 0.00479640
## 3 0.6393443 2.3606557 56.13115 1232.869 0.2131148 0.01320815 0.01320815
## 5 1.0983607 3.9016393 55.67213 1231.328 0.2196721 0.02501414 0.02501414
## 10 1.7540984 8.2459016 55.01639 1226.984 0.1754098 0.03595916 0.03595916
## 15 2.2950820 12.7049180 54.47541 1222.525 0.1530055 0.04858423 0.04858423
## 20 2.8524590 17.1475410 53.91803 1218.082 0.1426230 0.05892988 0.05892988
## FPR
## 1 0.0006086475
## 3 0.0019038136
## 5 0.0031398981
## 10 0.0066299250
## 15 0.0102382183
## 20 0.0138209165
Los links que pongo a continuación son los links de donde recaudé información, código, ejemplos, etc.