Summarising Findings in a Report
Compile key insights into a structured markdown summary with embedded visualisation references and actionable next steps.
Summarising Findings in a Report is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why a Structured EDA Report Matters
Raw Jupyter notebooks with hundreds of plots and code cells are difficult to share with stakeholders who need to act on findings. A structured EDA summary report distils the most important insights from all your univariate and bivariate analysis into a clear narrative. Good reports separate findings (what the data shows) from implications (what to do about it) and include supporting visualisations only for key claims.
The Six Sections of an EDA Report
A professional EDA report typically contains six sections: 1) Dataset Overview (shape, source, time period), 2) Data Quality Issues (missing values, outliers, duplicates and their treatment), 3) Key Variable Distributions (most important numeric and categorical columns), 4) Correlations and Associations (highest-magnitude relationships found), 5) Subgroup Insights (group differences that matter for the business question), and 6) Recommended Next Steps (cleaning actions, modelling suggestions).
Writing the Dataset Overview Section
The overview section should be generated programmatically to ensure it is always accurate. Capture shape, column names and dtypes, date range (if applicable), and the source or version of the dataset. Writing this section in code rather than prose prevents the common error of describing a 10,000-row dataset in a report that was actually generated from a 9,800-row cleaned version.
import pandas as pd
import seaborn as sns
df = sns.load_dataset('titanic')
print('=== DATASET OVERVIEW ===')
print(f'Shape: {df.shape[0]:,} rows x {df.shape[1]} columns')
print(f'Columns: {", ".join(df.columns)}')
print(f'Numeric: {df.select_dtypes("number").shape[1]} columns')
print(f'Categorical: {df.select_dtypes("object").shape[1]} columns')
print(f'Boolean: {df.select_dtypes("bool").shape[1]} columns')
print(f'Total missing cells: {df.isna().sum().sum():,}')
print(f'Duplicate rows: {df.duplicated().sum()}')Writing the Data Quality Section
The data quality section lists every issue found and the decision made for each. Use a table format with columns: Column, Issue, Severity (High/Medium/Low), Action Taken. Compute this table programmatically from the profiling results so it updates automatically when the data changes. Severity should reflect business impact — a missing target variable is High, a missing non-predictive column may be Low.
import pandas as pd
import seaborn as sns
df = sns.load_dataset('titanic')
# Auto-generate data quality table
missing_pct = (df.isna().sum() / len(df) * 100).round(1)
quality = missing_pct[missing_pct > 0].to_frame(name='missing_pct')
quality['severity'] = quality['missing_pct'].apply(
lambda x: 'High' if x > 30 else ('Medium' if x > 10 else 'Low')
)
quality['action'] = quality['missing_pct'].apply(
lambda x: 'Drop column' if x > 50 else 'Impute or flag'
)
print(quality.to_string())Generating Multi-Panel Summary Figures
A summary figure combines several plots into one image that can be embedded in a report. Use plt.subplots(rows, cols) to create a grid and assign each key finding its own panel. Save the figure with savefig() at a DPI appropriate for the output format (150 for screen, 300 for print). Title each panel with a clear finding statement like 'Fare is right-skewed (skew=4.1)' rather than just the column name.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = sns.load_dataset('titanic')
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 1. Fare distribution
sns.histplot(df['fare'], kde=True, bins=30, ax=axes[0][0])
axes[0][0].set_title('Fare is right-skewed (skew=4.1)')
# 2. Survival by class
survival = df.groupby('class')['survived'].mean().reset_index()
sns.barplot(data=survival, x='class',
y='survived', order=['First', 'Second', 'Third'], ax=axes[0][1])
axes[0][1].set_title('Survival Rate Drops by Class')
# 3. Age distribution
sns.histplot(df['age'].dropna(), kde=True, bins=25, ax=axes[1][0], color='coral')
axes[1][0].set_title('Age: Near-Normal, Missing 20%')
# 4. Embarkation counts
sns.countplot(data=df, x='embarked', ax=axes[1][1], palette='Set2')
axes[1][1].set_title('Most Boarded at Southampton')
plt.tight_layout()
plt.savefig('/tmp/eda_summary.png', dpi=150, bbox_inches='tight')
plt.show()
print('Saved: /tmp/eda_summary.png')Writing Findings as Narrative Text
Each key finding should be stated as a business-relevant sentence, not a technical description. Instead of 'The fare column has skewness=4.1', write 'Ticket prices are extremely right-skewed — a small number of first-class passengers paid over 10× the median fare, which may distort revenue analyses that use mean pricing.' This translation from statistical observation to business implication is what makes EDA reports valuable to non-technical stakeholders.
Generating Markdown Reports Programmatically
You can write EDA reports as markdown files directly from Python. Build a string containing markdown headings, bullet points, and embedded image links, then write it to a .md file. This approach creates reproducible reports that update automatically when the underlying data changes, making them suitable for integration into data pipeline output artifacts or Git repositories.
import pandas as pd
import seaborn as sns
df = sns.load_dataset('titanic')
# Build a simple markdown report
lines = [
'# EDA Summary Report: Titanic Dataset',
'',
'## Overview',
f'- **Rows:** {len(df):,}',
f'- **Columns:** {df.shape[1]}',
f'- **Total Missing Cells:** {df.isna().sum().sum():,}',
'',
'## Key Findings',
'- First-class passengers had a 63% survival rate vs 24% for third class.',
'- Fare is extremely right-skewed (skew=4.1); use log transform before modelling.',
'- Age is missing in 20% of rows — median imputation recommended.',
'',
'## Recommended Next Steps',
'1. Impute age with median grouped by class.',
'2. Drop the cabin column (77% missing).',
'3. Log-transform fare before any regression modelling.',
]
with open('/tmp/eda_report.md', 'w') as f:
f.write('\n'.join(lines))
print('Report written to /tmp/eda_report.md')
print('\n'.join(lines[:10]))Exporting to HTML with Jupyter
Jupyter notebooks can be exported to HTML or PDF using jupyter nbconvert --to html notebook.ipynb. This preserves all plots, code, and markdown cells in a single shareable file that requires no Python installation to view. For a fully automated pipeline, run the notebook programmatically with papermill: papermill input.ipynb output.ipynb -p date '2024-01-01', which parameterises and executes the notebook as a script.
# To export a Jupyter notebook to HTML:
# jupyter nbconvert --to html eda_notebook.ipynb
# To parameterise and run with papermill:
# pip install papermill
# papermill eda_template.ipynb eda_2024.ipynb -p date '2024-01-01' -p min_rows 1000
# The output notebook can then be exported:
# jupyter nbconvert --to html eda_2024.ipynb
print('Jupyter nbconvert and papermill automate report generation.')Structuring Actionable Next Steps
The recommended next steps section is often the most read part of an EDA report. Structure it as a prioritised checklist: P1 (blocking) — issues that must be fixed before any analysis is valid (e.g. misidentified dtypes), P2 (important) — cleaning actions that significantly affect model performance (e.g. outlier treatment), P3 (nice to have) — enrichment ideas and additional data sources to explore. This framing makes it easy for the team to allocate effort appropriately.
Using pandas-profiling for Rapid Reporting
ydata-profiling (pip install ydata-profiling) generates a comprehensive HTML report in one call. The report includes overview statistics, variable distributions, correlations, missing value patterns, and duplicate detection — all the sections of a manual EDA report. Use it for rapid exploration at the start of a project, then write a custom summary report to highlight the most relevant findings for your specific business question.
# pip install ydata-profiling
# from ydata_profiling import ProfileReport
# import seaborn as sns
# df = sns.load_dataset('titanic')
# profile = ProfileReport(df, title='Titanic EDA')
# profile.to_file('titanic_eda.html') # interactive HTML
# profile.to_notebook_iframe() # inline in Jupyter
# Key sections in the generated report:
# - Overview: shape, missing, duplicates
# - Variables: per-column statistics and plots
# - Correlations: Pearson, Spearman, Cramers V
# - Missing values: heatmap and dendrogram
# - Duplicates: full list of duplicate rows
print('ydata-profiling generates full EDA reports with one function call.')EDA Report Anti-Patterns to Avoid
Common EDA report anti-patterns: showing every plot for every column (creates 50-page reports no one reads — select the 5-10 most important), stating facts without interpretation ('age has 177 null values' — so what should we do?), not refreshing the report after cleaning (clean the data, then redo the profiling to confirm issues were resolved), and mixing cleaning code into analysis (keep data cleaning separate from the EDA narrative).
Quick Check
Test your understanding of EDA report writing from this lesson.
Lesson Recap
In this lesson you learned: structure EDA reports into six sections (overview, quality, distributions, correlations, subgroup insights, next steps), generate multi-panel summary figures and markdown reports programmatically, and translate statistical findings into business-relevant language. Next up we explore advanced indexing techniques — MultiIndex creation and hierarchical selection in Pandas.
Frequently asked questions
Is the “Summarising Findings in a Report” lesson free?
Yes — the full text of “Summarising Findings in a Report” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.
What will I learn in “Summarising Findings in a Report”?
Compile key insights into a structured markdown summary with embedded visualisation references and actionable next steps. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Pandas & NumPy Academy?
No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Summarising Findings in a Report” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Pandas & NumPy Academy lesson?
Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Dataset Profiling Checklist
- Univariate Analysis
- Bivariate and Correlation Analysis
- Summarising Findings in a Report