Locked methodology — worked through on engineering
One statement of every definition and scope, so none of it gets re-litigated. Engineering is used throughout as the worked example; the same rules apply to the other five buckets, with the one documented exception noted at the end.
1. The base population
Section titled “1. The base population”| Filter | Value | Why |
|---|---|---|
release_id |
'calendar_2025' |
One release. Pooling CY2022–25 is done separately as a robustness check in POOLED.md — it confirms these figures and tightens the interval 26%, but is not the headline because a pooled figure is no longer current. |
visit |
'V1' |
pas is collected only at the first visit; on multi-visit releases it is 100% populated at V1 and 0% at every revisit. |
gedu_lvl |
= '12' |
“Literate: graduate”. Completed a UG, has not completed a PG — '13' is “postgraduate and above” and is excluded. Someone currently doing a master’s is still '12' (unfinished) and appears as pas='91', which is why “studying” reads as PG study. |
tedu_lvl |
= '03' |
“Technical degree in engineering/technology”. Degrees only — the engineering diplomas ('08', '13') are a separate bucket and are 9–10 percentage points worse on formal employment. |
weight_annual |
not null | All shares are weighted. |
gedu_lvl and tedu_lvl are different fields whose code values overlap. tedu_lvl='13' is a
graduate-level engineering diploma; gedu_lvl='13' is a postgraduate degree. They are unrelated.
2. Two age windows, for two different questions
Section titled “2. Two age windows, for two different questions”This is the part that kept getting confused. They are not interchangeable.
A. Recent graduates — ages 22–24
Section titled “A. Recent graduates — ages 22–24”Three years from engineering’s normal completion age of 22. Use this for anything about what a fresh graduate faces, and for any comparison against a college’s placement figure, because a placement is reported at graduation.
Emitted by the pipeline as age_band = '0a. recent graduates', with the window set per bucket —
engineering 22–24, medical 24–26 (MBBS is 5.5 years including internship), everything else 21–23.
It is not computed by hand anywhere.
n = 1,042 · 1.16m people
| Formal | Informal wage | Self-employed | Working for money | Studying | Neither |
|---|---|---|---|---|---|
| 34.6% | 2.9% | 2.5% | 40.0% | 16.7% | 43.3% |
Formal and earning ≥₹6 lakh: 4.42% — and this one is checked against tenure below rather than taken on trust.
B. The whole stock — ages 21–34
Section titled “B. The whole stock — ages 21–34”Every engineering graduate in the working-age range, most of them years into a career. Use this for the size and state of the existing workforce, and as the pool for the tenure analysis.
n = 4,734 · 5.42m people
| Formal | Informal wage | Self-employed | Working for money | Studying | Neither |
|---|---|---|---|---|---|
| 52.6% | 4.3% | 7.8% | 64.7% | 6.0% | 29.3% |
Formal and earning ≥₹6 lakh: 17.56%
Never mix them
Section titled “Never mix them”4.42% and 17.56% answer different questions. The first is what a graduating engineer walks into; the second is where engineers who have been working for years have got to. The gap between them is wage growth, not disagreement. Any comparison against a college’s reported placement salary uses A, because that is the moment a college measures.
2b. The ≥₹6 lakh figure is checked against tenure, not assumed
Section titled “2b. The ≥₹6 lakh figure is checked against tenure, not assumed”The 22–24 window admits people at any tenure, and a 24-year-old can already have three years
behind them. Since wages nearly double over that span, the age window could be importing wage
growth into a number meant to describe people at the start. Engineering is the one bucket with the
sample to test this, so it is tested. check_entry_wage.py, clustered bootstrap over first-stage
units, 2,000 draws.
The like-for-like comparison — share of those in formal work clearing ₹6 lakh:
| Cut | n | FSUs | Estimate | 95% CI |
|---|---|---|---|---|
| Aged 22–24, any tenure (what the headline uses) | 304 | 279 | 12.76% | [6.58, 20.08] |
| Aged 22–24, under 1 year in (strict) | 101 | 94 | 10.34% | [2.54, 21.24] |
| Any age, under 1 year in (ignores graduation timing) | 182 | 168 | 11.19% | [4.50, 18.78] |
How the intervals are computed
Section titled “How the intervals are computed”Resample first-stage units — the village or urban block PLFS sampled — with replacement: draw 916 units from the 916, take every person in each drawn unit, recompute the weighted share, repeat 2,000 times, read off the 2.5th and 97.5th percentiles.
Clustering is the right method but not the reason these intervals are wide. The schema warns that treating people as independent understates the standard error by 3.5–4.7×, but that applies to whole-population estimates where each unit yields about twelve households. A thin subgroup is different: engineering graduates aged 22–24 are 1,042 people across 916 units, 1.14 per unit, with only 110 units holding more than one. Measured design effect: 1.14×.
| Method | Interval on the 4.42% | Width |
|---|---|---|
| Cluster bootstrap (used) | [2.19%, 7.19%] | 5.01pp |
| Person bootstrap | [2.42%, 6.73%] | 4.31pp |
| Wald from the raw count, unweighted | [3.17%, 5.67%] | 2.50pp |
The count sets the scale and the survey weights nearly double it. n=34 in the numerator gives the Wald width of 2.50pp; weighting takes it to 4.31pp because a handful of high-weight respondents genuinely move the estimate; clustering adds the last 0.7pp. The cluster bootstrap is kept because it is correct whether or not clustering bites and costs nothing — not because it is doing the work.
Verdict: the age window is not measurably contaminated. The gap to the strict entry-tenure reading is 2.4pp and the intervals overlap heavily. It reads slightly high, so using it is generous toward whatever it is compared against — the conservative direction for our purposes.
The strict cut is not adopted because it costs more than it buys: n falls from 304 to 101 and the interval widens from 13.5pp to 18.7pp. A noisier estimate of the same number is not an improvement.
Carried through to the cohort figure, the three wage rates give:
| Wage rate applied to the 34.6% formal rate | ≥₹6L rate | Cohort share |
|---|---|---|
| Same window, any tenure (headline) | 12.76% | 4.42% |
| Aged 22–24, entry tenure | 10.34% | 3.58% |
| Any age, entry tenure | 11.19% | 3.88% |
So the headline 4.42% would become 3.58% on the strictest reading. Every alternative is lower, which means 4.42% is the generous end of the range — worth stating wherever it is compared against a college’s reported placement salary.
A note on reading these: only the first row can be computed directly as a share of the cohort. Rows 2 and 3 restrict the denominator to people in their first year of an activity, so their raw share answers a different question. The comparable quantity is the composite above — the cohort’s formal employment rate times the entry-tenure wage rate.
3. Wage progression is measured by tenure, not age
Section titled “3. Wage progression is measured by tenure, not age”dur_pas — duration in the present principal activity status — collapsed to three steps. Pooled
across ages 21–34, because tenure cells inside 22–24 alone are too thin.
Tenure beats age here because it measures time in work directly: it makes no assumption about when anyone graduated, and it separates a fresh entrant aged 30 from a thirty-year-old with eight years behind them.
| Step | n | p25 | Median | p75 | p90 | ≥₹50k |
|---|---|---|---|---|---|---|
| Under 1 year | 182 | ₹20,000 | ₹25,000 | ₹35,000 | ₹50,000 | 11.2% |
| 1 to 3 years | 762 | ₹25,000 | ₹34,500 | ₹45,000 | ₹65,000 | 24.4% |
| Over 3 years | 1,216 | ₹30,000 | ₹42,000 | ₹60,000 | ₹80,000 | 42.9% |
Median rises 1.68× and the share clearing ₹50,000 goes 11.2% → 42.9%.
The code boundaries are inferred, not documented. dur_pas has no codebook in our schema, so
it was validated against people who cannot have long tenure: among graduates in salaried work,
code 3 peaks at age 22–23, code 4 at 25, code 5 from 27. That fits the standard NSS ladder — under
6 months, 6–12 months, 1–2 years, 2–3 years, 3+ years.
Two caveats. It measures time in the activity status, not with an employer, so changing jobs while staying salaried keeps the clock running. And it is blank for anyone not working, so it says nothing about the unemployed.
4. The activity split — five categories, exhaustive
Section titled “4. The activity split — five categories, exhaustive”Every person in the base falls in exactly one. They sum to 100.
| Category | Rule |
|---|---|
| Formal | pas='31' AND ern_reg>0 AND (job_pas IN ('2','3','4') OR ssec_pas NOT IN ('8','9')) |
| Informal wage | pas='31' AND ern_reg>0, without contract or benefits; plus casual wage labour pas IN ('41','42','51') |
| Self-employed | pas IN ('11','12') AND ern_self>0 |
| Studying | pas='91' — already holds a degree, so this is postgraduate study |
| Neither | everything else: 81 unemployed, 92/93 domestic duties, 21 unpaid family work, 94/95/97 |
What “formal” means, verified against the table’s own labels
Section titled “What “formal” means, verified against the table’s own labels”pas='31'— “Worked as regular salaried/wage employee”, the usual principal activity over the last 365 days, not a snapshot of last week.ern_reg>0— actually paid. 97% of salaried workers clear this; the rest are dropped.job_pas—1no written contract;2/3/4written contract of ≤1yr / 1–3yr / >3yr.ssec_pas—1–7are combinations of PF/pension, gratuity and health/maternity benefits;8“not eligible for any”;9“not known”.
| Route | All graduates | Engineering only | ||
|---|---|---|---|---|
| Share | Median | Share | Median | |
| Both contract and benefits | 53.8% | ₹28,500 | 75.9% | ₹39,600 |
| Benefits only, no contract | 13.7% | ₹22,000 | 15.1% | ₹35,000 |
| Contract only, no benefits | 5.9% | ₹14,000 | 2.5% | ₹21,000 |
| Neither → classed informal | 26.7% | ₹12,000 | 6.6% | ₹16,000 |
A known weakness — and it bites at the bottom of the education distribution, not here. Across all graduates the contract-only group earns ₹14,000 median, barely above the ₹12,000 of those classed informal: a written contract alone is a weak marker. For engineering graduates the sign reverses — contract-only earns ₹21,000 against the informal ₹16,000, and is 2.5% of the salaried rather than 5.9%.
An earlier version of this table published the all-graduates figures under an “engineering
graduates” heading, which made the weakness look far worse here than it is. It is real, and it is
concentrated at low education levels: see
../ASSUMPTIONS.md C1, where
contract-only admissions are 24% of the bottom rung’s formal count and earn less than the informal
group.
Requiring social security would cut engineering’s formal rate from 52.58% to 51.20%. The current rule is kept because it matches how PLFS-based formality is conventionally measured, and the alternative is one line of code away.
Two exclusions worth stating
Section titled “Two exclusions worth stating”- Unpaid family helpers (
pas='21') are never “working for money”. PLFS records them as employed; they earn nothing. They sit in “neither”. - Casual wage labour is counted as working without an earnings test, because
ern_regandern_selfcover only regular and self-employed work — of 1,286 casual labourers in the wider base, just 12 carry an earnings value. Requiring one would drop them for a reason about the survey’s field coverage, not their work. They are under 3% of engineering either way.
5. The ₹6 lakh line is a parameter, not an assumption
Section titled “5. The ₹6 lakh line is a parameter, not an assumption”₹6 lakh a year is ₹50,000 a month — the 90th percentile for an employed engineering graduate at
22–24. output/wage_threshold_grid.csv carries the exact weighted share above every threshold from
₹15,000 to ₹150,000 a month, for every bucket and step, so it can be moved without a rerun.
A log-normal was fitted for interpolation and then checked before use. It fails at low
thresholds by up to 14.9pp, because reported wages heap on round numbers and that is exactly where
those thresholds sit. So share_above() reads the empirical grid and refuses to answer below
₹15,000. The fit is used only above ₹40,000 and only to extrapolate past the top of the grid.
The fit also sits below the true share at ₹50,000 in 29 of 42 cells — the real right tail is fatter than log-normal, which matters for any analysis that models Indian salaries that way.
6. Where the other buckets differ
Section titled “6. Where the other buckets differ”Three buckets use age bands rather than tenure, because their smallest tenure cell falls under
the 50 minimum: medical (43), other technical (47) and other diploma (45). The rule is applied mechanically in build.py
and the lens chosen is printed for every bucket, never left implicit.
The “recent graduate” window is per-bucket, set three years from each course’s normal completion age: engineering 22–24, doctors 24–26 (MBBS is 5.5 years including internship), three-year degrees 21–23.