Python · Film revenue
Film Revenue & Genre Analysis
Not a Recipe
Inflation-adjusted revenue vs budget, popularity, and genre. TMDb sample.
Analyst · Python · EDA
About 10,000 TMDb titles. Dependent variable: inflation-adjusted revenue. The work is association, not a recipe for a hit.
The question
If you greenlighted from genre volume, would you actually pick the titles that earn?
Drama, Comedy, Thriller, and Action appear most often in this TMDb sample. Frequency is not the same as commercial performance. Among genres with ≥50 films that have known inflation-adjusted revenue, Animation’s median sits near $149M — Comedy’s near $47M. Budget and popularity move with adj. revenue; vote average and runtime are weaker.
Method
Pandas on the TMDb movie CSV (seaborn for the exploratory charts). Zeros in budget and revenue treated as missing (complete-case revenue work favors better-documented films). Multi-label genres expanded, so a film can sit in more than one bar. Runnable copy: python/tmdb_revenue.py.
Python
The extract repeats one title and includes a handful of rows with no IMDb id. After those are set aside, zeros in the money columns are missing — not a budget of zero. The CSV is not in this repo.
import pandas as pd
import numpy as np
movies = pd.read_csv("data_wrangling/raw/tmdb-movies.csv")
movies = movies.drop_duplicates()
movies = movies.dropna(subset=["imdb_id"])
for col in ("budget", "revenue", "budget_adj", "revenue_adj"):
movies[col] = movies[col].replace(0, np.nan)
revenue = movies.dropna(subset=["revenue_adj"])
# Budget and popularity move with inflation-adjusted revenue.
# Vote average and runtime are weaker. Association, not a cause.
assoc = revenue[
["budget_adj", "popularity", "vote_average", "runtime", "revenue_adj"]
].corr()["revenue_adj"]
# Frequency is not revenue. Drama, Comedy, Thriller, and Action lead the counts.
genre_counts = movies["genres"].dropna().str.split("|").explode().value_counts()
# A film with several genres is counted in each median.
# Keep genres with at least 50 films that have known revenue_adj.
expanded = (
revenue.dropna(subset=["genres"])
.assign(genre=lambda frame: frame["genres"].str.split("|"))
.explode("genre")
)
genre_medians = (
expanded.groupby("genre")["revenue_adj"]
.agg(n="count", median="median")
.query("n >= 50")
.sort_values("median", ascending=False)
)
# Animation ~$149M (n=237); Adventure ~$115M (n=843); Comedy ~$47M (n=1,771).
year_counts = movies["release_year"].value_counts()
# Peak year 2014, 699 titles.
year_vs_popularity = movies["release_year"].corr(movies["popularity"]) # ~0.09
year_vs_revenue = revenue["release_year"].corr(revenue["revenue_adj"]) # ~−0.10
Findings
Budget and popularity show the strongest positive associations with high inflation-adjusted revenue. Vote average and runtime are weaker. That is a pattern in this sample, not proof that buying a bigger budget causes a bigger box office.
Drama, Comedy, Thriller, and Action appear most often. Frequency is not the same as commercial performance. Among genres with at least 50 films that have known revenue:
Median revenue_adj in millions of 2010 USD. Animation n=237; Adventure n=843; Comedy n=1,771.
The extract includes far more recent movies (peak year 2014, 699 titles). Popularity is mildly higher for more recent films (year vs popularity corr 0.09). Mean inflation-adjusted revenue by year is volatile — blockbusters and missing financials move the line. Year vs revenue corr is −0.10.
So what
If you are ranking “what the data says about hits,” start with budget and popularity, then genre mix — not with “newer films automatically make more.” Comedy is everywhere and not the median-revenue leader.
Limitations
- About half of movies have missing or zero budget/revenue.
- Treating zeros as missing can hide a few true low-value titles.
- Expanded genres double-count films.
- TMDb popularity is platform-specific and may favor newer or more discussed titles.
- No causal claim.
Next research I would actually run: ROI (revenue_adj / budget_adj) and genre performance inside the same decade, controlling for vote count.