Data AnalyticsPortfolio projects with Indian public data

Haryana's interstate goods flows from e-way bill statistics

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

Haryana generated about 8.24 crore outgoing interstate e-way bills in 2024-25 but received only about 3.75 crore incoming ones, yet the rupee value moving in each direction was similar. So Haryana sends out many smaller consignments and receives fewer, larger ones. This project finds that pattern, and others like it, in the monthly e-way bill statistics published on the GST portal. You build a tidy state-month table and compute net flows and value per bill for Haryana, Delhi and Uttar Pradesh. You then check the national totals for consistency, which turns up a gap worth explaining.

The workbook

The GST portal's statistics download page links to an annual e-way bill workbook. We used ewb-data-2024-25.xlsx, titled "EWAY BILL STATISITICS FOR THE PERIOD APR - 2024 TO MAR- 2025" (the spelling is the file's own). It has one sheet with a two-row header:

  • State Code, STATE NAME, Year, Month
  • WITHIN-STATE, OUTGOING TO OTHER STATES and INCOMING FROM OTHER STATES, each with three columns: NO.OF SUPPLIERS, NO.OF EWB and ASSESSABLE VALUE (Rs. In Crore)

Rows are grouped by month, newest first: March 2025 comes at the top and April 2024 at the bottom. There are 38 state rows per month, including "Other Territory" with code 97. The file gives each state's totals in each direction. It does not give origin-destination pairs, so you cannot say where Haryana's goods went.

Summing the twelve months for Haryana gives 8,24,01,436 outgoing bills with an assessable value of about ₹13,25,711 crore. Incoming bills number 3,75,04,703, worth about ₹12,46,070 crore. That works out to roughly ₹1.61 lakh per outgoing bill and ₹3.32 lakh per incoming bill. These are our sums from the file, so reproduce them before you build anything else.

Why an employer would care

Logistics firms, warehousing developers, freight marketplaces and state industry departments want to know where goods move and how consignments are shaped. The analysis is also a template for any directional flow data, such as payments in and out, or customers arriving and leaving. The distinction between counts and values, and the discipline of checking that flows balance, carry over directly.

Cleaning issues

  • Two-row header. Build names like out_ewb, out_value_cr and in_suppliers explicitly.
  • Month order. Months run newest first. Build a proper date from Year and Month and sort.
  • Title and footer rows. Keep only rows with a numeric State Code.
  • Suppliers are not additive over months. A supplier active in every month would be counted twelve times. Report monthly supplier counts, or the maximum, never an annual sum.
  • The balance check. Every interstate bill is outgoing for one state and incoming for another, so national outgoing and incoming totals should be close. In the 2024-25 file, summed over all rows, counts agree within about 0.3%, but assessable value differs by about 5%. Investigate before trusting value comparisons, and write down what you find, even if the answer is "not explained in the file".

Code on synthetic rows

These rows are synthetic. The states are placeholders and every number is invented; only the layout and month ordering follow the real file.

python
import pandas as pd

raw = pd.DataFrame({
    "State Code": [6, 7, 9, 6, 7, 9, 6, 7, 9],
    "STATE NAME": ["STATE H", "STATE D", "STATE U"] * 3,
    "Year":  [2025] * 3 + [2025] * 3 + [2025] * 3,
    "Month": [3] * 3 + [2] * 3 + [1] * 3,          # newest first, as in the file
    "out_ewb":      [700_000, 250_000, 280_000, 640_000, 230_000, 260_000, 660_000, 240_000, 270_000],
    "out_value_cr": [11_000, 6_200, 9_500, 10_100, 5_800, 8_900, 10_400, 6_000, 9_100],
    "in_ewb":       [320_000, 410_000, 390_000, 300_000, 380_000, 370_000, 310_000, 400_000, 380_000],
    "in_value_cr":  [10_500, 7_000, 11_600, 9_800, 6_500, 11_000, 10_000, 6_800, 11_200],
    "in_suppliers": [110_000, 95_000, 120_000, 108_000, 93_000, 118_000, 109_000, 94_000, 119_000],
})
raw["month"] = pd.to_datetime(dict(year=raw["Year"], month=raw["Month"], day=1)).dt.to_period("M")
df = raw.sort_values(["STATE NAME", "month"]).reset_index(drop=True)

df["net_value_cr"] = df["out_value_cr"] - df["in_value_cr"]
df["out_value_per_bill_rs"] = (df["out_value_cr"] * 1e7 / df["out_ewb"]).round(0)
df["in_value_per_bill_rs"] = (df["in_value_cr"] * 1e7 / df["in_ewb"]).round(0)

summary = df.groupby("STATE NAME").agg(
    out_ewb=("out_ewb", "sum"), in_ewb=("in_ewb", "sum"),
    out_value_cr=("out_value_cr", "sum"), in_value_cr=("in_value_cr", "sum"),
    peak_monthly_in_suppliers=("in_suppliers", "max"),   # not summed: suppliers repeat across months
)
summary["bills_out_per_bill_in"] = (summary["out_ewb"] / summary["in_ewb"]).round(2)
summary["value_out_per_value_in"] = (summary["out_value_cr"] / summary["in_value_cr"]).round(2)
print(summary.to_string())

# Balance check across all states in the table (a closed synthetic system, so it will not balance)
tot = df[["out_ewb", "in_ewb", "out_value_cr", "in_value_cr"]].sum()
print(f"count gap {100 * (tot['in_ewb'] / tot['out_ewb'] - 1):.1f}%, value gap {100 * (tot['in_value_cr'] / tot['out_value_cr'] - 1):.1f}%")

The two ratios in the summary tell different stories. A state can send out twice as many bills as it receives while the value moving each way stays roughly equal, which is the Haryana pattern in the real file. With only three states the synthetic balance check cannot close, since most of their trading partners are missing. With all 38 rows of the real file, the count gap is small, so the value gap is the thing to explain.

Analysis plan

  1. 1Load the sheet, keep numeric State Code rows, name columns, build the month and sort.
  2. 2Reproduce the Haryana annual sums above as an assertion.
  3. 3For Haryana, Delhi and UP, chart monthly outgoing and incoming value and bills, and compute value per bill each way.
  4. 4Run the national balance check by month, and see whether the value gap is steady or concentrated in some months or in the Other Territory row.
  5. 5Add the 2023-24 workbook and compare year-on-year growth in bills and value for the three states.

Deliverables

  • Diverging bar: net interstate value (outgoing minus incoming) by state, NCR states highlighted.
  • Dual line chart: Haryana's monthly outgoing and incoming bills, and value per bill.
  • Balance table: month, national outgoing and incoming counts and values, gaps.
  • README: workbook and title, column mapping, month ordering, supplier non-additivity, balance-check results, the absence of origin-destination pairs.

Interview questions

  • Why can you not sum monthly supplier counts into an annual figure?
  • What would you need to say where Haryana's outgoing goods go?
  • National outgoing and incoming counts match closely but values do not. How would you investigate?
  • Is a high outgoing-to-incoming bill ratio evidence of manufacturing? What else could produce it?

The GST collections project uses the same portal's revenue workbook. Directional flow analysis is a staple of our Data Analyst programme, which runs for 3–4 months, live online, with optional in-person labs at our Noida centre.

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.