说,我有一个像这样的数据框:
affinity
applicant_id job_id
1 a 7
b 7
c 5
2 a 0
b 4
c 2
3 a 4
b 8
c 1
我需要使每个申请人与工作匹配,以便(a)优先考虑具有较高的亲和力; (b)没有申请人符合一份以上的职位; (c)没有一份工作适合多于一名申请人。因此,在上面的示例中,我想获得
affinity
applicant_id job_id
3 b 8
1 a 7
2 c 2
我能想到的最好的是
tmp = candidates.sort_values(ascending=False).copy()
matches = []
while len(tmp):
(applicant, job), affinity = next(tmp.iteritems())
matches.append((applicant, job))
tmp = tmp.loc[(tmp.index.get_level_values('applicant_id') != applicant)
& (tmp.index.get_level_values('job_id') != job)]
candidates.reindex(matches)
这可以在没有显式迭代的情况下在熊猫中实现吗?
答案 0 :(得分:1)
这是典型的linear sum assignment problem。
我们将创建矩阵,以一些高得惊人的代价填充缺失值,以使它们永远不会匹配。仅当至少一个工人对其有亲和力时,一项工作才会出现在此矩阵中,因此它将起作用。
from scipy import optimize
import pandas as pd
df = pd.DataFrame({'applicant_id': [1]*3 + [2]*3 + [3]*3 + [4],
'job_id': ['a', 'b', 'c']*3 + ['h'],
'affinity': [7,7,5,0,4,2,4,8,1,10]})
df1 = df.pivot(index='applicant_id', columns='job_id', values='affinity').fillna(-10**8)
#job_id a b c h
#applicant_id
#1 7.0 7.0 5.0 -100000000.0
#2 0.0 4.0 2.0 -100000000.0
#3 4.0 8.0 1.0 -100000000.0
#4 -100000000.0 -100000000.0 -100000000.0 10.0
opt = optimize.linear_sum_assignment(df1.to_numpy()*-1)
pd.DataFrame(df1.lookup(df1.index[opt[0]], df1.columns[opt[1]]),
columns=['affinity'],
index=pd.MultiIndex.from_arrays([df1.index[opt[0]], df1.columns[opt[1]]]))
affinity
applicant_id job_id
1 a 7.0
2 c 2.0
3 b 8.0
4 h 10.0
我们为每个人分配的工作量比人多,但是有些工作仍然空缺。由于人员多于工作,一些低亲和力的人仍未分配。
答案 1 :(得分:0)
那样的事情怎么样?
job['applicant_id'].fillna(method='ffill', inplace=True)
job_a = job.sort_values(['applicant_id', 'affinity'] , ascending=False).drop_duplicates(['applicant_id'], keep="first").drop_duplicates(['job_id'], keep="first")
job_a = job_a.append(job[~(job['applicant_id'].isin(list(job_a['applicant_id']))) & ~(job['job_id'].isin(list(job_a['job_id'])))])
print(job_a)