How To Make Fair Rosters When Staff Need To Work In 2 Hospitals (Case Study)


In our meetings with associate consultants and ward managers, we frequently face one recurring problem: having to schedule staff across different rosters.

The more detailed explanation on why this is hard is this: when you schedule that staff for roster A, you need to space their shifts out a little bit more so they could work on the other roster (roster B). When you schedule for roster B, not only do you need to accommodate for the arrangement done for roster A, but you’d also need to balance that person’s workload, shift count on weekends, public holidays, and much more.

With experience you may be able to guess better in terms of how you should arrange these duties, but you’d never get a guarantee whether it would work — there’s always a chance that you only realise you’ve gone in a “dead end” after hours of scheduling, and have to redo the entire thing from scratch.

From a manual-scheduling perspective, they assume that the best way to handle situations like these is to make the roster schedule for one of the rosters first, then accommodate with the arrangement when they make the second roster. But in our experience the better way to do this, is with program, and schedule both rosters at the same time.

We’ve worked with many clients in different hospitals and we’ve been able to successfully apply our rostering algorithm to automate rosters for each and every one of them.

One of the departments we’ve helped with needs to arrange rosters not only for their own hospital, but also for a neighbouring hospital as some of their staff rotate duties there as well.

Here’s how we tackled the challenge and turned their manual roster into an automated process in 1 month.

In this post we’ll share:

  • The process to analysing roster rules and turning them into roster models
  • The trick we used to fairly schedule between 2 rosters
  • The results we’ve achieved working with

How To Automate Hospital Staff Rosters

For those who aren’t familiar, our roster automation process is completely about turning the rostering problem into a mathematical model, and subsequently solving it.

The trick, therefore, is to see the roster rules as mathematical constraints on what distribution of shifts is “allowed”, and what is “not allowed”.

The same technique goes for optimization: you need to consider everything that goes into a “fair, good roster”, and break everything down to construct a mathematical entity that, the higher it gets, the better the roster is.

The unique challenge presented by this department is that, on the surface, we seem to be dealing with 2 rosters: each running in different hospitals. It seemed like if we are to schedule both of them, we’d need to prioritise scheduling for one of the rosters, and accommodate the other one around it.

However, we’re actually only ever dealing with one roster — that is the combined roster of both hospitals. When you schedule with code, it’s actually better that you schedule both simultaneously. It’s faster, it’s better, and you don’t have to compromise one roster for the other — as both are being assigned in equal fashion.

The Process to Analysing Roster Rules and Turning Them Into Roster Models

To be clear, the process of seeing roster rules as mathematical constraints works under a general “framework” of a big Boolean matrix.

The matrix is indexed by (1) The Person; (2) The Date; (3) The Shift Type. If the value of the Boolean is 1 (True), it means that person works a particular shift on a certain day. If the value is 0 (false), it means the person doesn’t work that shift on the day.

With this paradigm in mind, we can start to construct rules into mathematical rules:

I need 1 person for each shift every day.

What does this mean mathematically? It means that for each shift type and each day, the sum of the matrix for all people should equal 1.

(pseudo-code)
for date, shift_type in dates, shift_types:
    num_people_working = sum(matrix[person, date, shift_type] for person in persons)
    add_constraint(num_people_working == 1)

Each person can work at most 1 shift every 3 days

Mathematically, this translates to the fact that, the sum of all shifts in 3 days should be at most 1.

(pseudo-code)
for person, date in persons, dates[:-3]:
    num_shifts_in_3_day_period = sum(matrix[person, date, shift_type] for shift_type in shift_types in date in nearest_3_days)
    add_constraint(num_shifts_in_3_day_period <= 1)

And so on so forth.

You’ll realise the basic rules are really easy to grasp with. They’re at most just linear combinations and inequalities. Of course, at a higher level, some roster rules are better formulated with some more advanced techniques, but the basic linear equations are already enough to handle most of the rules we encounter.

The trick we used to fairly schedule between 2 rosters

The Department has always treated the 2 hospitals as 2 separate rosters. They’d first prioritise the shift arrangements in one of the peripheral hospitals , because it is less flexible, and then work around the main roster to fit through it.

This certainly worked for them (quality wise), but the downside is the heavy thinking and logical reasoning needed to balance between the 2 rosters — since you wouldn’t want the already-overworked doctors to take 2 closely scheduled calls within 1 week.

The key insight is to treat them as the same roster. We’d specify the number of shifts needed in each shift type (across both hospitals), and have the algorithm schedule both at the same time.

But that isn’t enough. Remember that one of the most important factor for a good roster is “evenly spacing out shifts across the month”, which was notoriously hard when you have to consider 1 staff across 2 rosters.

The trick here is to calculate the spacing of shifts in both rosters simultaneously.

Classically, in order to space out shifts, we’d need to know (1) how many shifts there are to fill; and (2) how many staff are there to take the shifts.

Assuming, say, we have 6 staff to carry out 30 on call duties over a month, naturally we’d prefer to have 1 shift every 5 days.

In that line of thinking, we’d construct an indicator variable which returns 1 when each staff works within a period spanning 5 days, and 0 when the staff does not work at all throughout the 5 days. By maximising the sum of these indicators, this would guide the solver to try find a solution that spaces out shifts 5 times a day in order to maximise the number of indicator variables “lit up” per shift assigned (which is 5 in this case).

Now, what if we maximise the same quantity, but with both hospitals considered? This would allow the solver to space out call duties across both hospitals. In other words, if a doctor is assigned a duty at hospital A, the solver would defer from scheduling another shift for him within 5 days of that shift in both hospitals.

As a result, we could create shift schedules that are fair for both hospitals, and doesn’t overwork our staff.

The Results We’ve Achieved

Within several iterations, we’ve settled on a roster configuration that fits best their use: they’d specify parameters like:

  • The team and seniority of each staff
  • Their Annual Leaves, Admin Duties
  • Their No Call Requests
  • Their total number of assigned calls at each seniority and hospital
  • Etc.

And we’ve been able to run the algorithm to generate a suitable roster within 5 minutes.

This previously took them hours.

I’m proud of the results we achieved with them. Within 1 month, we’ve built a customised algorithm that matches each and every aspect they need in their call rosters. The implications are not only the time and effort saved for the admin staff, but also for guaranteeing a fair and balanced work schedule for the team,, which hopefully, we can assist in reducing overwork and burnout associated with the human limitations of roster scheduling previously.

Automate Your Duty Roster with Expert Assistance

Our Duty Roster Scheduling Service

If you’re looking to implement an efficient, fair, and compliant ward roster scheduling system, we can help. We offer personalized roster algorithms tailored to your specific needs. Click here for a free roster audit to see how you can automate your scheduling process.

Learn to Schedule Duty Rosters with Program

If you want to try making your own rostering algorithm, you can learn it with my free e-book. This guide introduces you to the basics of using programming to create efficient and fair schedules. You will learn how to translate ward rules into code, automate repetitive tasks, and generate optimized duty rosters with ease. Because most doctors have little programming experience, I’ve written it for beginners in Python. Download it and start learning now!

Follow Us for More Insights!

I post regularly at my LinkedIn. Follow me for more updated programmatic rostering insights!


Join Our Newsletter

Subscribe to gain weekly insights for roster scheduling!