Since the 1930s, Walt Disney Studios has released more than 600 films covering a wide range of genres. While some movies are indeed directed towards kids, many are intended for a broad audience. In this project, you will analyze data to see how Disney movies have changed in popularity since its first movie release. You will also perform hypothesis testing to see what aspects of a movie contribute to its success. The dataset used in this project is a modified version of the Disney Character Success dataset from Kelly Garrett. This is the Result of Project "Disney Movies and Box Office Success", via datacamp.
Walt Disney Studios is the foundation on which The Walt Disney Company was built. The Studios has produced more than 600 films since their debut film, Snow White and the Seven Dwarfs in 1937. While many of its films were big hits, some of them were not. In this notebook, we will explore a dataset of Disney movies and analyze what contributes to the success of Disney movies.
First, we will take a look at the Disney data compiled by Kelly Garrett. The data contains 579 Disney movies with six features: movie title, release date, genre, MPAA rating, total gross, and inflation-adjusted gross.
Let's load the file and see what the data looks like.
# Import pandas library
import pandas as pd
# Read the file into gross
gross = pd.read_csv('./dataset/disney_movies_total_gross.csv', parse_dates=['release_date'])
# Print out gross
gross.head()
movie_title | release_date | genre | mpaa_rating | total_gross | inflation_adjusted_gross | |
---|---|---|---|---|---|---|
0 | Snow White and the Seven Dwarfs | 1937-12-21 | Musical | G | 184925485 | 5228953251 |
1 | Pinocchio | 1940-02-09 | Adventure | G | 84300000 | 2188229052 |
2 | Fantasia | 1940-11-13 | Musical | G | 83320000 | 2187090808 |
3 | Song of the South | 1946-11-12 | Adventure | G | 65000000 | 1078510579 |
4 | Cinderella | 1950-02-15 | Drama | G | 85000000 | 920608730 |
Let's started by exploring the data. We will check which are the 10 Disney movies that have earned the most at the box office. We can do this by sorting movies by their inflation-adjusted gross (we will call it adjusted gross from this point onward).
# Sort data by the adjusted gross in descending order
gross = gross.sort_values('inflation_adjusted_gross', ascending=False)
# Display the top 10 movies
gross.head(10)
movie_title | release_date | genre | mpaa_rating | total_gross | inflation_adjusted_gross | |
---|---|---|---|---|---|---|
0 | Snow White and the Seven Dwarfs | 1937-12-21 | Musical | G | 184925485 | 5228953251 |
1 | Pinocchio | 1940-02-09 | Adventure | G | 84300000 | 2188229052 |
2 | Fantasia | 1940-11-13 | Musical | G | 83320000 | 2187090808 |
8 | 101 Dalmatians | 1961-01-25 | Comedy | G | 153000000 | 1362870985 |
6 | Lady and the Tramp | 1955-06-22 | Drama | G | 93600000 | 1236035515 |
3 | Song of the South | 1946-11-12 | Adventure | G | 65000000 | 1078510579 |
564 | Star Wars Ep. VII: The Force Awakens | 2015-12-18 | Adventure | PG-13 | 936662225 | 936662225 |
4 | Cinderella | 1950-02-15 | Drama | G | 85000000 | 920608730 |
13 | The Jungle Book | 1967-10-18 | Musical | Not Rated | 141843000 | 789612346 |
179 | The Lion King | 1994-06-15 | Adventure | G | 422780140 | 761640898 |
From the top 10 movies above, it seems that some genres are more popular than others. So, we will check which genres are growing stronger in popularity. To do this, we will group movies by genre and then by year to see the adjusted gross of each genre in each year.
# Extract year from release_date and store it in a new column
gross['release_year'] = gross['release_date'].dt.year
# Compute mean of adjusted gross per genre and per year
group = gross.groupby(['genre', 'release_year']).mean()
# Convert the GroupBy object to a DataFrame
genre_yearly = group.reset_index()
# Inspect genre_yearly
genre_yearly.head(10)
genre | release_year | total_gross | inflation_adjusted_gross | |
---|---|---|---|---|
0 | Action | 1981 | 0.0 | 0.0 |
1 | Action | 1982 | 26918576.0 | 77184895.0 |
2 | Action | 1988 | 17577696.0 | 36053517.0 |
3 | Action | 1990 | 59249588.5 | 118358772.0 |
4 | Action | 1991 | 28924936.5 | 57918572.5 |
5 | Action | 1992 | 29028000.0 | 58965304.0 |
6 | Action | 1993 | 21943553.5 | 44682157.0 |
7 | Action | 1994 | 19180582.0 | 39545796.0 |
8 | Action | 1995 | 63037553.5 | 122162426.5 |
9 | Action | 1996 | 135281096.0 | 257755262.5 |
We will make a plot out of these means of groups to better see how box office revenues have changed over time.
# Import seaborn library
import seaborn as sns
# Plot the data
sns.relplot(x='release_year', y='inflation_adjusted_gross', kind='line', hue='genre', data=genre_yearly);
The line plot supports our belief that some genres are growing faster in popularity than others. For Disney movies, Action and Adventure genres are growing the fastest. Next, we will build a linear regression model to understand the relationship between genre and box office gross.
Since linear regression requires numerical variables and the genre variable is a categorical variable, we'll use a technique called one-hot encoding to convert the categorical variables to numerical. This technique transforms each category value into a new column and assigns a 1 or 0 to the column.
For this dataset, there will be 11 dummy variables, one for each genre except the action genre which we will use as a baseline. For example, if a movie is an adventure movie, like The Lion King, the adventure variable will be 1 and other dummy variables will be 0. Since the action genre is our baseline, if a movie is an action movie, such as The Avengers, all dummy variables will be 0.
# Convert genre variable to dummy variables
genre_dummies = pd.get_dummies(gross['genre'], drop_first=True)
# Inspect genre_dummies
genre_dummies.head()
Adventure | Black Comedy | Comedy | Concert/Performance | Documentary | Drama | Horror | Musical | Romantic Comedy | Thriller/Suspense | Western | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
8 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
Now that we have dummy variables, we can build a linear regression model to predict the adjusted gross using these dummy variables.
From the regression model, we can check the effect of each genre by looking at its coefficient given in units of box office gross dollars. We will focus on the impact of action and adventure genres here. (Note that the intercept and the first coefficient values represent the effect of action and adventure genres respectively). We expect that movies like the Lion King or Star Wars would perform better for box office.
# Import LinearRegression
from sklearn.linear_model import LinearRegression
# Build a linear regression model
regr = LinearRegression()
# Fit regr to the dataset
regr.fit(genre_dummies, gross['inflation_adjusted_gross'])
# Get estimated intercept and coefficient values
action = regr.intercept_
adventure = regr.coef_[[0]][0]
# Inspect the estimated intercept and coefficient values
print((action, adventure))
(102921757.3684249, 87475654.70909435)
Next, we will compute 95% confidence intervals for the intercept and coefficients. The 95% confidence intervals for the intercept a and coefficient bi means that the intervals have a probability of 95% to contain the true value a and coefficient bi respectively. If there is a significant relationship between a given genre and the adjusted gross, the confidence interval of its coefficient should exclude 0.
We will calculate the confidence intervals using the pairs bootstrap method.
# Import a module
import numpy as np
# Create an array of indices to sample from
inds = np.arange(0, len(gross['genre']))
# Initialize 500 replicate arrays
size = 500
bs_action_reps = np.empty(size)
bs_adventure_reps = np.empty(size)
After the initialization, we will perform pair bootstrap estimates for the regression parameters. Note that we will draw a sample from a set of (genre, adjusted gross) data where the genre is the original genre variable. We will perform one-hot encoding after that.
# Generate replicates
for i in range(size):
# Resample the indices
bs_inds = np.random.choice(inds, len(inds))
# Get the sampled genre and sampled adjusted gross
bs_genre = gross['genre'][bs_inds]
bs_gross = gross['inflation_adjusted_gross'][bs_inds]
# Convert sampled genre to dummy variables
bs_dummies = pd.get_dummies(bs_genre, drop_first=True)
# Build and fit a regression model
regr = LinearRegression().fit(bs_dummies, bs_gross)
# Compute replicates of estimated intercept and coefficient
bs_action_reps[i] = regr.intercept_
bs_adventure_reps[i] = regr.coef_[[0]][0]
Finally, we compute 95% confidence intervals for the intercept and coefficient and examine if they exclude 0. If one of them (or both) does, then it is unlikely that the value is 0 and we can conclude that there is a significant relationship between that genre and the adjusted gross.
# Compute 95% confidence intervals for intercept and coefficient values
confidence_interval_action = np.percentile(bs_action_reps, q=[2.5, 97.5])
confidence_interval_adventure = np.percentile(bs_adventure_reps, q=[2.5, 97.5])
# Inspect the confidence intervals
print(confidence_interval_action)
print(confidence_interval_adventure)
[7.20856440e+07 1.41776418e+08] [3.80589078e+07 1.42892272e+08]
The confidence intervals from the bootstrap method for the intercept and coefficient do not contain the value zero, as we have already seen that lower and upper bounds of both confidence intervals are positive. These tell us that it is likely that the adjusted gross is significantly correlated with the action and adventure genres.
From the results of the bootstrap analysis and the trend plot we have done earlier, we could say that Disney movies with plots that fit into the action and adventure genre, according to our data, tend to do better in terms of adjusted gross than other genres. So we could expect more Marvel, Star Wars, and live-action movies in the upcoming years!
# should Disney studios make more action and adventure movies?
more_action_adventure_movies = True