Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to create a matching algorithm for doctors and hospitals in Python, stuck on conditions

First of all, I would like to point out that I am quite a rookie in python so if my wording of or question itself sounds stupid, please bear with me, just trying to learn.

I created two dictionaries, one of doctors that assings a ranking to hospitals and one of hospitals that assings a ranking to doctors. Doctors to hospitals:

{'Doctor_5': {1.0: 'Hospital_7', 2.0: 'Hospital_6', 3.0: 'Hospital_8', 4.0: 'Hospital_5', 5.0: 'Hospital_9', 6.0: 'Hospital_4', 7.0: 'Hospital_10', 8.0: 'Hospital_3', 9.0: 'Hospital_2', 10.0: 'Hospital_1'}, 'Doctor_9': {1.0: 'Hospital_9', 2.0: 'Hospital_8', 3.0: 'Hospital_10', 4.0: 'Hospital_7', 5.0: 'Hospital_6', 6.0: 'Hospital_5', 7.0: 'Hospital_4', 8.0: 'Hospital_3', 9.0: 'Hospital_2', 10.0: 'Hospital_1'}, 'Doctor_8': {1.0: 'Hospital_8', 2.0: 'Hospital_9', 3.0: 'Hospital_10', 4.0: 'Hospital_7', 5.0: 'Hospital_6', 6.0: 'Hospital_5', 7.0: 'Hospital_4', 8.0: 'Hospital_3', 9.0: 'Hospital_2', 10.0: 'Hospital_1'}, 'Doctor_1': {1.0: 'Hospital_1', 2.0: 'Hospital_2', 3.0: 'Hospital_3', 4.0: 'Hospital_4', 5.0: 'Hospital_5', 6.0: 'Hospital_6', 7.0: 'Hospital_7', 8.0: 'Hospital_8', 9.0: 'Hospital_9', 10.0: 'Hospital_10'}, 'Doctor_4': {1.0: 'Hospital_5', 2.0: 'Hospital_6', 3.0: 'Hospital_4', 4.0: 'Hospital_7', 5.0: 'Hospital_3', 6.0: 'Hospital_2', 7.0: 'Hospital_1', 8.0: 'Hospital_8', 9.0: 'Hospital_9', 10.0: 'Hospital_10'}, 'Doctor_3': {1.0: 'Hospital_4', 2.0: 'Hospital_3', 3.0: 'Hospital_2', 4.0: 'Hospital_1', 5.0: 'Hospital_5', 6.0: 'Hospital_6', 7.0: 'Hospital_7', 8.0: 'Hospital_8', 9.0: 'Hospital_9', 10.0: 'Hospital_10'}, 'Doctor_6': {1.0: 'Hospital_7', 2.0: 'Hospital_8', 3.0: 'Hospital_6', 4.0: 'Hospital_9', 5.0: 'Hospital_5', 6.0: 'Hospital_10', 7.0: 'Hospital_4', 8.0: 'Hospital_3', 9.0: 'Hospital_2', 10.0: 'Hospital_1'}, 'Doctor_7': {1.0: 'Hospital_8', 2.0: 'Hospital_7', 3.0: 'Hospital_9', 4.0: 'Hospital_6', 5.0: 'Hospital_5', 6.0: 'Hospital_4', 7.0: 'Hospital_3', 8.0: 'Hospital_2', 9.0: 'Hospital_1'}, 'Doctor_10': {1.0: 'Hospital_10', 2.0: 'Hospital_9', 3.0: 'Hospital_8', 4.0: 'Hospital_7', 5.0: 'Hospital_6', 6.0: 'Hospital_5', 7.0: 'Hospital_4', 8.0: 'Hospital_3', 9.0: 'Hospital_2', 10.0: 'Hospital_1'}, 'Doctor_2': {1.0: 'Hospital_3', 2.0: 'Hospital_2', 3.0: 'Hospital_4', 4.0: 'Hospital_1', 5.0: 'Hospital_5', 6.0: 'Hospital_6', 7.0: 'Hospital_7', 8.0: 'Hospital_8', 9.0: 'Hospital_9', 10.0: 'Hospital_10'}}

Hospitals to doctors:

{'Hospital_2': {1.0: 'Doctor_1', 2.0: 'Doctor_2', 3.0: 'Doctor_3', 4.0: 'Doctor_4', 5.0: 'Doctor_5', 6.0: 'Doctor_6', 7.0: 'Doctor_7', 8.0: 'Doctor_8', 9.0: 'Doctor_9', 10.0: 'Doctor_10'}, 'Hospital_1': {1.0: 'Doctor_1', 2.0: 'Doctor_2', 3.0: 'Doctor_3', 4.0: 'Doctor_4', 5.0: 'Doctor_5', 6.0: 'Doctor_6', 7.0: 'Doctor_7', 8.0: 'Doctor_8', 9.0: 'Doctor_9', 10.0: 'Doctor_10'}, 'Hospital_8': {1.0: 'Doctor_8', 2.0: 'Doctor_9', 3.0: 'Doctor_7', 4.0: 'Doctor_6', 5.0: 'Doctor_10', 6.0: 'Doctor_4', 7.0: 'Doctor_3', 8.0: 'Doctor_2', 9.0: 'Doctor_1'}, 'Hospital_7': {1.0: 'Doctor_5', 2.0: 'Doctor_6', 3.0: 'Doctor_7', 4.0: 'Doctor_8', 5.0: 'Doctor_3', 6.0: 'Doctor_2', 7.0: 'Doctor_9', 8.0: 'Doctor_1', 9.0: 'Doctor_10'}, 'Hospital_10': {1.0: 'Doctor_10', 2.0: 'Doctor_9', 3.0: 'Doctor_8', 4.0: 'Doctor_7', 5.0: 'Doctor_6', 6.0: 'Doctor_5', 7.0: 'Doctor_4', 8.0: 'Doctor_3', 9.0: 'Doctor_2', 10.0: 'Doctor_1'}, 'Hospital_3': {1.0: 'Doctor_1', 2.0: 'Doctor_2', 3.0: 'Doctor_3', 4.0: 'Doctor_4', 5.0: 'Doctor_5', 6.0: 'Doctor_6', 7.0: 'Doctor_7', 8.0: 'Doctor_8', 9.0: 'Doctor_9', 10.0: 'Doctor_10'}, 'Hospital_9': {1.0: 'Doctor_9', 2.0: 'Doctor_10', 3.0: 'Doctor_8', 4.0: 'Doctor_7', 5.0: 'Doctor_6', 6.0: 'Doctor_5', 7.0: 'Doctor_4', 8.0: 'Doctor_3', 9.0: 'Doctor_2', 10.0: 'Doctor_1'}, 'Hospital_5': {1.0: 'Doctor_4', 2.0: 'Doctor_3', 3.0: 'Doctor_2', 4.0: 'Doctor_1', 5.0: 'Doctor_5', 6.0: 'Doctor_6', 7.0: 'Doctor_7', 8.0: 'Doctor_8', 9.0: 'Doctor_9', 10.0: 'Doctor_10'}, 'Hospital_4': {1.0: 'Doctor_3', 2.0: 'Doctor_2', 3.0: 'Doctor_4', 4.0: 'Doctor_1', 5.0: 'Doctor_5', 6.0: 'Doctor_6', 7.0: 'Doctor_7', 8.0: 'Doctor_8', 9.0: 'Doctor_9', 10.0: 'Doctor_10'}, 'Hospital_6': {1.0: 'Doctor_4', 2.0: 'Doctor_5', 3.0: 'Doctor_6', 4.0: 'Doctor_3', 5.0: 'Doctor_2', 6.0: 'Doctor_1', 7.0: 'Doctor_8', 8.0: 'Doctor_9', 9.0: 'Doctor_10'}}

I also created a list of doctors as this is used to create the index of my DataFrame resulting from the algorithm:

['Doctor_5', 'Doctor_9', 'Doctor_8', 'Doctor_1', 'Doctor_4', 'Doctor_3', 'Doctor_6', 'Doctor_7', 'Doctor_10', 'Doctor_2']

Now I am trying to create an algorithm that assigns doctors to hospitals based on the Gale-Shapley algorithm (knowing specifics is not necessary).

This is what I have come up with so far, I am presenting it in a DataFrame in the end because I find this more clear to interpret:

Matches = {}
Matches['Doctors'] = (doctors)
First_round = []
for Doctor_ in ranking_by_doctors:
    First_round.append(ranking_by_doctors[Doctor_].get(1.0))
Matches['First round'] = (First_round)
Matches
Matches_round_1 = pd.DataFrame.from_dict(Matches)
Matches_round_1.set_index('Doctors', inplace=True)
Matches_round_1   

This is my result:enter image description here

As you can see I am assigning the most preferred hospital of every doctor to that doctor. But I need help with the conditions of my function. As of right now there exist duplicates in my result: both doctor_7 and doctor_8 are matched to hospital_8, similarily hospital_7 is matched to two different doctors. However, I want to add a condition to my function that checks, in cases like these, which doctor the hospital prefers most, matching that doctor and leaving the other doctor unmatched. Afterwards I want to start the whole process again for the unmatched doctors, leading to new results in round 2. For this second round it should be possible that already matched hospitals break their match because a doctor approaches them that they prefer over their first match.

However, after looking at adjusting my function for some hours and exploring google and list comprehension guides for help, I have still not managed to find a solution. That is why I am turning to stackoverflow for help, maybe one of you has seen this problem before and can help me solve it. If you need anymore information than provided above, let me know!

Thank you very much in advance,

like image 350
Jeff Avatar asked Oct 27 '25 11:10

Jeff


1 Answers

I changed the First_round to a dictionary to make it a bit more straight forward. I would also suggest some other structure changes, but more on that afterwards. A solution is to simply pu in an if check to see if the specific hospital has been assigned and then exchange the doctor if he has a better score:

def hospital_ranking_of_doctor(hospital, doctor):
    return next(v for k, v in ranking_by_hospital[hospital].items() if v == doctor)

Matches = {}
Matches['Doctors'] = (doctors)
First_round = {}

# We loop through all the doctors one by one
for Doctor_ in ranking_by_doctors:

    # Then we find which hospital the doctor prefers
    favored_hospital = ranking_by_doctors[Doctor_].get(1.0)

    # We test if that hospital has already had a doctor assigned
    if favored_hospital not in First_round:
        # If it has not, then we just assign the current doctor
        First_round[favored_hospital] = Doctor_
    else:
        # If the hosptial was already assigned a doctor we compare 
        # that doctor with the new one and set the new one only if 
        # the hospital prefers him.
        previously_assigned_doctor = First_round[favored_hospital]
        if hospital_ranking_of_doctor(favored_hospital, previously_assigned_doctor) > hospital_ranking_of_doctor(favored_hospital, Doctor_):
            First_round[favored_hospital] = Doctor_

print(First_round)

Now for the structure changes, I think you should also either change the ranking structures from being a dictionary ranging numbers to hospitals/doctors, to either just being an ordered list of preferences or flipping it so the key is the hospital/doctor and the priority/score being the value. This would make checking the score of a doctor more natural like:

ranking_by_hospital['Hospital_2']['Doctor_2'] > ranking_by_hospital['Hospital_2']['Doctor_3']

So you could update the ranking function to be:

def hospital_ranking_of_doctor(hospital, doctor):
    return ranking_by_hospital[hospital][doctor]

Or simply inline those code bits.

like image 175
Vincent Avatar answered Oct 28 '25 23:10

Vincent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!