# renv::init()
library(rprojroot)
library(readxl)
library(dplyr)
library(tidyr )
# library(DT)
library(shiny)
library(shinythemes)
# library(shinydashboard)
# re0nv::snapshot()
movie_ratings <- read_excel("MovieRatings.xlsx", sheet = "MovieRatings")
# long format for easier computation
ratings_long <- pivot_longer(movie_ratings, cols = -Critic, names_to = "Movie", values_to = "Rating")
# global average rating
mu <- mean(ratings_long$Rating, na.rm = TRUE)
# user biases
user_biases <- ratings_long %>%
group_by(Critic) %>%
summarize(user_avg = mean(Rating, na.rm = TRUE)) %>%
mutate(b_u = user_avg - mu)
# movie biases
movie_biases <- ratings_long %>%
group_by(Movie) %>%
summarize(movie_avg = mean(Rating, na.rm = TRUE)) %>%
mutate(b_i = movie_avg - mu)
# joining biases back to the original ratings
ratings_with_biases <- ratings_long %>%
left_join(user_biases, by = "Critic") %>%
left_join(movie_biases, by = "Movie")
# Global Baseline Estimates
ratings_with_biases <- ratings_with_biases %>%
mutate(global_baseline_estimate = mu + b_u + b_i)
# movies not rated by each user and with highest estimates
recommendations <- ratings_with_biases %>%
filter(is.na(Rating)) %>%
arrange(desc(global_baseline_estimate))
# top 5 recommendations for each user
top_recommendations <- recommendations %>%
group_by(Critic) %>%
slice_max(global_baseline_estimate, n = 5) %>%
ungroup()
print(top_recommendations)
## # A tibble: 35 × 8
## Critic Movie Rating user_avg b_u movie_avg b_i global_baseline_esti…¹
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Burton Dead… NA 4 0.0656 4.44 0.510 4.51
## 2 Burton Capt… NA 4 0.0656 4.27 0.338 4.34
## 3 Burton Froz… NA 4 0.0656 3.73 -0.207 3.79
## 4 Burton Pitc… NA 4 0.0656 2.71 -1.22 2.78
## 5 Dan Capt… NA 5 1.07 4.27 0.338 5.34
## 6 Dan Jung… NA 5 1.07 3.9 -0.0344 4.97
## 7 Dan Froz… NA 5 1.07 3.73 -0.207 4.79
## 8 Dan Pitc… NA 5 1.07 2.71 -1.22 3.78
## 9 Dieudo… Jung… NA 4.67 0.732 3.9 -0.0344 4.63
## 10 Dieudo… Froz… NA 4.67 0.732 3.73 -0.207 4.46
## # ℹ 25 more rows
## # ℹ abbreviated name: ¹global_baseline_estimate
# UI
ui <- fluidPage(
theme = shinytheme("flatly"),
titlePanel("Movie Recommendations"),
sidebarLayout(
sidebarPanel(
selectInput("selectedCritic", "Choose a Critic:",
choices = unique(na.omit(top_recommendations$Critic)))
),
mainPanel(
tableOutput("recommendationsTable")
)
)
)
# Server
server <- function(input, output, session) {
output$recommendationsTable <- renderTable({
tryCatch({
filtered <- filter(top_recommendations, Critic == input$selectedCritic)
head(filtered, 5)
}, error = function(e) {
data.frame(Error = e$message)
})
})
# session information logging after session ending
session$onSessionEnded(function() {
info <- sessionInfo()
print(info)
})
}
# the app
shinyApp(ui = ui, server = server)
# library(rsconnect)
# deployApp("607_week11_movieRecommender_shinyapp.rmd")
Please see the deployed shiny app at this link.