Table of Contents

Load packages

library(ggplot2)
library(dplyr)
library(statsr)

Load data

Let’s put the gas in the tank

load("movies.Rdata")

Part 1: Data

As it was mentioned first that the data set is comprised of 651 randomly sampled movies produced and released before 2016, we can conclude that the conclusion derived are generalizable and can be applied to the population.

It is not causal as there is no random assignment. So we can’t find reason on why people like a movie or not.


Part 2: Research question

From the data model of the movies, we can aim to find what makes the good quality movie. Is good quality movie the one with most people’s liking or critics’ liking? For our research question, we’ll consider that a good quality movie is the one with a good critics score.

So what is the relation between people’s opinion, genre, awards are related to a critics’ score?

It is true that if people likes a movie the most, then it is watchable. But is it a good quality movie?


Part 3: Exploratory data analysis

Let’s dwell into this.

We’ll take the critics_score as the response variable and the below as the explanatory variables

  1. audience_score
  2. best_pic_win
  3. genre
  4. best_pic_nom
  5. runtime
  6. imdb_rating
ggplot(data=movies, aes(x=imdb_rating, y=critics_score)) + geom_point()

ggplot(data=movies, aes(x=audience_score, y=critics_score)) + geom_point()

So critics_score are direclty associated to audience_score and imdb_rating. Let’s check the same with runtime

ggplot(data=movies, aes(x=runtime, y=critics_score)) + geom_point()
## Warning: Removed 1 rows containing missing values (geom_point).

We know that runtime should not be a part of the critics_score. Let’s see if the modeling section (part 4) can find out that.

movies %>% group_by(genre) %>% summarize(mean=mean(critics_score), iqr=IQR(critics_score), count=n()) %>% arrange(desc(iqr))
## # A tibble: 11 x 4
##    genre                      mean   iqr count
##    <fct>                     <dbl> <dbl> <int>
##  1 Art House & International  51.6  55.2    14
##  2 Comedy                     40.9  50      87
##  3 Animation                  50.2  48       9
##  4 Science Fiction & Fantasy  50    48       9
##  5 Mystery & Suspense         54.9  46.5    59
##  6 Horror                     44.0  44      23
##  7 Action & Adventure         41.4  42      65
##  8 Drama                      62.2  40     305
##  9 Other                      64.9  40      16
## 10 Musical & Performing Arts  76.7  22.5    12
## 11 Documentary                86.3  15.2    52

Critics are leaned more towards Documentary in terms of the mean statistics, but towards ‘Art House and International’ interms of the IQR statistic. Let’s see how it’s been influenced with the combination of the other explanatory variables in the below sections.


Part 4: Modeling

Part 4.1 : Variables considered for the modeling

response variable explanatory variables
critics_score audience_score
  best_pic_win
  genre
  best_pic_nom
  runtime
  imdb_rating

Part 4.2 : Reason for excluding certain variables

critics_rating and audience_rating as they are less informative and categorical. And other variables for similar reasons.

movies %>% group_by(critics_rating) %>% summarize(count=n())
## # A tibble: 3 x 2
##   critics_rating  count
##   <fct>           <int>
## 1 Certified Fresh   135
## 2 Fresh             209
## 3 Rotten            307
movies %>% group_by(audience_rating) %>% summarize(count=n())
## # A tibble: 2 x 2
##   audience_rating count
##   <fct>           <int>
## 1 Spilled           275
## 2 Upright           376

These values are not useful for the critics’ score

Part 4.3 : Method Selection

We’ll use the Backward selection with the adjusted-r-squared.

The reason for choosing adjusted-r-squared is because that we need more reliable predictions on the critical score. We don’t need to find the significant predictors using p-value. And we can eliminate the unwanted variables in each step.

Part 4.4 : Linear Modeling

movies_lm <- lm(critics_score ~ audience_score + best_pic_win + genre + best_pic_nom + runtime + imdb_rating, data=movies)
summary(movies_lm)$adj.r.squared
## [1] 0.5976008

With the above value, let’s go to step 1 of removing each variable

Step 1

summary(lm(critics_score ~ audience_score + best_pic_win + genre + best_pic_nom + runtime, data=movies))$adj.r.squared
## [1] 0.5212694
summary(lm(critics_score ~ audience_score + best_pic_win + genre + best_pic_nom + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5978208
summary(lm(critics_score ~ audience_score + best_pic_win + genre + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5976335
summary(lm(critics_score ~ audience_score + best_pic_win + best_pic_nom + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5908536
summary(lm(critics_score ~ audience_score + genre + best_pic_nom + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5979892
summary(lm(critics_score ~ best_pic_win + genre + best_pic_nom + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5927875

We’ll remove the best_pic_win and we have updated adj-r-squared value as 0.5979892 .

Step 2

summary(lm(critics_score ~ audience_score + genre + best_pic_nom + runtime, data=movies))$adj.r.squared
## [1] 0.5213979
summary(lm(critics_score ~ audience_score + genre + best_pic_nom + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5982763
summary(lm(critics_score ~ audience_score + genre + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5974015
summary(lm(critics_score ~ audience_score + best_pic_nom + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5913518
summary(lm(critics_score ~ genre + best_pic_nom + runtime + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5932242

We’ll remove the runtime and we have updated adj-r-squared value as 0.5982763 .

Check that unwanted variable has been removed automatically, even though we added in knowingly

Step 3

summary(lm(critics_score ~ audience_score + genre + best_pic_nom, data=movies))$adj.r.squared
## [1] 0.5218319
summary(lm(critics_score ~ audience_score + genre + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5980058
summary(lm(critics_score ~ audience_score + best_pic_nom + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5913148
summary(lm(critics_score ~ genre + best_pic_nom + imdb_rating, data=movies))$adj.r.squared
## [1] 0.5930642

Since there is no improvement in the adj-r-squared value. We’ll stop it over here. The final predictors are audience_score + genre + best_pic_nom + imdb_rating

final_model <- lm(critics_score ~ audience_score + genre + best_pic_nom + imdb_rating, data=movies)
final_model
## 
## Call:
## lm(formula = critics_score ~ audience_score + genre + best_pic_nom + 
##     imdb_rating, data = movies)
## 
## Coefficients:
##                    (Intercept)                  audience_score  
##                       -61.3147                          0.2199  
##                 genreAnimation  genreArt House & International  
##                         7.9652                         -1.8330  
##                    genreComedy                genreDocumentary  
##                         3.1546                         13.0058  
##                     genreDrama                     genreHorror  
##                         7.2756                          7.4717  
## genreMusical & Performing Arts         genreMystery & Suspense  
##                         9.1947                          5.1115  
##                     genreOther  genreScience Fiction & Fantasy  
##                         9.9420                         12.4831  
##                best_pic_nomyes                     imdb_rating  
##                         4.8636                         15.2276

Part 4.5 : Model Diagnostics

Part 4.5.1 : Linear Relationships

Linear relationships : between critics_score & audience_score, critics_score & imdb_rating

ggplot(data = lm(critics_score ~ imdb_rating, data = movies), aes(x = .fitted, y = .resid)) + geom_point() + geom_hline(yintercept = 0, linetype = "dashed") + xlab("Fitted values") + ylab("Residuals")

ggplot(data = lm(critics_score ~ audience_score, data = movies), aes(x = .fitted, y = .resid)) + geom_point() + geom_hline(yintercept = 0, linetype = "dashed") + xlab("Fitted values") + ylab("Residuals")

It is satisfied as there is a random scatter around 0.

Part 4.5.2 : Residual Distributions

ggplot(data = final_model, aes(x = .resid)) + geom_histogram() + xlab("Residuals")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

The distribution is nearly normal and it is concentrated around 0.

Part 4.5.3 : Constant variability of the residuals

plot(final_model$residuals ~ final_model$fitted)

It is satisfied as there is a random scatter around 0.

Part 4.5.4 : Independent residuals

As the data is randomly sampled and each movie is independent of each other, we can safely assume that the residuals are also independent observations.

Part 4.6 : Interpretation of model coefficients

summary(final_model)
## 
## Call:
## lm(formula = critics_score ~ audience_score + genre + best_pic_nom + 
##     imdb_rating, data = movies)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -62.685 -12.156   2.123  12.962  47.683 
## 
## Coefficients:
##                                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                    -61.31470    5.86658 -10.452  < 2e-16 ***
## audience_score                   0.21985    0.07218   3.046 0.002415 ** 
## genreAnimation                   7.96521    6.44179   1.236 0.216732    
## genreArt House & International  -1.83304    5.32675  -0.344 0.730870    
## genreComedy                      3.15459    2.96196   1.065 0.287264    
## genreDocumentary                13.00581    3.58806   3.625 0.000312 ***
## genreDrama                       7.27561    2.51610   2.892 0.003963 ** 
## genreHorror                      7.47174    4.38329   1.705 0.088758 .  
## genreMusical & Performing Arts   9.19467    5.75841   1.597 0.110820    
## genreMystery & Suspense          5.11146    3.28835   1.554 0.120582    
## genreOther                       9.94198    5.06517   1.963 0.050103 .  
## genreScience Fiction & Fantasy  12.48306    6.40494   1.949 0.051737 .  
## best_pic_nomyes                  4.86358    4.06761   1.196 0.232265    
## imdb_rating                     15.22765    1.37636  11.064  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 18 on 637 degrees of freedom
## Multiple R-squared:  0.6063, Adjusted R-squared:  0.5983 
## F-statistic: 75.46 on 13 and 637 DF,  p-value: < 2.2e-16
Some observations are
  1. Proportion of variability in critic_score : 0.6063 (60.63%).
  2. With null hypothesis as all indicators are equals and p-value as very low. We can reject the null hypothesis and conclude that some indicators are not equal
  3. If a movie is documentary, then the average critic rating will increase by 13

Part 5: Prediction

Let’s try to predict the movie ‘La La Land’ from our model. First check if the movie is already present in the model.

movies %>% filter(grepl("land", title) | grepl("la la", title)) %>% select(title)
## # A tibble: 1 x 1
##   title              
##   <chr>              
## 1 Alice in Wonderland

It is not.

Part 5.1 :Prediction

Then, create the movie data and predict it

movie_predict_data <- data.frame(audience_score=81, genre = "Drama", best_pic_nom = "yes", imdb_rating=8.1)
predict(final_model, movie_predict_data)
##        1 
## 91.97652

With our prediction of 91.97652 % matches with the one in Rotten tomatoes’ 91 %

Part 5.2 :Prediction Interval

movie_predict_data <- data.frame(audience_score=81, genre = "Drama", best_pic_nom = "yes", imdb_rating=8.1)
predict(final_model, movie_predict_data, interval = "prediction", level = 0.95)
##        fit      lwr     upr
## 1 91.97652 55.78501 128.168

The 95% prediction interval of the critics’ score for any movie with audience_score=81, genre = "Drama", best_pic_nom = "yes", imdb_rating=8.1 is between 55.78501% and 128.168%.

Part 5.3 :Uncertainity around this prediction interval

As the critics’ score is percentage, it can’t exceed 100%. But the prediction interval has the upper limit as 128.168%

Part 5.4 :References

IMDB Link and Rotten Tomatoes Link Rotten Tomatoes IMDB


Part 6: Conclusion

  1. All else hold constant, Genres like ‘Science Fiction & Fantasy’ increases critics score by hefty 12.48306 compared to -1.83 of ‘Art House & International’

  2. Awards, Rating don’t affect critic score

So to conclude, critic’s score even though it is directly related to people’s opinion as audience_score/imdb_rating, but factors like genre/best_pic_nom plays a major role but not best_pic_win.

But there are cases where the model fails if the people like the movie too much and genre is ‘Science Fiction & Fantasy’, the critic’s score could be low due to other factors like bad movie plot. As adj-r-squared value is 59.83%, there are still hefty of chances where the prediction will still go wrong.