熊猫匹配算法

时间:2019-05-01 17:47:34

标签: python pandas

说,我有一个像这样的数据框:

                     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)

这可以在没有显式迭代的情况下在熊猫中实现吗?

2 个答案:

答案 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)