Loading libraries (tidyverse, dplyr, patchwork)
# Load libraries
library(tidyverse)
library(dplyr)
library(patchwork)Felix G.
University of Kansas - PSYC 399
Sev T.
Alayna C.
Emry L.
May 5, 2025
May 5, 2025
For our project, we looked at IMDB’s top 1000 movies (Chong) and each chose a different relationship to analyse to delve deeper.
## Summarize by Genres
imdbGenres <- imdbClean |>
dplyr::summarize(
genreTotal = sum(gross_m, na.rm = TRUE),
gross = (gross_m),
films = n_distinct(title, na.rm = TRUE),
.by = genre
)
## Summarize by Metascores
imdb_meta_na <- imdbClean|>
mutate(metascore = na_if(metascore, 0))
genre_metascore <- dplyr::summarize(
imdbClean,
.by = genre,
mmetascore = mean(metascore)) |>
arrange(desc(mmetascore))
## Sumamrize by Gross Revenue
imdb_gross_na <- imdbClean |>
mutate(
gross = if_else(`gross_m` == 0, NA, `gross_m`))
director_summary <- imdb_gross_na |>
group_by(director) |>
dplyr::summarize(
avg_rating = mean(rating, na.rm = TRUE),
avg_gross = mean(gross, na.rm = TRUE),
n_movies = n())To find our dataset, our group went through Kaggle to find something that caught our eye. We decided we wanted to look at movies, so after debating several datasets, we settled on “IMDB Top 1000 Movies”. The dataset was already cleaned, so we did not have to do much as far as wrangling, but we did change the name of “gross(M)” to avoid complications with parentheses and changed metascore values of zero because these films did not have pages on metacritic, where this score comes from. From there, we used summarize to calculate the total gross revenue, the number of films per genre, and mean metascores by genre.
Each group member chose a relationship they wanted to consider from there.
df_unique <- imdbClean %>%
distinct(title, gross_m, .keep_all = TRUE)
top10_grossing <- df_unique %>%
arrange(desc(gross_m)) %>%
slice_head(n = 10)
ggplot(top10_grossing, aes(x = reorder(title, gross_m), y = gross_m)) +
geom_point(size = 1.5) +
labs(title = "Top 10 Grossing Movies by Box Office Income",
x = "Movie Title",
y = "Gross Income (in Millions)") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))My part in the Unit 2 Project was to create a ggplot based on the top 10 grossing movies in terms of box office income (movies ~ gross_m). I tidied my dataset using the distinct() code to ensure the movie titles aligned with their gross income. Next, I used arrange() and slice_head() to separate the top 10 highest-grossing movies from the rest of the dataset. For the visual aid, I made a scatterplot using ggplot2. I mapped the movie titles to the x-axis and the gross income to the y-axis. The results show which movies had the highest box office income. I also used minimal theming and angled my x-axis movie titles
top_5_metascore <-
imdb_meta_na |>
filter(genre %in% c("Western", "Animation", "Film-Noir", "War", "Sci-Fi", "Thriller", "Comedy", "Crime", "Action", "Musical")) |>
mutate(
genre = factor(genre, c("Western", "Animation", "Film-Noir", "War", "Sci-Fi", "Thriller", "Comedy", "Crime", "Action", "Musical"))
)
ggplot(top_5_metascore, aes(x = metascore, y = rating, color = genre)) +
geom_point(na.rm = TRUE) + geom_abline(intercept = 0, slope = 1/10) +
facet_wrap(~genre) +
labs(
title = "Metascore by User Rating Across Genres",
x = "User Rating",
y = "Metascore (Critic Rating)"
)For my code, I looked at the metascore (a number created by a site called metacritic that looks at critic reviews, taking into consideration said critic’s reputation) against IMDB user ratings by genre. I used the summary of mean metascore by genre to find the average highest five and lowest five ranked genres, and focused on these 10 genres for my visualization so as to not overwhelm the viewer.
I used factoring to reorder the data so it would come across in order when I faceted the data. I also decided to use geom_abline to add a line through the visualizations with a slope of 1/10 to make it easier to compare the scores since metascore is out of 100 and rating is out of 10 and uses decimals.
From this visualization, I found that critics and the common viewer overall feel relatively similarly about film genres. However, IMDB users ranked Film-Noir, War, and Animation higher than critics. Critics rated Action, Sci-Fi, and Crime higher than users.
top_directors <- director_summary |>
arrange(desc(avg_rating)) |>
filter(row_number() <= 15)
top_directors |>
ggplot(aes(x = avg_rating, y = avg_gross)) +
geom_point() +
geom_text(aes(label = director), vjust = -0.5, size = 2.8) +
labs(
title = "Top 15 Directors by Average Rating",
x = "Average IMDb Rating",
y = "Average Gross (in millions)"
)The purpose of my code was to look at each of the top 15 directors that made the most gross money. Some of the data had missing data so I replaced the 0 with NA so it would not be included in the calculations. Then I grouped the data to director to filter it. Then, I found each director’s average imdb rating because I wanted to get the top 15 directors by rating. I also averaged their gross earnings & movies because some of the directors made more than one movie and this would be a fair way to see how much money they make on average. After I did that, I made it select the top 15 directors with the highest imdb rating using the filter command. Then I plotted their average using ggplot geompoint. The x axis was the average imdb rating of the director and the y axis was the average gross these actors made which was in millions.
imdbGenres1 <- imdbGenres |>
mutate(genre = fct_reorder(genre, films, .desc = TRUE)) |>
ggplot(aes(x = genre, y = gross)) + geom_boxplot() +
labs(
title = "IMDB's top 1000 movies: Gross revenue per genre",
x = "Film genre (in order of total films)",
y = "Gross revenue in millions ($)"
) +
stat_summary(
fun = "mean",
geom = "point",
color = "blue"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1)
)
imdbGenres2 <- imdbGenres |>
mutate(genre = fct_reorder(genre, genreTotal, .desc = TRUE)) |>
ggplot(aes(x = genre, y = gross)) + geom_boxplot() +
labs(
x = "Film genre (in order of total gross revenue)",
y = "Gross revenue in millions ($)"
) +
stat_summary(
fun = "mean",
geom = "point",
color = "blue"
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1)
)
imdbGenres1 / imdbGenres2I wanted to focus on gross revenue for the genres to see whether genre is a good predictor of gross revenue. I chose a boxplot for this, as it shows the interquartile range and clearly shows outliers.
I then added a stat_summary to show the mean. As we can see, the mean is higher the the median (50th percentile) in almost every genre, which suggests that the distribution is skewed towards higher revenue. On the surface we can see that the genres Adventure, Action, Sci-Fi, Animation, and Fantasy show significantly higher revenue than other genres.
Finally, I used Patchwork to display both versions of the graph: ordered by total number of films, and ordered by total gross revenue.
We discovered multiple shortcomings with this dataset.
First, there were many films with a metacritic score of 0, which we interpreted as missing data. To fix this, we converted those entries to NA to remove them for the metascore analysis.
Second, the top 15 directors showed a significant overlapping grouping around the origin point of the graph, suggesting less variance between directors with lower scores. To alleviate this, we decided to remove those data point from the graph to highlight the top 7 directors with greater variance between scores.
Finally, many of the films in this list have multiple genres. Therefore, the gross revenue of a single film could be added to multiple genres. For example, Star Wars: The Force Awakens is Action, Adventure, and Sci-FI, meaning that its $936.66 million is added to all three genres total gross figure. All of the top 10 movies by gross revenue have 2 or more genres. The resulting graph suggests that Adventure, Action, Sci-Fi, Animation, and Fantasy produce higher gross revenue, but it is likely that many blockbuster films overlap in these common genres.
To alleviate this, we recommend that future analysis should include Principal Component Analysis to discover factor loadings associated with genre.
Chong, A. (updated 2023). IMDB Top 1000 Movies [Data set]. Kaggle. https://www.kaggle.com/datasets/arthurchongg/imdb-top-1000-movies