【问题标题】:Trying to create a matching algorithm for doctors and hospitals in Python, stuck on conditions试图用 Python 为医生和医院创建匹配算法,但遇到了条件
【发布时间】:2019-06-18 05:15:19
【问题描述】:

首先,我想指出我在python方面是一个新手,所以如果我的措辞或问题本身听起来很愚蠢,请多多包涵,我只是在努力学习。

我创建了两个字典,一个为医院分配排名的医生,另一个为医生分配排名的医院。 医生到医院:

{'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'}}

医院到医生:

{'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'}}

我还创建了一个医生列表,因为它用于创建由算法产生的 DataFrame 的索引:

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

现在我正在尝试创建一个算法,根据 Gale-Shapley 算法将医生分配到医院(无需了解细节)。

这是我到目前为止的想法,最后我将它呈现在一个 DataFrame 中,因为我发现这更容易解释:

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   

这是我的结果:

如您所见,我将每位医生最喜欢的医院分配给该医生。但我需要有关我的职能条件的帮助。截至目前,我的结果中存在重复项:医生_7 和医生_8 都与医院_8 匹配,类似地,医院_7 与两个不同的医生匹配。但是,我想在我的函数中添加一个条件,在这种情况下检查医院最喜欢哪个医生,匹配那个医生,而让其他医生不匹配。之后,我想为未匹配的医生重新开始整个过程​​,在第 2 轮中产生新的结果。对于第二轮,已经匹配的医院应该有可能打破他们的匹配,因为医生接近他们,他们更喜欢他们的第一次匹配。

但是,在调整我的功能几个小时并探索谷歌和列表理解指南寻求帮助之后,我仍然没有设法找到解决方案。这就是为什么我转向stackoverflow寻求帮助的原因,也许你们中的一个人以前见过这个问题并且可以帮助我解决它。如果您需要上述信息以外的更多信息,请告诉我!

非常感谢您,

【问题讨论】:

  • 你能提供你的 Gale-Shapley 算法的实现吗?我问是因为,如果您的方案中有相同数量的提议者和接受者、医生和医院,则输出不应包含重复项。另外,您确定这是 SMP 吗?也许这是一个分配问题,匈牙利算法会更适合你。
  • 感谢您的评论佩德罗。到目前为止,这是我的实现,我正在尝试重建算法。此外,我确实有相同数量的医生和医院。
  • 在您寻求有关实际算法实现的帮助时说“(无需了解细节)”会产生误导。

标签: python dictionary conditional-statements list-comprehension matching


【解决方案1】:

我将 First_round 更改为字典以使其更直接。我还建议进行一些其他结构更改,但之后会更多。一个解决方案是简单地输入 if 检查以查看是否已分配特定医院,然后如果他的分数更高则交换医生:

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)

现在对于结构更改,我认为您还应该将排名结构从字典范围从数字到医院/医生更改为只是一个有序的偏好列表或翻转它,因此关键是医院/医生优先级/分数是价值。这将使检查医生的分数更自然,例如:

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

因此您可以将排名函数更新为:

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

或者只是内联那些代码位。

【讨论】:

  • 嘿文森特,谢谢你的回答!我翻转了钥匙和排名,这是你的意思吗? 'Doctor_5':{'Hospital_2':9.0,'Hospital_1':10.0,'Hospital_3':8.0,'Hospital_10':7.0,'Hospital_4':6.0,'Hospital_7':1.0,'Hospital_9':5.0,'Hospital_5' : 4.0, 'Hospital_8': 3.0, 'Hospital_6': 2.0} 抱歉,我不知道如何将其转换为代码格式。但是,这会阻止 .get 函数正常工作。
  • @Jeff,我添加了一个更新的排名函数来显示我的意思,虽然它变得很短,所以你可以考虑简单地内联那个位。要在 cmets 中格式化代码,请在代码段周围使用单个反引号 `。您可以单击评论字段右侧的“帮助”,然后单击“了解有关格式化的更多信息”,您还可以获得所有其他支持的格式化类型的参考。
  • 非常感谢!如果你有时间,还有几个问题。 “内联”是什么意思?此外,(同样只有在您有时间的情况下)您是否可以在您的代码中添加一些 cmets 来解释您的代码在该步骤中到底在做什么。如果我复制它,它就可以工作,太好了!但我也很想了解它。
  • 通过内联我的意思是获取函数的主体,然后将其插入到您将调用该函数的位置,例如,而不是使用def comp(a,b): return a>b,然后在某处调用if comp(k,b) and comp(k, x):,您只需调用if k>b and k>x: 如果您有一个非常短的函数并且没有在很多地方使用,则通常会这样做。我在代码中添加了一些 cmets,希望对您有所帮助。
  • 感谢大家的帮助,现在很清楚了!我真的很感激!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-14
  • 1970-01-01
  • 2023-02-09
  • 2018-08-22
  • 2018-11-29
相关资源
最近更新 更多