Approach

For this assignment, my goal is to clean and organize the existing ratings first, calculate the global, user, and movie averages in R, and then use those values to estimate missing ratings and generate a movie recommendation using the Global Baseline Estimate algorithm in R. I will first import the ratings data and make sure the rating columns are stored as numeric values, while keeping missing ratings as N/A rather than treating them as zeros. I will then calculate the overall average rating across all users and movies. Next, I will calculate each user’s average rating and compare it to the overall average to determine whether that user generally rates movies higher or lower than average. I will do the same for each movie by calculating its average rating and comparing it to the overall average. The Global Baseline Estimate will then combine the overall mean, the user’s rating tendency, and the movie’s rating tendency to predict how a user may rate a movie they have not already rated. These predicted ratings can then be compared to determine which unrated movie would be the best recommendation.

One challenge I anticipate is the missing data in the survey. Not every person rated every movie, so these missing values need to be excluded from the average calculations rather than interpreted as ratings of zero. Another challenge is the relatively small dataset. Since there are only a few users and movies, one unusually high or low rating could have a noticeable effect on the averages and predictions. Some movies also have fewer ratings than others, meaning their averages may be based on less information and may therefore be less reliable.

Code Base

Populate Ratings Data in R

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
ratings <- data.frame(
  person = c("Person 1", "Person 2", "Person 3", "Person 4", "Person 5"),
  Barbie = c(4, 4, 1, 5, 3),
  Oppenheimer = c(2, 4, 5, NA, 3),
  Inside_Out_2 = c(3, NA, 2, 5, 2),
  Wicked = c(5, 4, NA, 5, 2),
  Spiderman = c(4, 2, 4, 4, 3),
  Insidious = c(1, NA, 4, 5, 5)
)

ratings
##     person Barbie Oppenheimer Inside_Out_2 Wicked Spiderman Insidious
## 1 Person 1      4           2            3      5         4         1
## 2 Person 2      4           4           NA      4         2        NA
## 3 Person 3      1           5            2     NA         4         4
## 4 Person 4      5          NA            5      5         4         5
## 5 Person 5      3           3            2      2         3         5

Calculate Global Mean

global_mean <- mean(as.matrix(ratings[, -1]), na.rm = TRUE)
global_mean
## [1] 3.5

Calculate Movie Averages

movie_means <- colMeans(ratings[, -1], na.rm = TRUE)
movie_means
##       Barbie  Oppenheimer Inside_Out_2       Wicked    Spiderman    Insidious 
##         3.40         3.50         3.00         4.00         3.40         3.75

Calculate Movie Bias

movie_bias <- movie_means - global_mean
movie_bias
##       Barbie  Oppenheimer Inside_Out_2       Wicked    Spiderman    Insidious 
##        -0.10         0.00        -0.50         0.50        -0.10         0.25

Calculate average rating for each person

user_means <- rowMeans(ratings[, -1], na.rm = TRUE)
user_means
## [1] 3.166667 3.500000 3.200000 4.800000 3.000000

Calculate user bias

user_bias <- user_means - global_mean
user_bias
## [1] -0.3333333  0.0000000 -0.3000000  1.3000000 -0.5000000

Predict missing ratings using Global Baseline Estimate

person2_insideout <- global_mean + user_bias[2] + movie_bias["Inside_Out_2"]

person2_insidious <- global_mean + user_bias[2] + movie_bias["Insidious"]

person3_wicked <- global_mean + user_bias[3] + movie_bias["Wicked"]

person4_oppenheimer <- global_mean + user_bias[4] + movie_bias["Oppenheimer"]

person2_insideout
## Inside_Out_2 
##            3
person2_insidious
## Insidious 
##      3.75
person3_wicked
## Wicked 
##    3.7
person4_oppenheimer
## Oppenheimer 
##         4.8

Create table of predicted ratings

predictions <- data.frame(
  person = c("Person 2", "Person 2", "Person 3", "Person 4"),
  movie = c("Inside Out 2", "Insidious", "Wicked", "Oppenheimer"),
  predicted_rating = c(
    unname(person2_insideout),
    unname(person2_insidious),
    unname(person3_wicked),
    unname(person4_oppenheimer)
  )
)

predictions
##     person        movie predicted_rating
## 1 Person 2 Inside Out 2             3.00
## 2 Person 2    Insidious             3.75
## 3 Person 3       Wicked             3.70
## 4 Person 4  Oppenheimer             4.80

Select the highest predicted rating for each person

recommendations <- predictions %>%
  group_by(person) %>%
  slice_max(predicted_rating, n = 1) %>%
  ungroup()

recommendations
## # A tibble: 3 × 3
##   person   movie       predicted_rating
##   <chr>    <chr>                  <dbl>
## 1 Person 2 Insidious               3.75
## 2 Person 3 Wicked                  3.7 
## 3 Person 4 Oppenheimer             4.8

Results and Interpretation

The Global Baseline Estimate predicted ratings for the movies that each person had not previously rated. For Person 2, the predicted ratings were 3.00 for Inside Out 2 and 3.75 for Insidious, making Insidious the recommendation. Wicked was recommended to Person 3 with a predicted rating of 3.70, and Oppenheimer was recommended to Person 4 with a predicted rating of 4.80.

Persons 1 and 5 did not receive recommendations because they had already rated every movie in the dataset. Overall, the Global Baseline Estimate provided recommendations by considering the overall average rating, each user’s general rating tendency, and each movie’s rating tendency.

One challenge with this dataset is its small size. With only five people and six movies, individual ratings can have a large effect on the user averages, movie averages, and resulting predictions. Some movies also have fewer ratings than others, so their averages may be less representative.

The Global Baseline Estimate is relatively simple. It considers the overall average along with user and movie rating tendencies, but it does not account for factors such as movie genre or similarities in users’ preferences. Because of this, the recommendations should be interpreted as estimates based only on the available ratings.