Modeling and prediction for movies Setup Load packages:

library(ggplot2)
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
library(statsr)

Load data

load("movies.Rdata")

Part 1: Data The movies data were collected from 651 randomly sampled movies before 2016. This is an oberservational data and only association relationship can be concluded, we can not say any causality from this dataset.

Part 2: Research question In this analysis, we want to find out what attributes make a movie popular? Also, at the end of the report, we will build a prediction model and pick a movie from 2016 to validate our model predition.

Part 3: Exploratory data analysis Let’s review the variables we have here:

names(movies)
##  [1] "title"            "title_type"       "genre"           
##  [4] "runtime"          "mpaa_rating"      "studio"          
##  [7] "thtr_rel_year"    "thtr_rel_month"   "thtr_rel_day"    
## [10] "dvd_rel_year"     "dvd_rel_month"    "dvd_rel_day"     
## [13] "imdb_rating"      "imdb_num_votes"   "critics_rating"  
## [16] "critics_score"    "audience_rating"  "audience_score"  
## [19] "best_pic_nom"     "best_pic_win"     "best_actor_win"  
## [22] "best_actress_win" "best_dir_win"     "top200_box"      
## [25] "director"         "actor1"           "actor2"          
## [28] "actor3"           "actor4"           "actor5"          
## [31] "imdb_url"         "rt_url"

Our objective is to find which variables can provide us better prediction of movie popularity. As we can see we have several scores from either critics or audience, how do we decide which variable to be our response variable? Let’s check the correlation coefficient for critics_score and audience_score.

movies %>% summarise(cor(critics_score,audience_score))
## # A tibble: 1 x 1
##   `cor(critics_score, audience_score)`
##                                  <dbl>
## 1                                0.704

Since these two variables are highly correlated, it is ok to use either one and I choose audience_score as my response variable in this analysis.

I want to make the data cleaner and remove some variables that I won’t need in this analysis. Check the structure of the data.

str(movies)
## Classes 'tbl_df', 'tbl' and 'data.frame':    651 obs. of  32 variables:
##  $ title           : chr  "Filly Brown" "The Dish" "Waiting for Guffman" "The Age of Innocence" ...
##  $ title_type      : Factor w/ 3 levels "Documentary",..: 2 2 2 2 2 1 2 2 1 2 ...
##  $ genre           : Factor w/ 11 levels "Action & Adventure",..: 6 6 4 6 7 5 6 6 5 6 ...
##  $ runtime         : num  80 101 84 139 90 78 142 93 88 119 ...
##  $ mpaa_rating     : Factor w/ 6 levels "G","NC-17","PG",..: 5 4 5 3 5 6 4 5 6 6 ...
##  $ studio          : Factor w/ 211 levels "20th Century Fox",..: 91 202 167 34 13 163 147 118 88 84 ...
##  $ thtr_rel_year   : num  2013 2001 1996 1993 2004 ...
##  $ thtr_rel_month  : num  4 3 8 10 9 1 1 11 9 3 ...
##  $ thtr_rel_day    : num  19 14 21 1 10 15 1 8 7 2 ...
##  $ dvd_rel_year    : num  2013 2001 2001 2001 2005 ...
##  $ dvd_rel_month   : num  7 8 8 11 4 4 2 3 1 8 ...
##  $ dvd_rel_day     : num  30 28 21 6 19 20 18 2 21 14 ...
##  $ imdb_rating     : num  5.5 7.3 7.6 7.2 5.1 7.8 7.2 5.5 7.5 6.6 ...
##  $ imdb_num_votes  : int  899 12285 22381 35096 2386 333 5016 2272 880 12496 ...
##  $ critics_rating  : Factor w/ 3 levels "Certified Fresh",..: 3 1 1 1 3 2 3 3 2 1 ...
##  $ critics_score   : num  45 96 91 80 33 91 57 17 90 83 ...
##  $ audience_rating : Factor w/ 2 levels "Spilled","Upright": 2 2 2 2 1 2 2 1 2 2 ...
##  $ audience_score  : num  73 81 91 76 27 86 76 47 89 66 ...
##  $ best_pic_nom    : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ best_pic_win    : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ best_actor_win  : Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 2 1 1 ...
##  $ best_actress_win: Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ best_dir_win    : Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 1 1 1 ...
##  $ top200_box      : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ director        : chr  "Michael D. Olmos" "Rob Sitch" "Christopher Guest" "Martin Scorsese" ...
##  $ actor1          : chr  "Gina Rodriguez" "Sam Neill" "Christopher Guest" "Daniel Day-Lewis" ...
##  $ actor2          : chr  "Jenni Rivera" "Kevin Harrington" "Catherine O'Hara" "Michelle Pfeiffer" ...
##  $ actor3          : chr  "Lou Diamond Phillips" "Patrick Warburton" "Parker Posey" "Winona Ryder" ...
##  $ actor4          : chr  "Emilio Rivera" "Tom Long" "Eugene Levy" "Richard E. Grant" ...
##  $ actor5          : chr  "Joseph Julian Soria" "Genevieve Mooy" "Bob Balaban" "Alec McCowen" ...
##  $ imdb_url        : chr  "http://www.imdb.com/title/tt1869425/" "http://www.imdb.com/title/tt0205873/" "http://www.imdb.com/title/tt0118111/" "http://www.imdb.com/title/tt0106226/" ...
##  $ rt_url          : chr  "//www.rottentomatoes.com/m/filly_brown_2012/" "//www.rottentomatoes.com/m/dish/" "//www.rottentomatoes.com/m/waiting_for_guffman/" "//www.rottentomatoes.com/m/age_of_innocence/" ...

Imagine when you have a brand new movie, what you can know right away are the title, genre, runtime, actor/actress, and director, and these are your explanatory variables. On the other hand, you do not know what is the critics score, audience rating, etc. at that particular moment. So my new dataset will contain only the explanatory variables and one response variable.

movies_1 <- movies %>% select(1:5,thtr_rel_year,thtr_rel_month,audience_score, best_actor_win,best_actress_win,best_dir_win)
names(movies_1)
##  [1] "title"            "title_type"       "genre"           
##  [4] "runtime"          "mpaa_rating"      "thtr_rel_year"   
##  [7] "thtr_rel_month"   "audience_score"   "best_actor_win"  
## [10] "best_actress_win" "best_dir_win"

First, I want to validate the data to see if there is any bias. Since the movies were collected randomly from each year, I calculate how many movies were released each year in the dataset.

How many movies were release each year?

yr <- movies_1 %>% group_by(thtr_rel_year) %>% summarise(count = n())
ggplot(yr,aes(x=as.factor(thtr_rel_year),y=count)) + geom_bar(stat = "identity") +
  scale_x_discrete(breaks = seq(1970,2014,5)) + labs(x = "theater release year",y = "number of movies")

Even though more movies after 1995 were selected in this data, the difference is not that significant. Since we do not know total number of movies each year, it is reasonable to believe that more movies were released after 2000 and it is likely the reason behind the difference.

One more thing I want to explore is: Is there any certain month that the average scores are higher? Does not find anything interesting.

movies_1 %>% group_by(thtr_rel_month) %>% summarise(count = n(), avg_score = mean(audience_score))
## # A tibble: 12 x 3
##    thtr_rel_month count avg_score
##             <dbl> <int>     <dbl>
##  1              1    69      62.9
##  2              2    34      63.9
##  3              3    51      59.7
##  4              4    45      61.1
##  5              5    44      62.4
##  6              6    72      61.7
##  7              7    48      62.1
##  8              8    44      61.1
##  9              9    53      61.7
## 10             10    70      62.0
## 11             11    51      61.4
## 12             12    70      67.1

Let’s check whether certain types of movies title_type have higher scores on average. Documentary type has much higher scores than other two. Notice that majority of movies are belong to Feature Film.

movies_1 %>% group_by(title_type) %>% summarise(count = n(), avg_score = mean(audience_score))
## # A tibble: 3 x 3
##   title_type   count avg_score
##   <fct>        <int>     <dbl>
## 1 Documentary     55      83.3
## 2 Feature Film   591      60.5
## 3 TV Movie         5      56.8

Let’s see which genre gets higher scores on average. Still, Documentary has the highest avergae score.

movies_1 %>% group_by(genre) %>% summarise(count = n(), avg_score = mean(audience_score)) %>% arrange(desc(avg_score))
## # A tibble: 11 x 3
##    genre                     count avg_score
##    <fct>                     <int>     <dbl>
##  1 Documentary                  52      82.8
##  2 Musical & Performing Arts    12      80.2
##  3 Other                        16      66.7
##  4 Drama                       305      65.3
##  5 Art House & International    14      64  
##  6 Animation                     9      62.4
##  7 Mystery & Suspense           59      55.9
##  8 Action & Adventure           65      53.8
##  9 Comedy                       87      52.5
## 10 Science Fiction & Fantasy     9      50.9
## 11 Horror                       23      45.8

How about whether or not one of the main actors/actresses or director ever won a oscar? Here we see an interesting result. The top 2 highest average scores are coming from either “best actor and director” or “best actress and director”, but not all three. Notice that majority of movies filmed without best actor,actress, and director, indicating that there are still a lot of movie makers not getting Oscar award yet.

movies_1 %>% group_by(best_actor_win,best_actress_win,best_dir_win) %>% summarise(count = n(), avg_score = mean(audience_score)) %>% arrange(desc(avg_score))
## # A tibble: 8 x 5
## # Groups:   best_actor_win, best_actress_win [4]
##   best_actor_win best_actress_win best_dir_win count avg_score
##   <fct>          <fct>            <fct>        <int>     <dbl>
## 1 yes            no               yes              8      76.9
## 2 no             yes              yes              5      72.2
## 3 yes            yes              yes              4      72  
## 4 yes            yes              no              16      66.4
## 5 no             no               yes             26      66.3
## 6 no             no               no             480      62.0
## 7 no             yes              no              47      61.4
## 8 yes            no               no              65      60.3

Part 4: Modeling As above mentioned, I removed some variables and only included 10 explanatory variables(known) and 1 response variable(unknown). Here I would like to use backwards elimination p-value methods since it’s the fastest method. In my full model, I exclude title and thtr_rel_year. It might be possible that people enjoy movies more when certain “words” appear in the title, but we don’t have skills to analyze at this point. For the release year, it’s not related when we predict certain movie is popular or not, so I didn’t include thtr_rell_year in my model.

# Full model
mlr <- lm(audience_score ~ title_type + genre + runtime + mpaa_rating + thtr_rel_month +
            best_actor_win + best_actress_win + best_dir_win, data = movies_1)
summary(mlr)
## 
## Call:
## lm(formula = audience_score ~ title_type + genre + runtime + 
##     mpaa_rating + thtr_rel_month + best_actor_win + best_actress_win + 
##     best_dir_win, data = movies_1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -52.684 -12.995   1.278  13.251  39.492 
## 
## Coefficients:
##                                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                     58.05485    9.00873   6.444 2.32e-10 ***
## title_typeFeature Film         -11.83293    6.61174  -1.790  0.07399 .  
## title_typeTV Movie             -21.40435   10.41533  -2.055  0.04028 *  
## genreAnimation                   4.67673    6.97068   0.671  0.50252    
## genreArt House & International   9.53012    5.39195   1.767  0.07764 .  
## genreComedy                      0.98293    2.98616   0.329  0.74214    
## genreDocumentary                16.62940    7.09879   2.343  0.01946 *  
## genreDrama                      10.82022    2.53592   4.267 2.29e-05 ***
## genreHorror                     -6.85914    4.44890  -1.542  0.12364    
## genreMusical & Performing Arts  19.77580    6.05167   3.268  0.00114 ** 
## genreMystery & Suspense          1.07470    3.33231   0.323  0.74717    
## genreOther                      11.97678    5.04504   2.374  0.01790 *  
## genreScience Fiction & Fantasy  -4.02326    6.35636  -0.633  0.52700    
## runtime                          0.17768    0.04245   4.185 3.26e-05 ***
## mpaa_ratingNC-17               -10.41867   13.53800  -0.770  0.44183    
## mpaa_ratingPG                   -9.76940    4.90043  -1.994  0.04663 *  
## mpaa_ratingPG-13               -15.63729    5.00355  -3.125  0.00186 ** 
## mpaa_ratingR                    -9.99881    4.85316  -2.060  0.03979 *  
## mpaa_ratingUnrated              -6.48384    5.60508  -1.157  0.24780    
## thtr_rel_month                  -0.07782    0.20458  -0.380  0.70379    
## best_actor_winyes               -1.00440    2.11506  -0.475  0.63504    
## best_actress_winyes             -0.11666    2.32657  -0.050  0.96002    
## best_dir_winyes                  6.15676    2.92599   2.104  0.03576 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 17.83 on 627 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.2495, Adjusted R-squared:  0.2231 
## F-statistic: 9.474 on 22 and 627 DF,  p-value: < 2.2e-16

Model selection Remove best_actress_win since the p-value is the highest one at 0.96002

mlr <- lm(audience_score ~ title_type + genre + runtime + mpaa_rating + thtr_rel_month +
            best_actor_win + best_dir_win, data = movies_1)
summary(mlr)
## 
## Call:
## lm(formula = audience_score ~ title_type + genre + runtime + 
##     mpaa_rating + thtr_rel_month + best_actor_win + best_dir_win, 
##     data = movies_1)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -52.66 -12.99   1.23  13.26  39.50 
## 
## Coefficients:
##                                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                     58.08741    8.97817   6.470 1.98e-10 ***
## title_typeFeature Film         -11.83355    6.60648  -1.791  0.07374 .  
## title_typeTV Movie             -21.41802   10.40349  -2.059  0.03993 *  
## genreAnimation                   4.65993    6.95709   0.670  0.50323    
## genreArt House & International   9.51736    5.38166   1.768  0.07747 .  
## genreComedy                      0.96844    2.96978   0.326  0.74446    
## genreDocumentary                16.62061    7.09099   2.344  0.01939 *  
## genreDrama                      10.80326    2.51126   4.302 1.96e-05 ***
## genreHorror                     -6.86630    4.44308  -1.545  0.12275    
## genreMusical & Performing Arts  19.77684    6.04683   3.271  0.00113 ** 
## genreMystery & Suspense          1.05620    3.30919   0.319  0.74970    
## genreOther                      11.96525    5.03579   2.376  0.01780 *  
## genreScience Fiction & Fantasy  -4.02515    6.35120  -0.634  0.52647    
## runtime                          0.17738    0.04199   4.224 2.76e-05 ***
## mpaa_ratingNC-17               -10.39950   13.52185  -0.769  0.44213    
## mpaa_ratingPG                   -9.77016    4.89651  -1.995  0.04644 *  
## mpaa_ratingPG-13               -15.63761    4.99957  -3.128  0.00184 ** 
## mpaa_ratingR                    -9.99467    4.84861  -2.061  0.03968 *  
## mpaa_ratingUnrated              -6.47792    5.59938  -1.157  0.24775    
## thtr_rel_month                  -0.07793    0.20441  -0.381  0.70316    
## best_actor_winyes               -1.01135    2.10883  -0.480  0.63169    
## best_dir_winyes                  6.15251    2.92244   2.105  0.03566 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 17.82 on 628 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.2495, Adjusted R-squared:  0.2244 
## F-statistic: 9.941 on 21 and 628 DF,  p-value: < 2.2e-16

Remove thtr_rel_month since the p-value is the highest one at 0.70316

mlr <- lm(audience_score ~ title_type + genre + runtime + mpaa_rating +
            best_actor_win + best_dir_win, data = movies_1)
summary(mlr)
## 
## Call:
## lm(formula = audience_score ~ title_type + genre + runtime + 
##     mpaa_rating + best_actor_win + best_dir_win, data = movies_1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -52.902 -13.126   1.301  13.301  39.384 
## 
## Coefficients:
##                                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                     57.90767    8.95968   6.463 2.06e-10 ***
## title_typeFeature Film         -11.81662    6.60184  -1.790  0.07395 .  
## title_typeTV Movie             -21.29456   10.39138  -2.049  0.04085 *  
## genreAnimation                   4.56065    6.94749   0.656  0.51178    
## genreArt House & International   9.51314    5.37800   1.769  0.07739 .  
## genreComedy                      0.92043    2.96510   0.310  0.75634    
## genreDocumentary                16.62488    7.08616   2.346  0.01928 *  
## genreDrama                      10.81328    2.50942   4.309 1.90e-05 ***
## genreHorror                     -6.87936    4.43992  -1.549  0.12178    
## genreMusical & Performing Arts  19.75002    6.04231   3.269  0.00114 ** 
## genreMystery & Suspense          1.12324    3.30227   0.340  0.73386    
## genreOther                      12.04755    5.02774   2.396  0.01686 *  
## genreScience Fiction & Fantasy  -4.00936    6.34675  -0.632  0.52780    
## runtime                          0.17394    0.04099   4.244 2.53e-05 ***
## mpaa_ratingNC-17               -10.27603   13.50878  -0.761  0.44713    
## mpaa_ratingPG                   -9.78875    4.89294  -2.001  0.04587 *  
## mpaa_ratingPG-13               -15.58932    4.99457  -3.121  0.00188 ** 
## mpaa_ratingR                   -10.00672    4.84521  -2.065  0.03931 *  
## mpaa_ratingUnrated              -6.44191    5.59478  -1.151  0.25000    
## best_actor_winyes               -1.04551    2.10550  -0.497  0.61967    
## best_dir_winyes                  6.13159    2.91994   2.100  0.03613 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 17.81 on 629 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.2493, Adjusted R-squared:  0.2254 
## F-statistic: 10.44 on 20 and 629 DF,  p-value: < 2.2e-16

Remove best_actor_win since the p-value is the highest one at 0.61967

best_mlr <- lm(audience_score ~ title_type + genre + runtime + mpaa_rating +
            best_dir_win, data = movies_1)
summary(best_mlr)
## 
## Call:
## lm(formula = audience_score ~ title_type + genre + runtime + 
##     mpaa_rating + best_dir_win, data = movies_1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -52.671 -13.017   1.343  13.316  39.399 
## 
## Coefficients:
##                                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                     58.3175     8.9163   6.541 1.27e-10 ***
## title_typeFeature Film         -11.8562     6.5974  -1.797  0.07280 .  
## title_typeTV Movie             -21.2172    10.3840  -2.043  0.04144 *  
## genreAnimation                   4.4799     6.9414   0.645  0.51891    
## genreArt House & International   9.5847     5.3728   1.784  0.07492 .  
## genreComedy                      0.9012     2.9631   0.304  0.76111    
## genreDocumentary                16.5874     7.0815   2.342  0.01947 *  
## genreDrama                      10.7557     2.5052   4.293 2.04e-05 ***
## genreHorror                     -6.8424     4.4366  -1.542  0.12352    
## genreMusical & Performing Arts  19.7933     6.0381   3.278  0.00110 ** 
## genreMystery & Suspense          0.9625     3.2844   0.293  0.76958    
## genreOther                      11.9933     5.0236   2.387  0.01726 *  
## genreScience Fiction & Fantasy  -3.9078     6.3397  -0.616  0.53785    
## runtime                          0.1696     0.0400   4.239 2.58e-05 ***
## mpaa_ratingNC-17               -10.6730    13.4770  -0.792  0.42869    
## mpaa_ratingPG                   -9.8586     4.8880  -2.017  0.04413 *  
## mpaa_ratingPG-13               -15.6005     4.9915  -3.125  0.00186 ** 
## mpaa_ratingR                   -10.0048     4.8423  -2.066  0.03923 *  
## mpaa_ratingUnrated              -6.4048     5.5909  -1.146  0.25241    
## best_dir_winyes                  6.0833     2.9166   2.086  0.03740 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 17.8 on 630 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.249,  Adjusted R-squared:  0.2264 
## F-statistic: 10.99 on 19 and 630 DF,  p-value: < 2.2e-16

Try to remove title_type, genre, mpaa_rating one at a time since the slope of some levels are not significant.(I use 95% confident level). However, adjusted R square are all decreasing. Hence I got the best model already (adjusted R sqare: 0.2264).

Model diagnostics

# histogram of residuals...nearly normal residuals --- condition met
hist(best_mlr$residuals)

# qqnorm
qqnorm(best_mlr$residuals)

# residual plot. residuals vs. predicted...constant variability of residuals --- condition met
plot(best_mlr$residuals ~ mlr$fitted)

# independent residuals...there is not time series structure
plot(best_mlr$residuals)

Our best model has p-value: < 2.2e-16, which is smaller than 0.05. So we can say our model has at least one of the beta that is non-zero and the model as a whole is significant. We have adjusted R sqare: 0.2264, which tells us 22.6% of the variability of the data can be explained by our model.

The model tells us that if the movie was filmed by an Oscar winning director, its audience score will be higher 6 points on average when all else held constand. If the movie time increases by 1 minute, the audience score will be up 0.17 points when all else held constand.

For the title_type, genre, mpaa_rating variables, I’m not sure how to interpret these findings. Some levels of variables are not significant, so I’m not sure if we can interpret the same way as other significant variables.

Part 5: Prediction Pick a movie from 2016: The movie I pick is “La La Land”. title_type: Feature Film Rating: PG-13 Runtime: 128 minutes Genre: Comedy, Drama, Musical & Performing Arts.let’s use Musical & Performing Arts in our analysis Director: Damien Chazelle

lalaland <- data.frame(title_type = "Feature Film",genre = "Musical & Performing Arts",runtime = 128,mpaa_rating = "PG-13",best_dir_win = "yes")
predict(best_mlr,lalaland)
##        1 
## 78.44126
predict(best_mlr,lalaland,interval = "prediction",level = 0.95)
##        fit      lwr      upr
## 1 78.44126 41.33339 115.5491

Our model predicts La La Land’s audience score to be 72.36. We have 95% confidence that the score will be within 35.59 and 109.13. Actual audience score: 81

Reference: Wikipedia: https://en.wikipedia.org/wiki/La_La_Land_(film) Rotten tomatoes: https://www.rottentomatoes.com/m/la_la_land/ * *

Part 6: Conclusion Overall, our model provides a way to predict audience score of a particular movie, based on title_type,genre,runtime,mpaa_rating,best_dir_win. It tells us if a movie were filmed by an award winning director, the score tends to be higher. However, some features of this model can not be explained very well, for example, why the higher movie runtime gets higher score? Also, some levels of variables are not significant in the model. I am not sure if we should keep them or not.