Data AnalyticsPortfolio projects with Indian public data

A decade of Delhi budgets: estimates vs actuals from PRS analyses

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 27 September 2026 · 5 min read
In this article (7 sections)

Related programme: the Data Analytics with Generative AI course (3–4 months; ₹90,000 (inclusive of GST) · EMI from ₹4,000/month).

The short answer

Delhi's government presents a Budget Estimate each March, revises it a year later and reports actuals a year after that. So each fiscal year has three figures, and each published document mixes all three. This project collects the key-figures table from every PRS Legislative Research analysis of Delhi's budget, from 2016-17 to 2026-27. It builds a tidy panel with one row per fiscal year, item and vintage, and then answers a budget-credibility question: how far do Delhi's estimates move before they become actuals, and is the gap larger for receipts or for spending?

The source

PRS publishes a state budget analysis for Delhi every year, and its listing covers 2016-17 to 2026-27. Each analysis is a web page with an "Open Pdf" link. The 2026-27 page, for example, links to a PDF titled Budget_Analysis_2026-27-DL. Its Table 1 is "Budget 2026-27 - Key figures (in Rs crore)", and its note cites the Annual Financial Statement of the Delhi budget documents. The table's columns are 2024-25 Actuals, 2025-26 BE, 2025-26 RE and 2026-27 BE, and its rows include:

Item, Rs crore2024-25 Actuals2025-26 BE2025-26 RE2026-27 BE
Total Expenditure61,4711,00,00099,3101,03,700
Net Expenditure56,55795,35894,66899,446
Total Receipts62,42397,03578,5761,02,060
Net Receipts62,28181,65572,37982,480
Fiscal Balance5,724-13,703-22,289-16,966

Two things in that one table show why the project is worth doing. Receipts for 2025-26 were estimated at ₹97,035 crore and revised to ₹78,576 crore. And the 2025-26 BE of ₹1,00,000 crore spending compares with 2024-25 actual spending of ₹61,471 crore. The text of the same analysis gives the 2025-26 revised fiscal deficit as ₹22,290 crore, one crore off the table, which is the kind of rounding difference your README should note rather than fix.

PRS also publishes a State of State Finances report and similar analyses for Uttar Pradesh and Haryana, which lets you extend this to NCR later. Check the licence and attribution terms on the PRS site before republishing any table.

Who hires for this skill

Public-finance researchers, rating agencies, policy consultancies and journalists all need clean time series from documents released once a year. Building one requires version control of figures, not just transcription. Each fiscal year appears in up to three documents, so a careless panel mixes an estimate from one year with an actual from another. An analyst who can say "revisions to receipts averaged X% over the decade" with the vintage logic visible is doing real fiscal analysis.

Cleaning issues

  1. 1Indian digit grouping. "1,00,000" must parse to 100000. Strip commas and do not rely on a thousands separator setting.
  2. 2Negative signs. Deficits appear with a minus sign, and some years may use brackets. Normalise both.
  3. 3Changing row names. Item labels can vary across years. Keep a mapping from each year's label to one canonical item and store the original label.
  4. 4Three vintages per year. Store fiscal_year, item, vintage (BE, RE or Actuals) and source_document. Never overwrite one vintage with another.
  5. 5Late actuals. A fiscal year's actuals appear two documents later, so the latest two years have no actuals yet. Leave them missing.

Code: vintages and forecast drift

The panel below is synthetic. Years are real labels, but every rupee figure is invented and does not come from any Delhi budget.

python
import pandas as pd

rows = []
# (fiscal_year, item, BE, RE, Actuals): synthetic Rs crore values
for fy, item, be, re_, act in [
    ("2021-22", "total_expenditure", 69_000, 67_000, 63_500),
    ("2022-23", "total_expenditure", 75_800, 73_000, 66_900),
    ("2023-24", "total_expenditure", 78_800, 76_000, 70_100),
    ("2021-22", "total_receipts",    68_500, 64_800, 66_200),
    ("2022-23", "total_receipts",    74_000, 71_500, 70_400),
    ("2023-24", "total_receipts",    77_500, 69_900, 71_600),
    ("2024-25", "total_expenditure", 80_000, 78_500, None),
    ("2024-25", "total_receipts",    79_000, 74_000, None),
]:
    for vintage, value in [("BE", be), ("RE", re_), ("Actuals", act)]:
        if value is not None:
            rows.append({"fiscal_year": fy, "item": item, "vintage": vintage, "rs_crore": value})
panel = pd.DataFrame(rows)

# A tidy panel must never hold two values for the same year, item and vintage
assert not panel.duplicated(["fiscal_year", "item", "vintage"]).any()

wide = panel.pivot_table(index=["item", "fiscal_year"], columns="vintage", values="rs_crore")
wide["be_to_re_pct"] = 100 * (wide["RE"] / wide["BE"] - 1)
wide["be_to_actual_pct"] = 100 * (wide["Actuals"] / wide["BE"] - 1)
print(wide[["BE", "RE", "Actuals", "be_to_re_pct", "be_to_actual_pct"]].round(1).to_string())

# Summary: average and worst drift by item, using only years that have actuals
done = wide.dropna(subset=["Actuals"])
summary = done.groupby(level="item")["be_to_actual_pct"].agg(["mean", "min", "count"]).round(1)
print(summary.to_string())

The be_to_actual_pct column is the budget-credibility measure. A consistently negative value means the government spends or collects less than it announces. Keep the RE column too, because the revision a year later shows how much of the eventual gap was already visible mid-year.

Analysis plan

  • Download the PRS Delhi analysis for every year from 2016-17 to 2026-27. Record the PDF name and the date you fetched it.
  • Transcribe or extract each Key figures table into the long panel, with the original row label beside the canonical item.
  • Where two documents report the same year and vintage, compare them. Differences are revisions or rounding, so keep both and flag them.
  • Compute BE-to-RE and BE-to-Actuals drift for expenditure, receipts and fiscal balance.
  • Chart the decade, and mark years with unusual events that the analyses themselves discuss.

Deliverables

DeliverableContent
Tidy CSVfiscal_year, item, vintage, rs_crore, original_label, source_document
Fan chartFor each fiscal year, BE, RE and Actuals as three linked points
Drift tableItem, mean and worst BE-to-Actuals drift, years covered
READMEPRS pages and PDFs used, fetch dates, label mapping, rounding differences found, licence and attribution note

Interview questions

  • Why does each fiscal year appear in three different documents?
  • How did you stop your panel mixing a Budget Estimate with an Actual?
  • The table and the text disagree by one crore. What do you do?
  • Why is fiscal balance drift harder to interpret as a percentage than expenditure drift?
  • How would you extend the panel to Uttar Pradesh and Haryana without breaking comparability?

If you want to automate the extraction step, the budget PDF extraction project adds a language model and a verification harness. The Data Analyst programme runs for 3–4 months, live online, with optional in-person labs at our Noida centre. Ask a counsellor through the contact page about fees and batches.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.