前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >根据职位说明使用机器学习来检索相关简历

根据职位说明使用机器学习来检索相关简历

作者头像
KX_WEN
发布2018-02-05 17:59:25
1.5K0
发布2018-02-05 17:59:25

我们使用平均词嵌入(AWE)模型基于职业描述来检索相关的CV。我们在这提供了一个循序渐进的指南,通过使用西班牙语的文件(简历)训练,将已训练的领域词嵌入与预先训练好嵌入结合起来。我们还使用主要成分分析(PCA)作为一种缩减技术,用于将类似的维度用于单词嵌入结果。

架构描述

信息检索(IR)模型是由一个索引语料库和评分或排序功能所组成的。IR系统的主要目标是根据用户请求检索相关文档或网页。在检索过程中,评分功能根据检索到的文档与用户查询的相关性来对检索到的文档进行排序。诸如像BM25和语言模型这样的经典IR模型都是基于bag-of-words(BOW)索引方案。BOW模型有两个主要弱点:它们丢失了出现单词的上下文,而且也忽略了它的语义。潜在语义索引Latent semantic indexing(LSI)是一种用于处理这个问题的技术,但是当文档数量增加时,索引处理计算量将变得很大。最标准的解决这个问题的方法就是训练单词或语句嵌入到语料库中或者使用预训练的语料库。

字嵌入(WE)是从神经网络模型获得的术语的分布式表示。这些连续的表示近期已经被用于不同的自然语言处理任务中。平均词嵌入(AWE)是一种比较受欢迎的表示长文本序列的技术,它不仅仅是表示一个术语。

在我们的例子中,我们需要一组简历,但由于工作的描述是事先未知的,我们需要提供一个基于无监督学习方法的解决方案。因此,词嵌入的使用似乎是我们实验的一个很好的起点。

下图是架构的定义。

步骤1:训练域词嵌入(已训WEs)

作为第一步,我们从四个已知的职业(Java工程师,测试工程师Tester,人力资本管理SAP HCM和销售与分销SAP SD)中构建一个平均的简历文档,使得四个职业简历文档数量相当。由于简历是用不同格式和不同风格和词汇编写的,所以我们决定只使用名词和动词,以便从简历中获得重要和相关的信息。建立语料库后,我们将他传输给Word2vec,并设定以下参数:窗口大小为5,最小字数为3,维数为200. CBOW默认使用的就是Word2vec模型。

我们在Linux Ubuntu 16.04 LTS上使用Python 3.6.1和64位的Anaconda 。为了安装多个库,pip必须按如下所示运行install命令:

代码语言:javascript
复制
pip install gensim
pip install pattern3
pip install textract
pip install numpy
pip install scipy
pip install sklearn 
pip install pickle

在安装了所有需要的软件包之后,我们创建一个函数来从特定的文件夹中检索所有的CV,读取它们(使用textract),将它们解析(使用模式3),最后创建嵌入字(使用gensim)。负责从简历(PDF,TXT,DOC,DOCX)中提取文本的python函数定义如下:

代码语言:javascript
复制
from gensim.models import Word2Vec, KeyedVectors
from pattern3 import es
import textract
from os import listdir
rom os.path import isfile, join
import numpy as np
from scipy import spatial
from sklearn import decomposition
import matplotlib.pyplot as plt
import pickle
def read_All_CV(filename):
text = textract.process(filename)
return text.decode('utf-8')
#Next, we define a function to parse the documents (CVs) and save the word embeddings as follows:
def preprocess_training_data1(dir_cvs, dir_model_name):   
dircvs = [join(dir_cvs, f) for f in listdir(dir_cvs) if isfile(join(dir_cvs, f))]
alltext = ' '  
for cv in dircvs:
    yd = read_All_CV(cv)
    alltext += yd + " "   
    alltext = alltext.lower()
    vector = []
    for sentence in es.parsetree(alltext, tokenize=True, lemmata=True, tags=True):
        temp = []
        for chunk in sentence.chunks:
            for word in chunk.words:                            
                 if word.tag == 'NN' or word.tag == 'VB':
                    temp.append(word.lemma)
                    vector.append(temp)
                    global model
                    model = Word2Vec(vector, size=200, window=5, min_count=3, workers=4)
                    model.save(dir_model_name)

一旦所有的嵌入被保存进 dir_model_name,我们已经完成了将单词嵌入设置到全局变量模型的任务,我们可以使用PCA技术来减少预训练词嵌入的维度。

第2步:下载并减少预训练字嵌入(Pretrained PCA WEs)

在我们下载西班牙预训练词并嵌入后,我们观察到这些向量共有300个维度,我们提出的领域训练的嵌入有200个维度。于是我们决定将300维矢量缩减为200维,然后用两个词嵌入空间来构建混合空间。以下函数负责减少预先训练的词嵌入的维度:

代码语言:javascript
复制
def reduce_dimensions_WE(dir_we_SWE, dir_pca_we_SWE):
m1 = KeyedVectors.load_word2vec_format(dir_we_SWE ,binary=True)
model1 = {}
# normalize vectors
for string in m1.wv.vocab:
model1[string]=m1.wv[string] / np.linalg.norm(m1.wv[string])
# reduce dimensionality
pca = decomposition.PCA(n_components=200)
pca.fit(np.array(list(model1.values())))
model1=pca.transform(np.array(list(model1.values())))
i = 0
for key, value in model1.items():
    model1[key] = model1[i] / np.linalg.norm(model1[i])
    i = i + 1
    with open(dir_pca_we_SWE, 'wb') as handle:
    pickle.dump(model1, handle, protocol=pickle.HIGHEST_PROTOCOL)
    return model1

一旦获得了简化矢量,我们可以使用混合词嵌入和AWE来执行检索任务,以计算简历(CV)和查询(职业描述)的均值向量。

步骤3:构建混合词嵌入空间并检索相关简历(CV)

我们展示了一个在实验室中开发的服务,我们实际上加载了两个嵌入空间,当请求到来时,这个潜入空间必须被选择使用。例如,如果用户公布了一个职位名称“Java”,我们将会加载训练的嵌入空间。当输入另一个未知的配置文件,例如说“Cobol Analyst”时,则使用预先训练的词嵌入。另外,对于每个CV和职位请求,计算其平均字嵌入向量。最后,我们只是检索与职位描述要求相匹配的前三名的简历。以下Python函数负责这个处理块:

代码语言:python
代码运行次数:0
复制
model1 = Word2Vec.load(join(APP_STATIC, "word2vec/ourModel"))
with open(join(APP_STATIC, 'word2vec/reduced_pca.pickle'), 'rb') as f:
model2 = pickle.load(f)
@app.route('/find/', methods=['GET'])
def find():  
data = request.args.get('value')
w2v = []
aux = data.lower().split(" ")[0:5]
sel = len(set(['java','sap','tester','prueba','hcm','sd','pruebas','testing']).intersection(aux))
val = False
if sel > 0:
   model = model1
   val = True
else:
   model = model2
   if val:
      data = data.lower()
      for sentence in es.parsetree(data, tokenize=True, lemmata=True, tags=True):
          for chunk in sentence.chunks:
              for word in chunk.words:
                  if val:
                     if word.lemma in model.wv.vocab:
                        w2v.append(model.wv[word.lemma])
                     else:
                          if word.lemma.lower() in model.wv.vocab:
                           w2v.append(model.wv[word.lemma.lower()])
                     else:
                           if word.string in model.keys():
                              w2v.append(model[word.string])
                     else:
                           if word.string.lower() in model.keys():
                              w2v.append(model[word.string.lower()])
                              Q_w2v = np.mean(w2v, axis=0)
                              # Example of document represented by average of each document term vectors.
                              dircvs = APP_STATIC + "/cvs_dir"
                              dircvsd = [join(dircvs, f) for f in listdir(dircvs) if isfile(join(dircvs, f))]
                              D_w2v = []
                              for cv in dircvsd:
                                  yd = textract.process(cv).decode('utf-8')
                                  w2v = []
                              for sentence in es.parsetree(yd.lower(), tokenize=True, lemmata=True, tags=True):
                              for chunk in sentence.chunks:
                              for word in chunk.words:
                                 if val:
                                 if word.lemma in model.wv.vocab:
                                    w2v.append(model.wv[word.lemma])
                                 else:
                                 if word.lemma.lower() in model.wv.vocab:
                                    w2v.append(model.wv[word.lemma.lower()])
                                 else:
                                 if word.string in model.keys():
                                    w2v.append(model[word.string])
                                 else:
                                 if word.string.lower() in model.keys():
                                    w2v.append(model[word.string.lower()])
                                    D_w2v.append((np.mean(w2v, axis=0),cv))
                                    # Make the retrieval using cosine similarity between query and document vectors.
                                    retrieval = []
                                 for i in range(len(D_w2v)):
                                     retrieval.append((1 - spatial.distance.cosine(Q_w2v, D_w2v[i][0]),D_w2v[i][1]))
                                     retrieval.sort(reverse=True)
                                     ret_data = {"cv1":url_for('static', filename="test/"+retrieval[0][1][retrieval[0][1].rfind('/')+1:]), "score1": str(round(retrieval[0][0], 4)), "cv2":url_for('static', filename="test/"+retrieval[1][1][retrieval[1][1].rfind('/')+1:]), "score2": str(round(retrieval[1][0], 4)),"cv3":url_for('static', filename="test/"+retrieval[2][1][retrieval[2][1].rfind('/')+1:]), "score3": str(round(retrieval[2][0], 4))   }
                              return jsonify(ret_data)
评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 架构描述
  • 第2步:下载并减少预训练字嵌入(Pretrained PCA WEs)
  • 步骤3:构建混合词嵌入空间并检索相关简历(CV)
相关产品与服务
NLP 服务
NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档