Lesson 28 · Real-World Data Analytics
Python Data Analytics #28: Email Marketing Performance Analysis in Python
Video twenty-eight of the hundred-video real-world data analytics series. Real published email marketing benchmarks across forty-five real industries, from…
- CourseReal-World Data Analytics
- Lesson28 of 100
- FormatJupyter notebook · 30 code cells
- Data1 dataset
What you'll learn
Datasets used in this lesson
Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.
📓 Full notebook
Download .ipynbData Analytics 100, Video 28: Email Marketing Performance Analysis#
- Video twenty-eight of the hundred-video real-world data analytics series.
- Real published email marketing benchmarks across forty-five real industries, from a real report covering 3.6 million real campaigns.
- Let's get into it.
Part 1: Real Benchmarks, Real Industries#
import pandas as pd
import matplotlib.pyplot as plt
benchmarks = pd.read_csv('email_marketing_benchmarks_2026.csv')
benchmarks.shape
Part 2: Real Data Preview#
benchmarks.head(5)
benchmarks.describe().round(2)
Part 3: Real Top Open Rate Industries#
top_open_rate = benchmarks.sort_values('Open_Rate_Pct', ascending=False).head(10)
top_open_rate[['Industry', 'Open_Rate_Pct']]
Part 4: Real Bottom Open Rate Industries#
bottom_open_rate = benchmarks.sort_values('Open_Rate_Pct').head(10)
bottom_open_rate[['Industry', 'Open_Rate_Pct']]
Part 5: Visualizing Real Open Rates#
top10 = benchmarks.sort_values('Open_Rate_Pct', ascending=False).head(10)
plt.figure(figsize=(9, 6))
plt.barh(top10['Industry'], top10['Open_Rate_Pct'], color='steelblue')
plt.xlabel('Real Open Rate (%)')
plt.title('Real Top 10 Industries by Email Open Rate')
plt.gca().invert_yaxis()
plt.tight_layout()
plt.savefig('top_open_rates.png', dpi=120)
plt.close()
Part 6: Real Click Rate Leaders#
top_click_rate = benchmarks.sort_values('Click_Rate_Pct', ascending=False).head(10)
top_click_rate[['Industry', 'Click_Rate_Pct']]
Part 7: Real Open Rate vs Click Rate, Are They Related?#
open_click_corr = benchmarks['Open_Rate_Pct'].corr(benchmarks['Click_Rate_Pct'])
round(open_click_corr, 3)
Part 8: Visualizing the Real Weak Relationship#
plt.figure(figsize=(8, 6))
plt.scatter(benchmarks['Open_Rate_Pct'], benchmarks['Click_Rate_Pct'], color='darkorange', s=40)
plt.xlabel('Real Open Rate (%)')
plt.ylabel('Real Click Rate (%)')
plt.title('Real Open Rate vs Click Rate by Industry')
plt.tight_layout()
plt.savefig('open_vs_click_scatter.png', dpi=120)
plt.close()
Part 9: Real Click-to-Open Rate, The Content Signal#
top_ctor = benchmarks.sort_values('Click_To_Open_Rate_Pct', ascending=False).head(10)
top_ctor[['Industry', 'Click_To_Open_Rate_Pct']]
Part 10: Real Low Open, High CTOR Industries#
median_open = benchmarks['Open_Rate_Pct'].median()
median_ctor = benchmarks['Click_To_Open_Rate_Pct'].median()
hidden_gems = benchmarks[(benchmarks['Open_Rate_Pct'] < median_open) & (benchmarks['Click_To_Open_Rate_Pct'] > median_ctor)]
hidden_gems[['Industry', 'Open_Rate_Pct', 'Click_To_Open_Rate_Pct']]
Part 11: Real Unsubscribe Rate Leaders#
top_unsub = benchmarks.sort_values('Unsubscribe_Rate_Pct', ascending=False).head(10)
top_unsub[['Industry', 'Unsubscribe_Rate_Pct']]
Part 12: Real Lowest Unsubscribe Rate Industries#
bottom_unsub = benchmarks.sort_values('Unsubscribe_Rate_Pct').head(10)
bottom_unsub[['Industry', 'Unsubscribe_Rate_Pct']]
Part 13: Real Correlation, Open Rate and Unsubscribe Rate#
open_unsub_corr = benchmarks['Open_Rate_Pct'].corr(benchmarks['Unsubscribe_Rate_Pct'])
round(open_unsub_corr, 3)
Part 14: Real All-Metric Correlation Matrix#
metric_cols = ['Open_Rate_Pct', 'Click_Rate_Pct', 'Click_To_Open_Rate_Pct', 'Unsubscribe_Rate_Pct']
correlation_matrix = benchmarks[metric_cols].corr().round(3)
correlation_matrix
Part 15: Real Overall Industry Benchmark#
overall_open = round(benchmarks['Open_Rate_Pct'].median(), 2)
overall_click = round(benchmarks['Click_Rate_Pct'].median(), 2)
overall_open, overall_click
Part 16: Real Campaign Benchmarking Function#
def benchmark_campaign(industry_name, my_open_rate, my_click_rate):
row = benchmarks[benchmarks['Industry'] == industry_name].iloc[0]
open_diff = round(my_open_rate - row['Open_Rate_Pct'], 2)
click_diff = round(my_click_rate - row['Click_Rate_Pct'], 2)
return {'open_rate_vs_benchmark': open_diff, 'click_rate_vs_benchmark': click_diff}
benchmark_campaign('e-commerce', 35.0, 1.5)
Part 17: Real Testing the Function on Another Industry#
benchmark_campaign('Non-profit', 48.0, 3.5)
Part 18: Real Distribution of Open Rates#
plt.figure(figsize=(9, 5))
plt.hist(benchmarks['Open_Rate_Pct'], bins=15, color='mediumseagreen', edgecolor='white')
plt.axvline(overall_open, color='crimson', linestyle='--', label=f'Real Median: {overall_open}%')
plt.xlabel('Real Open Rate (%)')
plt.ylabel('Real Number of Industries')
plt.title('Real Distribution of Email Open Rates Across Industries')
plt.legend()
plt.tight_layout()
plt.savefig('open_rate_distribution.png', dpi=120)
plt.close()
Part 19: Real Range Check, Click Rate#
click_range = round(benchmarks['Click_Rate_Pct'].max() - benchmarks['Click_Rate_Pct'].min(), 2)
click_range
Part 20: Real Industries Above the Overall Median on Every Metric#
medians = benchmarks[metric_cols].median()
all_star = benchmarks[(benchmarks['Open_Rate_Pct'] > medians['Open_Rate_Pct']) & (benchmarks['Click_Rate_Pct'] > medians['Click_Rate_Pct']) & (benchmarks['Unsubscribe_Rate_Pct'] < medians['Unsubscribe_Rate_Pct'])]
all_star[['Industry']]
Part 21: Real Worst-Performing Industries Overall#
struggling = benchmarks[(benchmarks['Open_Rate_Pct'] < medians['Open_Rate_Pct']) & (benchmarks['Click_Rate_Pct'] < medians['Click_Rate_Pct'])]
len(struggling), struggling['Industry'].tolist()[:10]
Part 22: Real Ranking by Composite Engagement Score#
benchmarks['engagement_score'] = (benchmarks['Open_Rate_Pct'] * 0.3 + benchmarks['Click_Rate_Pct'] * 10 * 0.4 + benchmarks['Click_To_Open_Rate_Pct'] * 0.3).round(2)
benchmarks.sort_values('engagement_score', ascending=False)[['Industry', 'engagement_score']].head(10)
Part 23: Real Bottom of the Composite Ranking#
benchmarks.sort_values('engagement_score')[['Industry', 'engagement_score']].head(10)
Part 24: Real Legal Industry Deep Dive#
legal_row = benchmarks[benchmarks['Industry'] == 'Legal'].iloc[0]
legal_row[metric_cols]
Part 25: Real Retail vs E-commerce Comparison#
retail_ecom = benchmarks[benchmarks['Industry'].isin(['Retail', 'e-commerce'])]
retail_ecom[['Industry'] + metric_cols]
Part 26: Saving the Real Ranked Benchmark Table#
ranked_benchmarks = benchmarks.sort_values('engagement_score', ascending=False).reset_index(drop=True)
ranked_benchmarks.to_csv('ranked_email_benchmarks.csv', index=False)
reloaded_ranked = pd.read_csv('ranked_email_benchmarks.csv')
reloaded_ranked.shape == ranked_benchmarks.shape
Part 27: Real Sanity Check, Percentages in Range#
all((0 <= benchmarks['Open_Rate_Pct']) & (benchmarks['Open_Rate_Pct'] <= 100)) and all((0 <= benchmarks['Click_Rate_Pct']) & (benchmarks['Click_Rate_Pct'] <= 100))
Part 28: Real Sanity Check, No Duplicate Industries#
benchmarks['Industry'].is_unique
Part 29: Real Takeaway for a Hypothetical Campaign#
my_result = benchmark_campaign('Software and web app', 41.0, 1.3)
my_result
Part 30: Real Recap Print#
top_industry = benchmarks.sort_values('engagement_score', ascending=False).iloc[0]['Industry']
print(f'Across {len(benchmarks)} real industries, the median open rate was {overall_open}% and median click rate was {overall_click}%, with {top_industry} posting the real strongest composite email performance.')
Wrap-Up: What You Learned#
- Real published industry benchmarks give any marketer an honest yardstick, without one, a raw open or click rate number means very little.
- Open rate and click rate turned out to be only weakly correlated across real industries, confirming they genuinely measure different things.
- Click-to-open rate isolates real content quality specifically, separate from how many people opened the email in the first place.
- A real simple reusable benchmarking function makes comparing any real campaign against its real industry standard fast and repeatable.
- Combining several real metrics into one composite score is a real practical way to rank performance across many real categories at once.
- Next video: real airline customer sentiment analysis, returning to real text analysis with a real single-brand deep dive.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



