Contexto
Los sistemas de recomendación son herramientas y algoritmos diseñados
para sugerir productos, servicios, información o contenido a los
usuarios, basándose en sus preferencias y comportamientos previos,
existen dos tipos de sistemas de recomendaicones principales:

- Sistema Basado en Contenido
** Recomienda cosas similares a lo que ya te ha gustado. Por ejemplo, si
te gusta una película de acción, te sugiere otras películas del mismo
género.
** Ejemplo: Netflix te recomienda series y películas basadas en lo que
has visto.
- Sistema Colaborativo
** Recomienda basándose en lo que les ha gustado a personas similares a
ti, sin importar las características del contenido.
** Ejemplo: Facebook sugiere amigos o páginas basadas en tus
amigos.
Actividad
Durante esta actividad se realizará un sistema de recomendaciones
colaborativo en el que asignaremos ponderación con respecto a las
similitudes entre los gustos de las personas para poder recomendar
películas con alta probabildiad de que les gusten a los usuarios.
library(tidyverse)
library(recommenderlab)
Paso 1
1.- Crear la matriz
movie_ratings_tarea <- data.frame(
KP1 = c(5, 4, 5, 4),
ENREDADOS = c(4, 5, 4, NA),
UP = c(5, 4, 5, 2),
CARS1 = c(4, 5, 3, NA),
TS3 = c(3, 5, 3, 2),
SHREK2 = c(3, 5, 4, 3),
MONJA = c(3, NA, 3, NA)
)
rownames(movie_ratings_tarea) <- c('Diego','Lalo', 'Ale', 'You' )
movie_ratings_tarea
## KP1 ENREDADOS UP CARS1 TS3 SHREK2 MONJA
## Diego 5 4 5 4 3 3 3
## Lalo 4 5 4 5 5 5 NA
## Ale 5 4 5 3 3 4 3
## You 4 NA 2 NA 2 3 NA
Paso 2
Proceso de matrices:
Durante esta parte del proceso se crean un vector a cada usuario con
respecto a las calificaciones que les asignaron a cada una de las
películas, después se grafican los vectores y finalmente se calculan las
distancias entre ellos para encontrar la mayor similitud entre usuarios,
a menor distancia mayor similitud de gustos.
cosine_similarity <- function(vec_1, vec_2) {
vec_len <- length(vec_1)
# NA values are replaced with 0
vec_1[is.na(vec_1)] <- 0
vec_2[is.na(vec_2)] <- 0
# Computing the denominator
vec_1_denom <- sqrt(sum(vec_1^2))
vec_2_denom <- sqrt(sum(vec_2^2))
denominator <- vec_1_denom * vec_2_denom
# Computing the numerator
tib = tibble(vec_1 = vec_1, vec_2 = vec_2)
tib <- tib %>% mutate(products = vec_1 * vec_2)
numerator <- sum(tib$products)
# Return the cosine similarity
return (numerator / denominator)
}
Vectorizamos las puntuaciones:
# Obtenemos los vectores de cada persona
You <- as.numeric(as.vector(movie_ratings_tarea['You',]))
Diego <- as.numeric(as.vector(movie_ratings_tarea['Diego',]))
Lalo <- as.numeric(as.vector(movie_ratings_tarea['Lalo',]))
Ale <- as.numeric(as.vector(movie_ratings_tarea['Ale',]))
# Obtenemos "distancia" usando similitud por conseno
similarities_tarea <- data.frame(
cosine_similarity = c(cosine_similarity(You, Diego), cosine_similarity(You, Lalo), cosine_similarity(You, Ale))
)
rownames(similarities_tarea) <- c('Diego', 'Lalo', 'Ale')
similarities_tarea
## cosine_similarity
## Diego 0.7503127
## Lalo 0.7424242
## Ale 0.8003335
Paso 3
A continuación se realizan una ponderación tomando en cuenta las
similitudes con los demás usuarios con la cual prediciremos que tan
probable es que a alguien le guste una película que no ha visto
comparando con los demás usuarios (aquellos con mayor similitud tendrán
un mayor impacto en la predicción)
# Creamos una función para obtener un promedio ponderado en base a los amigos
movie_rating_weighted_average <- function(movie, friends) {
denominator <- 0
numerator <- 0
for (friend in friends) {
friend_similarity <- similarities_tarea[friend,][1]
friend_rating <- movie_ratings_tarea[friend, movie][1]
# Tomaremos el promedio ponderado en cuenta solo para películas con calificación
if (is.na(friend_rating)) next
denominator <- denominator + friend_similarity
numerator <- numerator + (friend_similarity * friend_rating)
}
return (numerator / denominator)
}
#file.choose()
Paso 4
Predicción En este último paso procedemos a predecir la posible
puntuación que el usuario podría asignarle a las películas que no ha
visto, a mayor puntuación más recomendada es la palícula
friend_names <- c('Diego', 'Lalo', 'Ale')
new_movies <- c('ENREDADOS', 'CARS1', 'MONJA')
new_movie_predicted_ratings <- tibble()
for (n in new_movies) {
predicted_rating <- movie_rating_weighted_average(n, friend_names)
prediction_tibble <- tibble(movie = n, predicted_rating = predicted_rating)
new_movie_predicted_ratings <- bind_rows(new_movie_predicted_ratings, prediction_tibble)
}
new_movie_predicted_ratings
## # A tibble: 3 × 2
## movie predicted_rating
## <chr> <dbl>
## 1 ENREDADOS 4.32
## 2 CARS1 3.97
## 3 MONJA 3
Como podemos ver, la película con mayor rating predicho es ENREDADOS
por lo que será la película recomendada en primer lugar
LS0tDQp0aXRsZTogIlJFQ09NRU5EQUNJT05FUy1FUVVJUE8iDQphdXRob3I6ICJGbG9yIE1hcnTDrW5leiAtIEx1aXMgRGF2aWQgQ2FzdGlsbG8iDQpkYXRlOiAiMjAyNC0wNC0xOSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiBzaW1wbGV4DQotLS0NCg0KIVtdKEM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXE1PRFVMTyA0XFxSRUNPTU1NLmpwZykNCg0KIyBDb250ZXh0bw0KTG9zIHNpc3RlbWFzIGRlIHJlY29tZW5kYWNpw7NuIHNvbiBoZXJyYW1pZW50YXMgeSBhbGdvcml0bW9zIGRpc2XDsWFkb3MgcGFyYSBzdWdlcmlyIHByb2R1Y3Rvcywgc2VydmljaW9zLCBpbmZvcm1hY2nDs24gbyBjb250ZW5pZG8gYSBsb3MgdXN1YXJpb3MsIGJhc8OhbmRvc2UgZW4gc3VzIHByZWZlcmVuY2lhcyB5IGNvbXBvcnRhbWllbnRvcyBwcmV2aW9zLCBleGlzdGVuICBkb3MgdGlwb3MgZGUgc2lzdGVtYXMgZGUgcmVjb21lbmRhaWNvbmVzIHByaW5jaXBhbGVzOiAgDQoNCiFbXShDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxNT0RVTE8gNFxccmVjb20ucG5nKSAgDQoNCiogU2lzdGVtYSBCYXNhZG8gZW4gQ29udGVuaWRvICANCioqIFJlY29taWVuZGEgY29zYXMgc2ltaWxhcmVzIGEgbG8gcXVlIHlhIHRlIGhhIGd1c3RhZG8uIFBvciBlamVtcGxvLCBzaSB0ZSBndXN0YSB1bmEgcGVsw61jdWxhIGRlIGFjY2nDs24sIHRlIHN1Z2llcmUgb3RyYXMgcGVsw61jdWxhcyBkZWwgbWlzbW8gZ8OpbmVyby4gIA0KKiogRWplbXBsbzogTmV0ZmxpeCB0ZSByZWNvbWllbmRhIHNlcmllcyB5IHBlbMOtY3VsYXMgYmFzYWRhcyBlbiBsbyBxdWUgaGFzIHZpc3RvLiAgDQoqIFNpc3RlbWEgQ29sYWJvcmF0aXZvICANCioqIFJlY29taWVuZGEgYmFzw6FuZG9zZSBlbiBsbyBxdWUgbGVzIGhhIGd1c3RhZG8gYSBwZXJzb25hcyBzaW1pbGFyZXMgYSB0aSwgc2luIGltcG9ydGFyIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlbCBjb250ZW5pZG8uICANCioqIEVqZW1wbG86IEZhY2Vib29rIHN1Z2llcmUgYW1pZ29zIG8gcMOhZ2luYXMgYmFzYWRhcyBlbiB0dXMgYW1pZ29zLg0KDQojIEFjdGl2aWRhZA0KRHVyYW50ZSBlc3RhIGFjdGl2aWRhZCBzZSByZWFsaXphcsOhIHVuIHNpc3RlbWEgZGUgcmVjb21lbmRhY2lvbmVzIGNvbGFib3JhdGl2byBlbiBlbCBxdWUgYXNpZ25hcmVtb3MgcG9uZGVyYWNpw7NuIGNvbiByZXNwZWN0byBhIGxhcyBzaW1pbGl0dWRlcyBlbnRyZSBsb3MgZ3VzdG9zIGRlIGxhcyBwZXJzb25hcyBwYXJhIHBvZGVyIHJlY29tZW5kYXIgcGVsw61jdWxhcyBjb24gYWx0YSBwcm9iYWJpbGRpYWQgZGUgcXVlIGxlcyBndXN0ZW4gYSBsb3MgdXN1YXJpb3MuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpICAgDQpsaWJyYXJ5KHJlY29tbWVuZGVybGFiKQ0KYGBgDQojIyBQYXNvIDENCjEuLSBDcmVhciBsYSBtYXRyaXoNCmBgYHtyfQ0KbW92aWVfcmF0aW5nc190YXJlYSA8LSBkYXRhLmZyYW1lKA0KICBLUDEgPSBjKDUsIDQsIDUsIDQpLCANCiAgRU5SRURBRE9TID0gYyg0LCA1LCA0LCBOQSksDQogIFVQID0gYyg1LCA0LCA1LCAyKSwNCiAgQ0FSUzEgPSBjKDQsIDUsIDMsIE5BKSwNCiAgVFMzICA9IGMoMywgNSwgMywgMiksDQogIFNIUkVLMiA9IGMoMywgNSwgNCwgMyksDQogIE1PTkpBID0gYygzLCBOQSwgMywgTkEpDQopDQpyb3duYW1lcyhtb3ZpZV9yYXRpbmdzX3RhcmVhKSA8LSBjKCdEaWVnbycsJ0xhbG8nLCAgJ0FsZScsICdZb3UnICkNCm1vdmllX3JhdGluZ3NfdGFyZWENCmBgYA0KDQojIyBQYXNvIDINClByb2Nlc28gZGUgbWF0cmljZXM6ICANCkR1cmFudGUgZXN0YSBwYXJ0ZSBkZWwgcHJvY2VzbyBzZSBjcmVhbiB1biB2ZWN0b3IgYSBjYWRhIHVzdWFyaW8gY29uIHJlc3BlY3RvIGEgbGFzIGNhbGlmaWNhY2lvbmVzIHF1ZSBsZXMgYXNpZ25hcm9uIGEgY2FkYSB1bmEgZGUgbGFzIHBlbMOtY3VsYXMsIGRlc3B1w6lzIHNlIGdyYWZpY2FuIGxvcyB2ZWN0b3JlcyB5IGZpbmFsbWVudGUgc2UgY2FsY3VsYW4gbGFzIGRpc3RhbmNpYXMgZW50cmUgZWxsb3MgcGFyYSBlbmNvbnRyYXIgbGEgbWF5b3Igc2ltaWxpdHVkIGVudHJlIHVzdWFyaW9zLCBhIG1lbm9yIGRpc3RhbmNpYSBtYXlvciBzaW1pbGl0dWQgZGUgZ3VzdG9zLg0KYGBge3J9DQpjb3NpbmVfc2ltaWxhcml0eSA8LSBmdW5jdGlvbih2ZWNfMSwgdmVjXzIpIHsNCiAgdmVjX2xlbiA8LSBsZW5ndGgodmVjXzEpDQogIA0KICAjIE5BIHZhbHVlcyBhcmUgcmVwbGFjZWQgd2l0aCAwDQogIHZlY18xW2lzLm5hKHZlY18xKV0gPC0gMA0KICB2ZWNfMltpcy5uYSh2ZWNfMildIDwtIDANCiAgDQogICMgQ29tcHV0aW5nIHRoZSBkZW5vbWluYXRvcg0KICB2ZWNfMV9kZW5vbSA8LSBzcXJ0KHN1bSh2ZWNfMV4yKSkNCiAgdmVjXzJfZGVub20gPC0gc3FydChzdW0odmVjXzJeMikpDQogIGRlbm9taW5hdG9yIDwtIHZlY18xX2Rlbm9tICogdmVjXzJfZGVub20NCiAgDQogICMgQ29tcHV0aW5nIHRoZSBudW1lcmF0b3INCiAgdGliID0gdGliYmxlKHZlY18xID0gdmVjXzEsIHZlY18yID0gdmVjXzIpDQogIHRpYiA8LSB0aWIgJT4lIG11dGF0ZShwcm9kdWN0cyA9IHZlY18xICogdmVjXzIpDQogIG51bWVyYXRvciA8LSBzdW0odGliJHByb2R1Y3RzKQ0KICANCiAgIyBSZXR1cm4gdGhlIGNvc2luZSBzaW1pbGFyaXR5DQogIHJldHVybiAobnVtZXJhdG9yIC8gZGVub21pbmF0b3IpDQp9DQpgYGANCg0KVmVjdG9yaXphbW9zIGxhcyBwdW50dWFjaW9uZXM6DQpgYGB7cn0NCiMgT2J0ZW5lbW9zIGxvcyB2ZWN0b3JlcyBkZSBjYWRhIHBlcnNvbmENCllvdSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydZb3UnLF0pKQ0KRGllZ28gPC0gYXMubnVtZXJpYyhhcy52ZWN0b3IobW92aWVfcmF0aW5nc190YXJlYVsnRGllZ28nLF0pKQ0KTGFsbyA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydMYWxvJyxdKSkNCkFsZSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydBbGUnLF0pKQ0KDQoNCiMgT2J0ZW5lbW9zICJkaXN0YW5jaWEiIHVzYW5kbyBzaW1pbGl0dWQgcG9yIGNvbnNlbm8NCnNpbWlsYXJpdGllc190YXJlYSA8LSBkYXRhLmZyYW1lKA0KICBjb3NpbmVfc2ltaWxhcml0eSA9IGMoY29zaW5lX3NpbWlsYXJpdHkoWW91LCBEaWVnbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgTGFsbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgQWxlKSkNCikNCnJvd25hbWVzKHNpbWlsYXJpdGllc190YXJlYSkgPC0gYygnRGllZ28nLCAnTGFsbycsICdBbGUnKQ0Kc2ltaWxhcml0aWVzX3RhcmVhDQpgYGANCg0KDQojIyBQYXNvIDMNCkEgY29udGludWFjacOzbiBzZSByZWFsaXphbiB1bmEgcG9uZGVyYWNpw7NuIHRvbWFuZG8gZW4gY3VlbnRhIGxhcyBzaW1pbGl0dWRlcyBjb24gbG9zIGRlbcOhcyB1c3VhcmlvcyBjb24gbGEgY3VhbCBwcmVkaWNpcmVtb3MgcXVlIHRhbiBwcm9iYWJsZSBlcyBxdWUgYSBhbGd1aWVuIGxlIGd1c3RlIHVuYSBwZWzDrWN1bGEgcXVlIG5vIGhhIHZpc3RvIGNvbXBhcmFuZG8gIGNvbiBsb3MgZGVtw6FzIHVzdWFyaW9zIChhcXVlbGxvcyBjb24gbWF5b3Igc2ltaWxpdHVkIHRlbmRyw6FuIHVuIG1heW9yIGltcGFjdG8gZW4gbGEgcHJlZGljY2nDs24pDQpgYGB7cn0NCiMgQ3JlYW1vcyB1bmEgZnVuY2nDs24gcGFyYSBvYnRlbmVyIHVuIHByb21lZGlvIHBvbmRlcmFkbyBlbiBiYXNlIGEgbG9zIGFtaWdvcw0KbW92aWVfcmF0aW5nX3dlaWdodGVkX2F2ZXJhZ2UgPC0gZnVuY3Rpb24obW92aWUsIGZyaWVuZHMpIHsNCiAgZGVub21pbmF0b3IgPC0gMA0KICBudW1lcmF0b3IgPC0gMA0KICBmb3IgKGZyaWVuZCBpbiBmcmllbmRzKSB7DQogICAgZnJpZW5kX3NpbWlsYXJpdHkgPC0gc2ltaWxhcml0aWVzX3RhcmVhW2ZyaWVuZCxdWzFdDQogICAgZnJpZW5kX3JhdGluZyA8LSBtb3ZpZV9yYXRpbmdzX3RhcmVhW2ZyaWVuZCwgbW92aWVdWzFdDQogICAgDQogICAgIyBUb21hcmVtb3MgZWwgcHJvbWVkaW8gcG9uZGVyYWRvIGVuIGN1ZW50YSBzb2xvIHBhcmEgcGVsw61jdWxhcyBjb24gY2FsaWZpY2FjacOzbg0KICAgIGlmIChpcy5uYShmcmllbmRfcmF0aW5nKSkgbmV4dA0KICAgIA0KICAgIGRlbm9taW5hdG9yIDwtIGRlbm9taW5hdG9yICsgZnJpZW5kX3NpbWlsYXJpdHkNCiAgICBudW1lcmF0b3IgPC0gbnVtZXJhdG9yICsgKGZyaWVuZF9zaW1pbGFyaXR5ICogZnJpZW5kX3JhdGluZykNCiAgfQ0KICANCiAgcmV0dXJuIChudW1lcmF0b3IgLyBkZW5vbWluYXRvcikNCn0NCmBgYA0KYGBge3J9DQojZmlsZS5jaG9vc2UoKQ0KYGBgDQoNCiMjIFBhc28gNA0KUHJlZGljY2nDs24NCkVuIGVzdGUgw7psdGltbyBwYXNvIHByb2NlZGVtb3MgYSBwcmVkZWNpciBsYSBwb3NpYmxlIHB1bnR1YWNpw7NuIHF1ZSBlbCB1c3VhcmlvIHBvZHLDrWEgYXNpZ25hcmxlIGEgbGFzIHBlbMOtY3VsYXMgcXVlIG5vIGhhIHZpc3RvLCBhIG1heW9yIHB1bnR1YWNpw7NuIG3DoXMgcmVjb21lbmRhZGEgZXMgbGEgcGFsw61jdWxhDQpgYGB7cn0NCmZyaWVuZF9uYW1lcyA8LSBjKCdEaWVnbycsICdMYWxvJywgJ0FsZScpDQpuZXdfbW92aWVzIDwtIGMoJ0VOUkVEQURPUycsICdDQVJTMScsICdNT05KQScpDQpuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MgPC0gdGliYmxlKCkNCmZvciAobiBpbiBuZXdfbW92aWVzKSB7DQogIHByZWRpY3RlZF9yYXRpbmcgPC0gbW92aWVfcmF0aW5nX3dlaWdodGVkX2F2ZXJhZ2UobiwgZnJpZW5kX25hbWVzKQ0KICBwcmVkaWN0aW9uX3RpYmJsZSA8LSB0aWJibGUobW92aWUgPSBuLCBwcmVkaWN0ZWRfcmF0aW5nID0gcHJlZGljdGVkX3JhdGluZykNCiAgbmV3X21vdmllX3ByZWRpY3RlZF9yYXRpbmdzIDwtIGJpbmRfcm93cyhuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MsIHByZWRpY3Rpb25fdGliYmxlKQ0KfQ0KbmV3X21vdmllX3ByZWRpY3RlZF9yYXRpbmdzDQpgYGANCg0KQ29tbyBwb2RlbW9zIHZlciwgbGEgcGVsw61jdWxhIGNvbiBtYXlvciByYXRpbmcgcHJlZGljaG8gZXMgRU5SRURBRE9TIHBvciBsbyBxdWUgc2Vyw6EgbGEgcGVsw61jdWxhIHJlY29tZW5kYWRhIGVuIHByaW1lciBsdWdhcg0K