library(ggplot2)
library(dplyr)
library(statsr)Let’s put the gas in the tank
load("movies.Rdata")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.
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?
Let’s dwell into this.
We’ll take the critics_score as the response variable and the below as the explanatory variables
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.
| response variable | explanatory variables |
|---|---|
| critics_score | audience_score |
| best_pic_win | |
| genre | |
| best_pic_nom | |
| runtime | |
| imdb_rating |
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
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.
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
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 .
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
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
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.
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.
plot(final_model$residuals ~ final_model$fitted)It is satisfied as there is a random scatter around 0.
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.
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
critic_score : 0.6063 (60.63%).
13
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.
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 %
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%.
As the critics’ score is percentage, it can’t exceed 100%. But the prediction interval has the upper limit as 128.168%
All else hold constant, Genres like ‘Science Fiction & Fantasy’ increases critics score by hefty 12.48306 compared to -1.83 of ‘Art House & International’
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.