Data AnalyticsDomain analytics and business cases

Analyze operating expenses without changing the cost taxonomy

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (6 sections)

A category rename can look like a new expense if the report compares periods under different classification rules. Before explaining a cost increase, apply a consistent taxonomy or build a clear bridge between the old and new classifications.

Preserve the original expense records and version the mapping separately. Reclassification should change how amounts are grouped, not the underlying total.

Start with source cost codes

The original synthetic expense fixture contains five records:

PeriodCost codeAmount paise
Januarycloud_service10,000
Januarycontractor20,000
Februarycloud_service12,000
Februarycontractor18,000
Februaryobservability3,000

Taxonomy v1 classifies cloud service and observability as Technology. Version v2 calls that grouping Infrastructure. Both keep contractor spending in People. The rename does not create a new economic expense.

For a comparable view, this example maps both periods through v2. A historical-as-reported view can retain the original version, but it must be labeled separately.

Apply one version with a left join

sql
SELECT e.period,t.category,COUNT(*) AS expense_rows,
 SUM(e.amount_paise) AS amount_paise,
 SUM(t.cost_code IS NULL) AS unmapped_rows
FROM expenses e
LEFT JOIN cost_taxonomy t
 ON t.cost_code=e.cost_code AND t.version='v2'
GROUP BY e.period,t.category ORDER BY e.period,t.category;

The left join preserves unknown cost codes as an exception group. An inner join could silently drop them and make expense totals appear lower.

Under v2, January contains Infrastructure at 10,000 and People at 20,000 paise. February contains Infrastructure at 15,000 and People at 18,000. Total expense rises from 30,000 to 33,000: Infrastructure increases 5,000 while People decreases 2,000.

Verify mapping coverage and the variance bridge

python
from collections import defaultdict
from build_and_verify import database

db = database()
mapping = dict(db.execute("SELECT cost_code,category FROM cost_taxonomy WHERE version='v2'"))
rows = db.execute('SELECT * FROM expenses').fetchall()
totals = defaultdict(int)
unmapped = []
for expense,period,code,amount in rows:
    if code not in mapping:
        unmapped.append(expense)
    totals[(period,mapping.get(code,'UNMAPPED'))] += amount
db.close()
assert not unmapped
assert dict(totals)=={('2026-01','Infrastructure'):10000,('2026-01','People'):20000,
                     ('2026-02','Infrastructure'):15000,('2026-02','People'):18000}
assert sum(totals.values())==sum(r[3] for r in rows)==63000
variance = {category:totals[('2026-02',category)]-totals[('2026-01',category)]
            for category in ('Infrastructure','People')}
assert variance=={'Infrastructure':5000,'People':-2000}
assert sum(variance.values())==33000-30000==3000
print({'taxonomy':'v2','category_variance_paise':variance,'total_variance_paise':3000})

The mapping table's key is version plus cost code. Without that uniqueness, one expense could match several categories and be counted more than once.

Separate reclassification from real movement

If the taxonomy changes more than a label—for example, moving support contractors from People to Technology—publish a reclassification bridge. Show the previous period under its original rules, the classification-only adjustment, and the restated comparable period.

Do not rewrite the raw transaction's source code merely to fit the latest presentation. Keeping raw codes allows another report to use a different legitimate grouping without losing auditability.

Historical mappings may also need effective dates. Distinguish “how this expense was classified then” from “how we would classify the same expense under today's policy.” Neither should be silently substituted for the other.

Investigate the economic change after classification is stable

The 5,000 Infrastructure increase consists of 2,000 more cloud-service spending and 3,000 of observability spending. That breakdown identifies where to investigate; it does not establish waste or a need to cut costs.

Usage, service scope, price changes, timing and allocation policy can all affect the amount. Compare relevant operational drivers when available, and avoid dividing by an unrelated output metric simply to create a cost-per-unit chart.

This exercise treats the recorded amounts as the selected expense measure. Accruals, cash timing, tax and capitalization policies require their own definitions and are outside the fixture.

Exercise: add a new cost code absent from v2. Verify that the total is preserved in an unmapped group and that the coverage assertion fails before a category-level variance is approved.

NeuraPath's Data Analytics with Generative AI course connects dimensional modeling with business reporting. A credible expense comparison keeps classification changes separate from changes in spending.

Continue learning

This article is part of the Domain analytics and business cases sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

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.