Medical Coding Accuracy Audit Dashboard
Build a Power BI dashboard auditing medical coding accuracy by department.
Introduction
30 Second Summary
Every time a medical coder enters the wrong diagnosis or procedure code, the resulting claim gets denied. These errors cost healthcare organizations millions in lost revenue and create compliance risks that can trigger full-scale audits.
In this project, you will build a medical coding accuracy audit dashboard that identifies which departments fall below the industry 95% accuracy benchmark. You will use Python to clean and analyze synthetic claims data, then visualize the results in an interactive Power BI dashboard.
What You'll Build
A medical coding accuracy audit dashboard that transforms raw synthetic healthcare claims data into department-level coding accuracy insights, complete with KPI benchmarking, error type analysis, and training needs prioritization.
By the end of this project, you'll have:
- A Python data pipeline that cleans raw claims data and calculates medical coding accuracy KPIs across departments and specialties.
- A multi-sheet Excel workbook with executive summary metrics, department breakdowns, error type distributions, and training needs prioritization.
- An interactive Power BI dashboard with executive summary, department drill-down, and training needs heatmap pages that visualize performance against the 95% industry benchmark.
- Secret Mission: Add a financial impact analysis that quantifies revenue leakage per department and projects savings from accuracy improvements.
Are there any prerequisites?
You should have Python installed on your machine along with pandas. You also need Power BI Desktop (free for individual use) and Excel installed. A free Kaggle account is needed to download the dataset.
Before We Start
Before We Start...
Set Up Your Project and Download Data
Before you can analyze medical coding accuracy, you need the raw data and a working project structure.
In this step, you will download a synthetic healthcare claims dataset from Kaggle, set up your project folders, and write the initial Python script that loads and explores the data.
In this step, get ready to:
- Download the synthetic AR medical dataset from Kaggle and organize your project folder.
- Verify your Python environment and install the openpyxl package for Excel export.
- Load the dataset with pandas and identify the key columns for your audit analysis.
Download the Kaggle dataset
The dataset you will use is a fully synthetic medical billing dataset that simulates real-world claim statuses, denials, team allocation, and accounts receivable follow-up.
- Open your web browser and navigate to the Kaggle dataset page:
- https://www.kaggle.com/datasets/abuthahir1998/synthetic-ar-medical-dataset-with-realistic-denial
- Click the Download button near the top of the page.
- Sign in to your Kaggle account if prompted.
- The download will be a .zip file. Extract it to find the CSV file inside.
Now create your project folder structure and move the CSV into it.
- Open your terminal by pressing Cmd+Space (macOS) or the Windows key (Windows) and typing Terminal or PowerShell, then press Enter.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir medical-coding-audit
cd medical-coding-audit
- Create the data subfolder for your raw dataset by running:
mkdir data
- Move or copy the extracted CSV file into the data folder you just created.
- Rename the CSV file to synthetic_ar_medical_dataset.csv if it has a different name.
- Confirm the folder structure is correct by running:
ls data
You should see synthetic_ar_medical_dataset.csv listed in the output.
Finding your downloaded file
On macOS, downloaded files land in ~/Downloads. On Windows, check your Downloads folder. You can drag the extracted CSV into the data folder using Finder or File Explorer.
Don't see a CSV after extracting?
Kaggle sometimes packages downloads inside a nested folder within the zip. Look inside any subfolders in the extracted contents for a .csv file.
help me find the CSV file in my Kaggle download
Verify Python environment and install openpyxl
Your Python installation needs the openpyxl package to export analysis results to Excel later in the project.
- Confirm Python is available by running:
python --version
You should see a version number printed, confirming Python is ready.
Seeing 'command not found'?
Try python3 --version instead. On macOS and some Linux distributions, python3 is the correct command. If neither works, revisit your Python installation.
help me troubleshoot my Python installation
- Install the openpyxl package by running:
pip install openpyxl
What is openpyxl?
The openpyxl library is the engine that pandas uses under the hood when exporting DataFrames to .xlsx Excel files. Without it, the to_excel() method would fail.
- Create your Python script file by running:
touch coding_audit.py
- Confirm the file exists by running:
ls
You should see coding_audit.py and the data folder listed in the output.
Windows alternative to touch
If you are on Windows and touch is not recognized, use New-Item coding_audit.py in PowerShell instead.
- Open coding_audit.py in your preferred code editor.
Load and explore the dataset
Before building any metrics, you need to understand what columns are available and what the data looks like. This exploration step informs the column mapping you will define next.
- Add the following imports and configuration to the top of coding_audit.py:
import pandas as pd
import numpy as np
from pathlib import Path
# === CONFIGURATION ===
# Update these paths and column mappings based on your downloaded dataset
DATA_PATH = Path("data/synthetic_ar_medical_dataset.csv")
OUTPUT_PATH = Path("output/coding_audit_results.xlsx")
# Ensure output directory exists
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
What does this code do?
DATA_PATH points to the CSV you downloaded. OUTPUT_PATH defines where your final Excel workbook will be saved.
The mkdir(parents=True, exist_ok=True) line creates the output folder automatically if it does not already exist. This saves you from creating it manually.
- Add the data loading section below your configuration code:
# === STEP 1: LOAD DATA ===
print("Loading dataset...")
df = pd.read_csv(DATA_PATH)
print(f"Dataset shape: {df.shape}")
print(f"Columns: {list(df.columns)}")
print(df.head())
What does this code do?
This reads the entire CSV into a pandas DataFrame called df. The print statements show you the dataset dimensions, all column names, and the first five rows of data.
Pay close attention to the column names printed. You will use them to set up the column mapping constants next.
- Save coding_audit.py and run it to explore your data:
python coding_audit.py
You should see the dataset shape, a list of column names, and the first few rows printed to your terminal.
Seeing a FileNotFoundError?
This means DATA_PATH does not match the actual filename or location. Check that your CSV is inside the data folder and is named synthetic_ar_medical_dataset.csv. Update the DATA_PATH variable in your script if your file has a different name.
help me fix my file path
Now use the printed column names to define your column mapping. This mapping pattern makes the rest of your script flexible regardless of exact column naming in the dataset.
- Add the column mapping below your data loading code in coding_audit.py:
# === COLUMN MAPPING ===
# After exploring your data, update these mappings to match actual column names.
# Run df.columns and df.head() to identify the correct field names.
# Example mappings (adjust to your dataset):
COL_CLAIM_ID = "claim_id" # Unique claim identifier
COL_CLAIM_STATUS = "claim_status" # e.g., Approved, Denied
COL_DEPARTMENT = "department" # Department or team name
COL_DENIAL_REASON = "denial_reason" # Reason for denial
COL_CLAIM_AMOUNT = "claim_amount" # Billed amount
COL_SERVICE_DATE = "service_date" # Date of service
COL_PROVIDER_SPECIALTY = "provider_specialty" # Provider specialty
Why use a column mapping?
Datasets from different sources often use different column names for the same concept. By defining constants like COL_CLAIM_STATUS at the top, you only need to update one line if the actual column name in your CSV differs from the example.
Compare the column names printed by your script with the values in this mapping. If any column name differs, update the string value on the right side to match your dataset exactly.
- Save coding_audit.py.
What columns should you look for?
Your dataset should contain fields for: a unique claim ID, a status indicating whether the claim was approved or denied, a department or team name, a denial reason, a financial amount, a service date, and a provider specialty. The exact names may vary.
✔️ Awesome, I've got everything!
Great. Double check you have saved coding_audit.py and that running it prints the dataset shape and columns without errors.
ⓧ I'd like to double check the full code
Here is the complete coding_audit.py file at the end of this step:
import pandas as pd
import numpy as np
from pathlib import Path
# === CONFIGURATION ===
DATA_PATH = Path("data/synthetic_ar_medical_dataset.csv")
OUTPUT_PATH = Path("output/coding_audit_results.xlsx")
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
# === STEP 1: LOAD DATA ===
print("Loading dataset...")
df = pd.read_csv(DATA_PATH)
print(f"Dataset shape: {df.shape}")
print(f"Columns: {list(df.columns)}")
print(df.head())
# === COLUMN MAPPING ===
COL_CLAIM_ID = "claim_id"
COL_CLAIM_STATUS = "claim_status"
COL_DEPARTMENT = "department"
COL_DENIAL_REASON = "denial_reason"
COL_CLAIM_AMOUNT = "claim_amount"
COL_SERVICE_DATE = "service_date"
COL_PROVIDER_SPECIALTY = "provider_specialty"
Your project foundation is in place. You have raw data loaded and a clear map of which columns drive the analysis. Next up, you will clean this data and engineer the accuracy features that power the audit dashboard.
Clean Data and Engineer Features
Your raw dataset is loaded, but real-world healthcare data always contains inconsistencies. Missing fields, inconsistent casing, and duplicate records can all skew your audit metrics.
In this step, you will clean the raw claims data and then engineer new features that let you measure coding accuracy at the department level. These calculated fields form the foundation of every KPI and visualization in the rest of the project.
In this step, get ready to:
- Clean the dataset by removing incomplete rows, standardizing text, and converting dates.
- Engineer binary flags that identify denied claims and coding-specific errors.
- Build aggregation tables that summarize coding accuracy by department, error type, and month.
Clean the raw data
Before calculating any metrics, you need to ensure every row is usable. Claims missing a status or department cannot contribute to accuracy calculations and would distort your results.
- In coding_audit.py, find the last line of your column mapping section (the line that says COL_PROVIDER_SPECIALTY = "provider_specialty").
- Add the data cleaning code below it:
# === STEP 2: DATA CLEANING ===
print("\nCleaning data...")
# Drop rows missing critical fields
df = df.dropna(subset=[COL_CLAIM_STATUS, COL_DEPARTMENT])
# Standardize text columns: trim whitespace and apply title case
for col in [COL_CLAIM_STATUS, COL_DEPARTMENT, COL_DENIAL_REASON]:
if col in df.columns:
df[col] = df[col].astype(str).str.strip().str.title()
# Convert date column to datetime
if COL_SERVICE_DATE in df.columns:
df[COL_SERVICE_DATE] = pd.to_datetime(df[COL_SERVICE_DATE], errors="coerce")
# Remove exact duplicate rows
initial_count = len(df)
df = df.drop_duplicates()
print(f"Removed {initial_count - len(df)} duplicate rows")
What does this code do?
This cleaning block handles four common data quality issues in healthcare claims datasets:
- dropna(subset=[...]) removes rows that are missing a claim status or department. Without these fields, a claim cannot be classified as accurate or inaccurate.
- The for loop standardizes text by trimming whitespace and applying title case. This prevents "cardiology" and "Cardiology" from being treated as separate departments.
- pd.to_datetime() converts the service date to a proper datetime type so you can extract months and quarters later.
- drop_duplicates() removes any exact duplicate rows that would inflate claim counts.
- Save coding_audit.py.
- Run the script in your terminal:
python coding_audit.py
- You should see a line that says Removed X duplicate rows where X is the number of duplicates found (this may be 0 if the dataset has no duplicates).
Seeing a KeyError or FileNotFoundError?
- A KeyError means one of your column mapping constants does not match an actual column name in the CSV. Run print(df.columns.tolist()) and compare the output to your COL_ variables.
- A FileNotFoundError means the script cannot find the CSV. Make sure your DATA_PATH matches the actual filename in your data\ folder.
Why isn't my data cleaning script finding the CSV or recognizing column names?
Engineer coding accuracy features
Your cleaned dataset has claim statuses and denial reasons as raw text. To calculate accuracy metrics, you need binary flags that the script can sum and count against.
- In coding_audit.py, add the following feature engineering code below the cleaning section:
# === STEP 3: FEATURE ENGINEERING ===
print("\nEngineering features...")
# Binary flag: 1 if claim was denied, 0 otherwise
df["is_denied"] = (df[COL_CLAIM_STATUS].str.lower() == "denied").astype(int)
# Binary flag: 1 if denial reason contains coding-related keywords
coding_error_keywords = ["coding", "code", "invalid code", "incorrect code"]
df["is_coding_error"] = df[COL_DENIAL_REASON].str.lower().apply(
lambda x: 1 if any(kw in str(x) for kw in coding_error_keywords) else 0
)
# Extract temporal features from service date
if COL_SERVICE_DATE in df.columns and df[COL_SERVICE_DATE].notna().any():
df["service_month"] = df[COL_SERVICE_DATE].dt.to_period("M").astype(str)
df["service_quarter"] = df[COL_SERVICE_DATE].dt.to_period("Q").astype(str)
print(f"Total claims: {len(df)}")
print(f"Denied claims: {df['is_denied'].sum()}")
print(f"Coding errors: {df['is_coding_error'].sum()}")
What does this code do?
This section creates three types of engineered features:
- is_denied flags every denied claim regardless of the reason. This drives the overall denial rate metric.
- is_coding_error flags only denials caused by coding issues (not eligibility, authorization, or other reasons). This is the key column for calculating coding accuracy.
- service_month and service_quarter let you track accuracy trends over time to see if departments are improving or declining.
The keyword-matching approach for is_coding_error is flexible. If your dataset uses different terminology for coding-related denials, update the coding_error_keywords list to match.
- Save coding_audit.py and run the script again.
- You should see three summary lines printed: total claims, denied claims, and coding errors. The coding errors count should be smaller than the denied claims count (coding issues are one subset of all denial reasons).
Coding errors showing as 0?
If Coding errors: 0 prints, the keyword list may not match your dataset's denial reason values. Add a temporary line print(df[COL_DENIAL_REASON].unique()) to see the actual values, then update coding_error_keywords accordingly.
Why are my coding errors showing as zero even though I have denied claims?
Build aggregation tables
With your binary flags in place, you can now group claims by department to calculate each team's coding accuracy rate. This is where the audit story starts to emerge.
- Add the department summary aggregation below the feature engineering section in coding_audit.py:
dept_summary = df.groupby(COL_DEPARTMENT).agg(
total_claims=("is_denied", "count"),
denied_claims=("is_denied", "sum"),
coding_errors=("is_coding_error", "sum")
).reset_index()
# Calculate accuracy and benchmark comparison
dept_summary["accuracy_rate"] = 1 - (dept_summary["coding_errors"] / dept_summary["total_claims"])
dept_summary["denial_rate"] = dept_summary["denied_claims"] / dept_summary["total_claims"]
dept_summary["meets_benchmark"] = dept_summary["accuracy_rate"] >= 0.95
dept_summary["training_required"] = ~dept_summary["meets_benchmark"]
dept_summary = dept_summary.sort_values("accuracy_rate", ascending=True)
print("\nDepartment Accuracy Rates:")
print(dept_summary[[COL_DEPARTMENT, "accuracy_rate", "total_claims", "training_required"]].to_string(index=False))
What does this code do?
- groupby(COL_DEPARTMENT).agg(...) groups all claims by department and counts totals, denials, and coding errors for each.
- accuracy_rate is calculated as 1 minus the coding error rate. A department with 5 coding errors out of 100 claims has a 95% accuracy rate.
- meets_benchmark compares each department against the 95% industry standard. Departments below this threshold get flagged for training.
- Sorting by accuracy_rate ascending puts the worst performers at the top, making them immediately visible.
- Save coding_audit.py and run the script.
- You should see a printed table showing department names, their accuracy rates (varying approximately between 85-98%), total claim counts, and training status flags.
Table not printing or showing unexpected values?
- If accuracy rates all show 1.0, no coding errors were detected. Check the troubleshooting in the previous substep for keyword matching.
- If you see a DataError, ensure your is_denied and is_coding_error columns contain numeric values (0 and 1), not strings.
Why are my department accuracy rates all showing 1.0 or producing errors?
Now add the error type breakdown and monthly trends tables. These two aggregations feed into the Excel export and Power BI visualizations you will build in upcoming steps.
- Add the error type aggregation below the department summary in coding_audit.py:
error_types = df[df["is_denied"] == 1].groupby(
[COL_DEPARTMENT, COL_DENIAL_REASON]
).size().reset_index(name="error_count")
error_types = error_types.sort_values([COL_DEPARTMENT, "error_count"], ascending=[True, False])
What does this code do?
This filters the data to only denied claims, then counts how many times each denial reason occurs within each department. Sorting by count (descending) within each department highlights the most frequent error types first.
You will not see output from this code yet. The error type data feeds into the Excel export in the next step.
- Add the monthly trends aggregation below the error types code:
if "service_month" in df.columns:
monthly_trends = df.groupby("service_month").agg(
total_claims=("is_denied", "count"),
coding_errors=("is_coding_error", "sum"),
denied_claims=("is_denied", "sum")
).reset_index()
monthly_trends["accuracy_rate"] = 1 - (monthly_trends["coding_errors"] / monthly_trends["total_claims"])
monthly_trends["denial_rate"] = monthly_trends["denied_claims"] / monthly_trends["total_claims"]
else:
monthly_trends = pd.DataFrame({"Note": ["No date column available for temporal analysis"]})
What does this code do?
This groups claims by month and calculates accuracy and denial rates for each period. The else branch handles the edge case where no valid dates exist, creating a placeholder DataFrame instead of crashing.
This data powers the trend line chart in Power BI, showing whether accuracy is improving or declining over time.
- Save coding_audit.py.
The monthly trends data will appear in your Excel export in the next step. No new terminal output is expected from these two additions.
✔️ Awesome, I've got everything!
Great. Double check you have saved coding_audit.py with all three sections: cleaning, feature engineering, and aggregation tables.
ⓧ I'd like to double check the full code
Here is the complete coding_audit.py at this point:
import pandas as pd
import numpy as np
from pathlib import Path
# === CONFIGURATION ===
DATA_PATH = Path("data/synthetic_ar_medical_dataset.csv")
OUTPUT_PATH = Path("output/coding_audit_results.xlsx")
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
# === STEP 1: LOAD DATA ===
print("Loading dataset...")
df = pd.read_csv(DATA_PATH)
print(f"Dataset shape: {df.shape}")
print(f"Columns: {list(df.columns)}")
print(df.head())
# === COLUMN MAPPING ===
COL_CLAIM_ID = "claim_id"
COL_CLAIM_STATUS = "claim_status"
COL_DEPARTMENT = "department"
COL_DENIAL_REASON = "denial_reason"
COL_CLAIM_AMOUNT = "claim_amount"
COL_SERVICE_DATE = "service_date"
COL_PROVIDER_SPECIALTY = "provider_specialty"
# === STEP 2: DATA CLEANING ===
print("\nCleaning data...")
df = df.dropna(subset=[COL_CLAIM_STATUS, COL_DEPARTMENT])
for col in [COL_CLAIM_STATUS, COL_DEPARTMENT, COL_DENIAL_REASON]:
if col in df.columns:
df[col] = df[col].astype(str).str.strip().str.title()
if COL_SERVICE_DATE in df.columns:
df[COL_SERVICE_DATE] = pd.to_datetime(df[COL_SERVICE_DATE], errors="coerce")
initial_count = len(df)
df = df.drop_duplicates()
print(f"Removed {initial_count - len(df)} duplicate rows")
# === STEP 3: FEATURE ENGINEERING ===
print("\nEngineering features...")
df["is_denied"] = (df[COL_CLAIM_STATUS].str.lower() == "denied").astype(int)
coding_error_keywords = ["coding", "code", "invalid code", "incorrect code"]
df["is_coding_error"] = df[COL_DENIAL_REASON].str.lower().apply(
lambda x: 1 if any(kw in str(x) for kw in coding_error_keywords) else 0
)
if COL_SERVICE_DATE in df.columns and df[COL_SERVICE_DATE].notna().any():
df["service_month"] = df[COL_SERVICE_DATE].dt.to_period("M").astype(str)
df["service_quarter"] = df[COL_SERVICE_DATE].dt.to_period("Q").astype(str)
print(f"Total claims: {len(df)}")
print(f"Denied claims: {df['is_denied'].sum()}")
print(f"Coding errors: {df['is_coding_error'].sum()}")
dept_summary = df.groupby(COL_DEPARTMENT).agg(
total_claims=("is_denied", "count"),
denied_claims=("is_denied", "sum"),
coding_errors=("is_coding_error", "sum")
).reset_index()
dept_summary["accuracy_rate"] = 1 - (dept_summary["coding_errors"] / dept_summary["total_claims"])
dept_summary["denial_rate"] = dept_summary["denied_claims"] / dept_summary["total_claims"]
dept_summary["meets_benchmark"] = dept_summary["accuracy_rate"] >= 0.95
dept_summary["training_required"] = ~dept_summary["meets_benchmark"]
dept_summary = dept_summary.sort_values("accuracy_rate", ascending=True)
print("\nDepartment Accuracy Rates:")
print(dept_summary[[COL_DEPARTMENT, "accuracy_rate", "total_claims", "training_required"]].to_string(index=False))
error_types = df[df["is_denied"] == 1].groupby(
[COL_DEPARTMENT, COL_DENIAL_REASON]
).size().reset_index(name="error_count")
error_types = error_types.sort_values([COL_DEPARTMENT, "error_count"], ascending=[True, False])
if "service_month" in df.columns:
monthly_trends = df.groupby("service_month").agg(
total_claims=("is_denied", "count"),
coding_errors=("is_coding_error", "sum"),
denied_claims=("is_denied", "sum")
).reset_index()
monthly_trends["accuracy_rate"] = 1 - (monthly_trends["coding_errors"] / monthly_trends["total_claims"])
monthly_trends["denial_rate"] = monthly_trends["denied_claims"] / monthly_trends["total_claims"]
else:
monthly_trends = pd.DataFrame({"Note": ["No date column available for temporal analysis"]})
Your data pipeline now produces department-level accuracy metrics and trend data. Next up, you will calculate organization-wide KPIs, build a training needs prioritization, and export everything to a multi-sheet Excel workbook for Power BI.
Calculate KPIs and Export to Excel
Your data is clean, enriched with accuracy flags, and broken down by department. Now it's time to answer the core audit question: does this organization meet the industry accuracy standard?
In this step, you will calculate organization-wide KPIs, compare them against the 95% AHIMA benchmark, build a training needs priority list, and export everything into a multi-sheet Excel workbook that Power BI can consume.
In this step, get ready to:
- Calculate organization-wide coding accuracy, denial rate, and coding-specific denial rate.
- Build a training needs analysis that prioritizes underperforming departments.
- Export all analysis into a 5-sheet Excel workbook for Power BI.
Calculate organization-wide KPIs
The first question any audit answers is "how are we doing overall?" You need three numbers: the overall coding accuracy rate, the overall denial rate, and the coding-specific denial rate. The formula for coding accuracy is (Total claims - Coding errors) / Total claims.
- In coding_audit.py, scroll to the very bottom of your file (after the monthly_trends section).
- Add the KPI calculation code below by copying the following:
# === STEP 4: CALCULATE KPIs ===
print("\nCalculating KPIs...")
# Organization-wide metrics
total_claims = len(df)
total_denied = df["is_denied"].sum()
total_coding_errors = df["is_coding_error"].sum()
overall_accuracy = 1 - (total_coding_errors / total_claims)
overall_denial_rate = total_denied / total_claims
coding_denial_rate = total_coding_errors / total_claims
executive_summary = pd.DataFrame({
"Metric": [
"Total Claims Audited",
"Overall Coding Accuracy Rate",
"Industry Benchmark",
"Gap to Benchmark",
"Overall Denial Rate",
"Coding-Specific Denial Rate",
"Total Coding Errors",
"Total Denied Claims"
],
"Value": [
total_claims,
f"{overall_accuracy:.2%}",
"95.00%",
f"{(0.95 - overall_accuracy):.2%}" if overall_accuracy < 0.95 else "Above Benchmark",
f"{overall_denial_rate:.2%}",
f"{coding_denial_rate:.2%}",
total_coding_errors,
total_denied
]
})
print(f"\nOverall Coding Accuracy: {overall_accuracy:.2%}")
print(f"Industry Benchmark: 95.00%")
What does this code do?
This section computes three core KPIs from the cleaned dataset. overall_accuracy tells you the percentage of claims that did NOT have a coding error.
The executive_summary DataFrame packages these numbers into a tidy table that includes the 95% industry benchmark comparison. If the organization is below 95%, the "Gap to Benchmark" row shows how far they need to improve.
Why 95%?
The 95% accuracy rate is the de facto industry standard for medical coding, referenced by AHIMA (American Health Information Management Association). Organizations below this threshold face increased compliance risk and revenue leakage from preventable claim denials.
- Save coding_audit.py.
Seeing a ZeroDivisionError?
This means your dataset loaded with zero rows after cleaning. Go back and check that your column mapping constants (COL_CLAIM_STATUS, COL_DEPARTMENT) match the actual column names in your CSV.
help me debug a ZeroDivisionError in my KPI calculations
Build the training needs analysis
Knowing the overall accuracy is useful, but the real value is identifying which departments need intervention. A priority score combines claim volume with accuracy gap so high-volume, low-accuracy departments rise to the top.
- Add the training needs prioritization code below your KPI section:
# === STEP 5: TRAINING NEEDS PRIORITIZATION ===
print("\nBuilding training needs analysis...")
# Filter to departments that fall below 95% benchmark
training_needs = dept_summary[dept_summary["training_required"]].copy()
# Use actual average claim amount if available, otherwise default
if COL_CLAIM_AMOUNT in df.columns:
avg_claim = df[COL_CLAIM_AMOUNT].mean()
else:
avg_claim = 1000
# Calculate how far below benchmark and prioritize by volume x gap
training_needs["accuracy_gap"] = 0.95 - training_needs["accuracy_rate"]
training_needs["priority_score"] = (
training_needs["total_claims"] * training_needs["accuracy_gap"]
)
training_needs = training_needs.sort_values("priority_score", ascending=False)
What does the priority score mean?
The formula is: (Claims volume) x (Accuracy gap from 95%). A department processing 5,000 claims at 90% accuracy gets a much higher priority score than one processing 200 claims at 88%.
This ensures training resources go where they will prevent the most denials.
- Save coding_audit.py.
Training needs DataFrame is empty?
If every department is above 95% accuracy, training_needs will be empty. That is a valid result. It means no departments require training intervention based on the benchmark.
help me understand why my training_needs table is empty
Export all analysis to Excel
Power BI can import Excel workbooks directly, making .xlsx files an ideal bridge between your Python pipeline and the dashboard. You will create a single workbook with five sheets, one for each analysis dimension.
- Add the Excel export code below your training needs section:
# === STEP 6: EXPORT TO EXCEL ===
print(f"\nExporting to {OUTPUT_PATH}...")
# Write each analysis table to its own sheet in a single workbook
with pd.ExcelWriter(OUTPUT_PATH, engine="openpyxl") as writer:
executive_summary.to_excel(writer, sheet_name="Executive_Summary", index=False)
dept_summary.to_excel(writer, sheet_name="Department_Accuracy", index=False)
error_types.to_excel(writer, sheet_name="Error_Types", index=False)
training_needs.to_excel(writer, sheet_name="Training_Needs", index=False)
monthly_trends.to_excel(writer, sheet_name="Monthly_Trends", index=False)
print(f"\nExport complete! Open {OUTPUT_PATH} in Power BI Desktop.")
print(f"\nKey Finding: {len(training_needs)} department(s) require training (below 95% benchmark).")
What does this code do?
The pd.ExcelWriter context manager creates a single .xlsx file and writes each DataFrame to a named sheet. The openpyxl engine handles the actual Excel format writing behind the scenes.
The five sheets are: Executive_Summary (org-wide KPIs), Department_Accuracy (per-department breakdown), Error_Types (denial reason distribution), Training_Needs (prioritized department list), and Monthly_Trends (temporal data).
- Save coding_audit.py.
- Run the complete script by running this command in your terminal:
python coding_audit.py
- You should see output ending with the overall coding accuracy rate and the number of departments requiring training.
- Confirm the Excel file exists by running:
ls output/
- You should see coding_audit_results.xlsx listed in the output.
Seeing a ModuleNotFoundError for openpyxl?
This means the openpyxl package is not installed in your active Python environment. Run pip install openpyxl and then re-run the script.
help me fix a ModuleNotFoundError for openpyxl
- Open coding_audit_results.xlsx in Excel and verify that all 5 sheet tabs appear at the bottom of the workbook.
- Click the Executive_Summary sheet and confirm it shows the overall accuracy rate and benchmark comparison.
✔️ Awesome, I've got everything!
Great. Double check you have saved coding_audit.py and that your Excel file has all 5 sheets populated.
ⓧ I'd like to double check the full code
Here is the complete coding_audit.py file up to this point:
import pandas as pd
import numpy as np
from pathlib import Path
# === CONFIGURATION ===
DATA_PATH = Path("data/synthetic_ar_medical_dataset.csv")
OUTPUT_PATH = Path("output/coding_audit_results.xlsx")
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
# === STEP 1: LOAD DATA ===
print("Loading dataset...")
df = pd.read_csv(DATA_PATH)
print(f"Dataset shape: {df.shape}")
print(f"Columns: {list(df.columns)}")
print(df.head())
# === COLUMN MAPPING ===
COL_CLAIM_ID = "claim_id"
COL_CLAIM_STATUS = "claim_status"
COL_DEPARTMENT = "department"
COL_DENIAL_REASON = "denial_reason"
COL_CLAIM_AMOUNT = "claim_amount"
COL_SERVICE_DATE = "service_date"
COL_PROVIDER_SPECIALTY = "provider_specialty"
# === STEP 2: DATA CLEANING ===
print("\nCleaning data...")
df = df.dropna(subset=[COL_CLAIM_STATUS, COL_DEPARTMENT])
for col in [COL_CLAIM_STATUS, COL_DEPARTMENT, COL_DENIAL_REASON]:
if col in df.columns:
df[col] = df[col].astype(str).str.strip().str.title()
if COL_SERVICE_DATE in df.columns:
df[COL_SERVICE_DATE] = pd.to_datetime(df[COL_SERVICE_DATE], errors="coerce")
initial_count = len(df)
df = df.drop_duplicates()
print(f"Removed {initial_count - len(df)} duplicate rows")
# === STEP 3: FEATURE ENGINEERING ===
print("\nEngineering features...")
df["is_denied"] = (df[COL_CLAIM_STATUS].str.lower() == "denied").astype(int)
coding_error_keywords = ["coding", "code", "invalid code", "incorrect code"]
df["is_coding_error"] = df[COL_DENIAL_REASON].str.lower().apply(
lambda x: 1 if any(kw in str(x) for kw in coding_error_keywords) else 0
)
if COL_SERVICE_DATE in df.columns and df[COL_SERVICE_DATE].notna().any():
df["service_month"] = df[COL_SERVICE_DATE].dt.to_period("M").astype(str)
df["service_quarter"] = df[COL_SERVICE_DATE].dt.to_period("Q").astype(str)
print(f"Total claims: {len(df)}")
print(f"Denied claims: {df['is_denied'].sum()}")
print(f"Coding errors: {df['is_coding_error'].sum()}")
dept_summary = df.groupby(COL_DEPARTMENT).agg(
total_claims=("is_denied", "count"),
denied_claims=("is_denied", "sum"),
coding_errors=("is_coding_error", "sum")
).reset_index()
dept_summary["accuracy_rate"] = 1 - (dept_summary["coding_errors"] / dept_summary["total_claims"])
dept_summary["denial_rate"] = dept_summary["denied_claims"] / dept_summary["total_claims"]
dept_summary["meets_benchmark"] = dept_summary["accuracy_rate"] >= 0.95
dept_summary["training_required"] = ~dept_summary["meets_benchmark"]
dept_summary = dept_summary.sort_values("accuracy_rate", ascending=True)
print("\nDepartment Accuracy Rates:")
print(dept_summary[[COL_DEPARTMENT, "accuracy_rate", "total_claims", "training_required"]].to_string(index=False))
error_types = df[df["is_denied"] == 1].groupby(
[COL_DEPARTMENT, COL_DENIAL_REASON]
).size().reset_index(name="error_count")
error_types = error_types.sort_values([COL_DEPARTMENT, "error_count"], ascending=[True, False])
if "service_month" in df.columns:
monthly_trends = df.groupby("service_month").agg(
total_claims=("is_denied", "count"),
coding_errors=("is_coding_error", "sum"),
denied_claims=("is_denied", "sum")
).reset_index()
monthly_trends["accuracy_rate"] = 1 - (monthly_trends["coding_errors"] / monthly_trends["total_claims"])
monthly_trends["denial_rate"] = monthly_trends["denied_claims"] / monthly_trends["total_claims"]
else:
monthly_trends = pd.DataFrame({"Note": ["No date column available for temporal analysis"]})
# === STEP 4: CALCULATE KPIs ===
print("\nCalculating KPIs...")
total_claims = len(df)
total_denied = df["is_denied"].sum()
total_coding_errors = df["is_coding_error"].sum()
overall_accuracy = 1 - (total_coding_errors / total_claims)
overall_denial_rate = total_denied / total_claims
coding_denial_rate = total_coding_errors / total_claims
executive_summary = pd.DataFrame({
"Metric": [
"Total Claims Audited",
"Overall Coding Accuracy Rate",
"Industry Benchmark",
"Gap to Benchmark",
"Overall Denial Rate",
"Coding-Specific Denial Rate",
"Total Coding Errors",
"Total Denied Claims"
],
"Value": [
total_claims,
f"{overall_accuracy:.2%}",
"95.00%",
f"{(0.95 - overall_accuracy):.2%}" if overall_accuracy < 0.95 else "Above Benchmark",
f"{overall_denial_rate:.2%}",
f"{coding_denial_rate:.2%}",
total_coding_errors,
total_denied
]
})
print(f"\nOverall Coding Accuracy: {overall_accuracy:.2%}")
print(f"Industry Benchmark: 95.00%")
# === STEP 5: TRAINING NEEDS PRIORITIZATION ===
print("\nBuilding training needs analysis...")
training_needs = dept_summary[dept_summary["training_required"]].copy()
if COL_CLAIM_AMOUNT in df.columns:
avg_claim = df[COL_CLAIM_AMOUNT].mean()
else:
avg_claim = 1000
training_needs["accuracy_gap"] = 0.95 - training_needs["accuracy_rate"]
training_needs["priority_score"] = (
training_needs["total_claims"] * training_needs["accuracy_gap"]
)
training_needs = training_needs.sort_values("priority_score", ascending=False)
# === STEP 6: EXPORT TO EXCEL ===
print(f"\nExporting to {OUTPUT_PATH}...")
with pd.ExcelWriter(OUTPUT_PATH, engine="openpyxl") as writer:
executive_summary.to_excel(writer, sheet_name="Executive_Summary", index=False)
dept_summary.to_excel(writer, sheet_name="Department_Accuracy", index=False)
error_types.to_excel(writer, sheet_name="Error_Types", index=False)
training_needs.to_excel(writer, sheet_name="Training_Needs", index=False)
monthly_trends.to_excel(writer, sheet_name="Monthly_Trends", index=False)
print(f"\nExport complete! Open {OUTPUT_PATH} in Power BI Desktop.")
print(f"\nKey Finding: {len(training_needs)} department(s) require training (below 95% benchmark).")
Your Python pipeline is complete. You have a multi-sheet Excel workbook ready to fuel an interactive dashboard. Next up, you will import this data into Power BI and build an executive-level audit dashboard with gauges, trend lines, and KPI cards.
Build the Power BI Executive Dashboard
Your Python script has done the heavy lifting. You have an Excel workbook packed with accuracy rates, denial breakdowns, and training priorities.
Now you need to make that data talk to stakeholders who do not read spreadsheets. In this step, you will build an interactive Power BI Executive Summary page that shows at a glance whether the organization meets the 95% coding accuracy benchmark.
In this step, get ready to:
- Import all 5 Excel sheets into Power BI Desktop as data tables.
- Build KPI cards, a gauge visual, and a donut chart for the Executive Summary page.
- Add a monthly trend line chart with a 95% benchmark reference line.
Import data into Power BI
Power BI needs a data source before you can build any visuals. You will connect it to the Excel workbook your script exported.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Power BI Desktop and press Enter to open it.
- If Power BI shows a welcome screen or tutorial dialog, close it to reach the blank canvas.
- On the Home ribbon, click Get Data.
- Select Excel Workbook from the list, then click Connect.
- Browse to your project folder and select output\coding_audit_results.xlsx. Click Open.
- In the Navigator pane, check the boxes next to all 5 sheets: Executive_Summary, Department_Accuracy, Error_Types, Training_Needs, and Monthly_Trends.
- Click Load to import all tables into the Power BI data model.
After loading completes, switch to the Data view (the table icon on the left sidebar) to verify all 5 tables appear in the Fields pane on the right.
What is the Fields pane?
The Fields pane lists every table you loaded. Expand a table to see its columns. You will drag these fields onto visuals throughout the next substeps.
Don't see all 5 tables?
Go back to Home and click Get Data again. Make sure you checked all 5 sheet checkboxes in the Navigator pane before clicking Load.
If the Excel file is not showing up, confirm you ran coding_audit.py successfully and that coding_audit_results.xlsx exists in your output folder.
Having trouble?
Build the Executive Summary page
The Executive Summary page is the first thing a stakeholder sees. It answers one question instantly: are we meeting the 95% accuracy benchmark?
- Switch to the Report view (the bar-chart icon on the left sidebar).
- You should see a blank canvas. This is your first report page.
- On the Insert ribbon, click Text box.
- Type Medical Coding Accuracy Audit as the page title. Increase the font size so it stands out.
- Drag the text box to the top of the canvas.
Why a text box instead of a title visual?
Power BI does not have a dedicated title visual. A text box gives you full formatting control over your page heading.
Now add four KPI cards that summarize the audit at a glance.
- In the Visualizations pane, click the Card visual (single number card icon).
- From the Fields pane, expand the Executive_Summary table and drag the Value field into the card's data well.
- Use a filter on the Metric field to show only Overall Coding Accuracy Rate. This is your first KPI card.
- Repeat this process to create 3 more cards filtered to: Total Claims Audited, Total Coding Errors, and a count of departments below benchmark from the Department_Accuracy table (filter where training_required equals True).
- Arrange the four cards in a row below your title text box.
Resize cards for a clean layout
Click a card visual and drag its corner handles to resize. Aim for equal widths across all four cards so the row looks balanced.
Next, add a Gauge visual that shows accuracy against the 95% target.
- In the Visualizations pane, click the Gauge visual icon.
- Set the Value field to your overall accuracy rate from the Executive_Summary table.
- In the Format visual pane (paint roller icon), expand Gauge axis.
- Set Min to 0.80 and Max to 1.00.
- Set the Target field to 0.95 (the industry benchmark).
- Position the gauge below the KPI cards on the left side of the canvas.
What does the gauge target line show?
The target marker on the gauge represents the 95% AHIMA industry benchmark. A needle to the left of the target means the organization is underperforming. A needle past the target means the organization exceeds benchmark.
Finally, add a Donut chart showing the breakdown of denial reasons.
- Click the Donut chart icon in the Visualizations pane.
- From the Error_Types table, drag denial_reason to the Legend well.
- Drag error_count to the Values well.
- Position the donut chart to the right of the gauge.
Apply a professional color scheme to all visuals.
- Select each visual and open the Format visual pane (paint roller icon).
- Use green (#2E7D32 or similar) for values above the 95% benchmark.
- Use red or amber (#D32F2F or #FF8F00) for values below the benchmark.
- Apply these colors to conditional formatting on your KPI cards and gauge segments.
Why green and red?
Traffic-light coloring is a standard convention in healthcare dashboards. Stakeholders immediately know green means meeting target and red means action needed. This removes the cognitive load of reading exact numbers.
Add a monthly trend line chart
A single accuracy number tells you where you are today. A trend line tells you whether things are getting better or worse over time.
- Click the Line chart icon in the Visualizations pane.
- From the Monthly_Trends table, drag service_month to the X-axis well.
- Drag accuracy_rate to the Y-axis well.
- Position the line chart below the gauge and donut chart, spanning the full width of the canvas.
Now add the 95% benchmark as a constant reference line.
- Click on your line chart to select it.
- In the Visualizations pane, click the Analytics icon (magnifying glass with a line graph).
- Expand Y-Axis constant line.
- Click + Add.
- Set the Value to 0.95.
- Give it a name like 95% Benchmark.
- Set the Color to red and the Line style to dashed so it stands out from the data line.
- Toggle Data label to On so the benchmark value is visible on the chart.
What is the Analytics pane?
The Analytics pane in Power BI lets you overlay reference lines on visuals. For line charts, you can add constant lines, trend lines, average lines, and more. The Y-Axis constant line draws a horizontal line at a fixed value across the entire chart.
Save your work.
- Press Ctrl+S (Windows) or Cmd+S (macOS).
- Save the file as coding_audit_dashboard.pbix in your project folder.
Your Executive Summary page should now display the overall accuracy rate gauge, four KPI cards, a donut chart of denial reasons, and a monthly trend line with a dashed red benchmark at 95%.
Line chart showing no data?
If your line chart is blank, it may mean the Monthly_Trends table has no date-based data. Check that your dataset had a valid service_date column and that your Python script successfully created the service_month column.
You can verify by switching to the Data view, selecting the Monthly_Trends table, and checking that it has rows of monthly data (not a single note saying dates were unavailable).
Need help debugging your trend chart?
Your executive dashboard is live. Next up, you will build a department drill-down page that reveals exactly which teams need training and what error types are dragging them below benchmark.
Add Department Drill-Down and Training Needs Pages
Your Executive Summary page gives stakeholders a bird's-eye view of the organization's coding accuracy. Now it's time to let them drill into the details and pinpoint exactly where training is needed.
In this step, you'll add two more pages to your Power BI report. The Department Performance page ranks every department against the 95% benchmark. The Training Needs page reveals which error types are dragging each department down.
In this step, get ready to:
- Build a Department Performance page with a ranked bar chart and data table.
- Build a Training Needs page with a heatmap matrix and time slicer.
- Add cross-filtering, page navigation, and final polish to the report.
Build the Department Comparison page
This page will let stakeholders instantly see which departments fall below the 95% accuracy benchmark. A horizontal bar chart makes the comparison visual, and a table provides the raw numbers.
- In Power BI Desktop, click the + icon next to your existing page tab at the bottom of the canvas to add a new page.
- Double-click the new page tab and rename it to Department Performance.
- In the Visualizations pane on the right, click the Clustered Bar Chart icon (horizontal bars).
- Drag the chart to fill the upper portion of the canvas.
- From the Department_Accuracy table in the Data pane, drag the department field to the Y-axis well.
- Drag the accuracy_rate field to the X-axis well.
- Click the three-dot menu (...) on the Y-axis field in the well, then select Sort ascending so the lowest-accuracy departments appear at the top.
Now add a constant line at 95% so underperformers are immediately visible.
- With the bar chart selected, click the Analytics pane (magnifying glass icon) in the Visualizations panel.
- Expand X-Axis Constant Line and click + Add line.
- Set the Value to 0.95.
- Toggle on Data label so the 95% threshold is labeled on the chart.
Next, add conditional formatting so bars below the benchmark stand out in red.
- With the bar chart selected, switch to the Format visual pane (paint roller icon).
- Expand Bars (or Columns depending on your version) and click the fx (conditional formatting) button next to the color option.
- Set the format style to Rules.
- Create a rule: if accuracy_rate is less than 0.95, set the color to red.
- Create a second rule: if accuracy_rate is greater than or equal to 0.95, set the color to green.
- Click OK to apply.
Finally, add a Table visual below the bar chart for the detailed numbers.
- Click an empty area of the canvas, then select the Table visual from the Visualizations pane.
- From the Department_Accuracy table, drag these fields into the Columns well: the department name, total_claims, accuracy_rate, denied_claims, and training_required.
- Resize the table to fit below the bar chart.
Why both a chart and a table?
The bar chart tells the visual story. Stakeholders can instantly spot which departments are in the red zone. The table underneath provides the exact numbers auditors need for documentation and follow-up.
- Save your report by pressing Ctrl+S (Windows) or Cmd+S (macOS).
Your Department Performance page should now show a horizontal bar chart with red bars below the 95% line and green bars above it, plus a data table underneath.
Bars are all one color?
Make sure you selected Rules (not Gradient) in the conditional formatting dialog. Also confirm the field is set to accuracy_rate and the threshold value is 0.95.
Help me fix conditional formatting on my bar chart.
Build the Training Needs Heatmap
The heatmap reveals patterns that a simple accuracy number hides. If a department has low accuracy, the matrix shows whether the problem is one dominant error type or spread across many categories.
- Click the + icon at the bottom of the canvas to add another new page.
- Double-click the page tab and rename it to Training Needs.
- In the Visualizations pane, click the Matrix visual icon (grid with row/column headers).
- From the Error_Types table, drag the department field to the Rows well.
- Drag the denial reason field to the Columns well.
- Drag the error_count field to the Values well.
- Resize the matrix to fill the upper two-thirds of the canvas.
Now apply conditional formatting so the highest error counts glow with a strong color.
- With the matrix selected, click the dropdown arrow on the error_count field in the Values well.
- Select Conditional formatting, then Background color.
- Keep the format style as Gradient. Set the minimum color to white and the maximum color to a strong red or orange.
- Click OK to apply.
What does the color scale show?
Cells with higher error counts get a deeper color. This instantly draws the eye to which department-and-error-type combinations need urgent attention. A department with a dark red cell in one column has a concentrated training gap in that specific area.
Add a quarter slicer so users can focus on recent data.
- Click an empty area of the canvas, then select the Slicer visual from the Visualizations pane.
- From the Monthly_Trends table (or whichever table has your quarter field), drag the quarter field into the slicer's Field well.
- Position the slicer in the upper-right area of the page so it doesn't overlap the matrix.
Add a text box summarizing the key finding.
- Click Insert in the top ribbon, then select Text box.
- Type a summary sentence identifying which departments need immediate training attention based on your data (for example: "Departments X and Y require priority coding training based on error volume and accuracy gap").
- Position the text box below the matrix.
- Save your report with Ctrl+S (Windows) or Cmd+S (macOS).
Your Training Needs page should display a color-scaled matrix with departments as rows and error types as columns. Darker cells highlight the biggest problem areas.
Matrix shows blank cells or no data?
Confirm you dragged fields from the Error_Types table (not Department_Accuracy). The Error_Types sheet has the department-by-denial-reason breakdown the matrix needs.
Help me fix my Power BI matrix visual.
Add interactivity and final polish
Cross-filtering is what makes this dashboard interactive. When a stakeholder clicks a department bar on Page 2, every other visual on that page updates to show only that department's data.
- Navigate to your Department Performance page.
- Click the bar chart to select it.
- In the top ribbon, click Format, then Edit interactions.
- On the Table visual, make sure the filter icon (funnel) is selected rather than the "none" icon. This enables cross-filtering from the bar chart to the table.
- Click Edit interactions again to exit interaction editing mode.
What is cross-filtering?
Cross-filtering means clicking a data point in one visual automatically filters all other visuals on the same page. Power BI enables this by default for most visuals, but the Edit Interactions menu lets you control which visuals respond to clicks.
Now add page navigation so users can move between your three report pages easily.
- Click Insert in the top ribbon, then select Buttons, then Navigator, then Page navigator.
- Power BI inserts a navigation bar showing all page names. Position it at the top or bottom of the canvas.
- Copy the navigator to your other two pages so every page has consistent navigation. Select the navigator, press Ctrl+C (Windows) or Cmd+C, navigate to another page, and press Ctrl+V (Windows) or Cmd+V (macOS).
Finally, add a report title and data source note for professional context.
- On the Executive Summary page, click Insert then Text box.
- Type a report title at the top of the page (e.g. "Medical Coding Accuracy Audit") if you haven't already.
- Add a smaller text box at the bottom with: Source: Synthetic AR Medical Dataset and today's date.
- Save your report with Ctrl+S (Windows) or Cmd+S (macOS).
Test the interactivity by clicking a department bar on the Department Performance page. The table below should filter to show only that department's row.
Clicking a bar doesn't filter the table?
Go back to Format then Edit interactions with the bar chart selected. Confirm the funnel (filter) icon is active on the table visual, not the circle (none) icon.
Help me set up cross-filtering in Power BI.
Secret mission
Financial Impact Analysis
Your dashboard tells leadership which departments need training. But what if you could also tell them exactly how much money those coding errors are costing? In this extension, you will add a financial impact layer that quantifies revenue leakage per department and projects the savings from reaching 95% accuracy.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs or cloud resources to worry about. Decide whether to keep your files for future reference, or delete them to free up disk space.
Resources you used:
- Project folder medical-coding-audit containing your Python script, raw CSV data, and Excel output.
- Power BI .pbix file saved in your project folder.
- The openpyxl Python package installed via pip.
Keep everything running
No action needed. Choose this if you want to revisit the dashboard, refine your analysis, or use it as a portfolio piece.
- All files remain on your local machine at no cost.
- You can reopen the .pbix file in Power BI Desktop at any time to update or explore further.
- Rerun coding_audit.py any time you want to regenerate the Excel workbook with fresh logic.
Pause - I'll come back to this later
Since everything is local, there is nothing to pause or shut down. Your files stay on disk until you delete them.
- Close Power BI Desktop if it is still open to free up memory.
- Close any terminal sessions running in the project folder.
- Your project folder, Excel workbook, and .pbix file will be ready when you return.
Delete - I don't want to use this again
Remove all project files and the installed package to start fresh.
- Close Power BI Desktop if it is still open.
- Delete the project folder by running the appropriate command for your operating system.
On macOS or Linux:
rm -rf ~/Desktop/medical-coding-audit
On Windows (PowerShell):
Remove-Item -Recurse -Force "$HOME\Desktop\medical-coding-audit"
- Uninstall the openpyxl package by running:
pip uninstall openpyxl
- Confirm the uninstall when prompted by typing y.
- Your Kaggle account and Python installation remain on your machine. These are general-purpose tools useful for future projects.
Nice Work!
Nice Work!
You just built a medical coding accuracy audit dashboard from scratch. Starting with raw synthetic claims data, you transformed it into actionable department-level insights that identify training needs and protect revenue.
You've learned how to:
- Build a Python data pipeline that cleans raw healthcare claims and calculates coding accuracy KPIs against the 95% industry benchmark.
- Export a multi-sheet Excel workbook with executive summaries, department breakdowns, error type analysis, and training needs prioritization.
- Design an interactive Power BI dashboard with cross-filtering, conditional formatting, and benchmark comparisons that surface underperforming departments.
- Secret Mission: Quantified the financial impact of coding errors and projected revenue savings from accuracy improvements.
Ready to quiz yourself?