Experiment 03
Global IT Spend in Power BI
How does a large company keep $900M of IT spend honest? This dashboard compares plan, forecast and actuals across business areas, countries and cost types, and shows where the variance comes from.
- Period
- Built Oct 2026
- Stack
- Power BI Desktop, DAX, Power Query, Python notebook
- Data
- 93,729 rows, 7 business areas, 30 countries
- Context
- Crio.Do DA-201, session 7
Where do plan, forecast and actuals drift apart?
- Cost distribution: how spend splits across 7 business areas, 5 IT areas (38 sub-areas), 6 regions (30 countries) and 5 cost-element groups (23 sub-groups).
- Budget and forecast alignment: where are the largest gaps between actual, forecast and plan, over time and geography?
- Structural drivers: what drives deviations in areas such as internal versus external labour, shared services and R&D planning?
Power Query prep, a clean model, DAX measures
- Append and tag. Combine the two sheets (81,610 + 12,119 rows) and tag each with a dataset period, so a single click can return to the original view.
- Replace nulls with 0. Each ERP row fills only one of actual, forecast or plan. Dropping rows with nulls would erase the budget.
- Sort months properly. Add a month number and quarter, and sort by column, so Power BI doesn't order months alphabetically.
- Keep the credits. 1,463 negative actual rows (about −$126M) are valid chargebacks and accrual reversals. Removing them would inflate net spend.
- Measure. Variance is defined once as
Actual − Plan, so negative means underspend, and used everywhere.
A Python EDA notebook sits alongside the dashboard for checks that are easier in code.
Full-year actuals land 3.77% under plan
- $900.40Mfull-year plan
- $890.54Mforecast
- $866.41Mactual
- −$33.99Mactual vs plan (−3.77%)
The drill-downs are where the questions live: variance by business area and region, internal versus external labour, and a clear flag on Europe shared services overspend.
Plan is a full year; actuals are not
The first version of the numbers looked alarming: actuals 38% below plan. That is a comparison of eight months of actuals against twelve months of plan. The fair like-for-like view is January to August only:
- Use the month slicer, not the dataset-period filter, for a fair year-to-date comparison.
- Replacing nulls with 0 is safe here only because each row fills exactly one measure.
- This is a practice dataset, so the real-world causes of the variances are not known.
Contact
Got a messy dataset or a science question?
I read everything and answer when I can. The quickest way is email, and LinkedIn works too.