招聘市场上 自然语言处理工程师都得会点啥
以boss直聘https://www.zhipin.com/上面搜索nlp为例,我们抓取数据,探索一下市场上对nlp人才的需求.
代码放在https://github.com/sdu2011/nlp.你可以稍加改造,看看自己所在地区,目标职位都要求一些什么技能.
以南京地区的nlp岗位为例.
- 要抓取职位列表.获取招聘方信息.抓取到职位详情页面的url。
- 要抓取职位详情,解析详情,分词,统计,提取关键词等
- 可视化. seaborn wordcloud等图形化展示.
数据抓取与清洗
这部分就不多谈了.主要要了解一些爬虫知识.html页面的解析库BeatifulSoup用法.这一步"脏活比较多",主要就是分析各种html的tag的格式,去除空格啦,提取各种tag下信息啦之类的数据清洗工作.
current_url = "https://www.zhipin.com/job_detail/?query=nlp&scity=101190100&industry=&position=" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' ,'Connection': 'keep-alive' } r=requests.get(current_url,headers=headers) def parse_job_detail(url): r=requests.get(url,headers=headers) bs = BeautifulSoup(r.text,"html.parser") h3=bs.find("h3",text="职位描述") #print(h3.find_next_sibling("div")) div_tag = h3.find_next_sibling("div") #print(div_tag.text) requirements = []#任职要求 responsbility = []#岗位职责 require_flag = False responsbility_flag = False for c in div_tag.children: #print(c,type(c)) if type(c) is bs4.element.NavigableString: str_no_space = c.string.replace(" ","") #print(str_no_space) if str_no_space.find("任职要求") != -1: #这边不能用==判断 因为前面由于中文字符的问题 replace替换不掉:后面的blank responsbility_flag = False require_flag = True continue if str_no_space.find("岗位职责") != -1: #这边不能用==判断 因为前面由于中文字符的问题 replace替换不掉:后面的blank require_flag = False responsbility_flag = True continue if require_flag: requirements.append(str_no_space) if responsbility_flag: responsbility.append(str_no_space) #print(requirements) #print(responsbility) return (requirements,responsbility) #parse_job_detail("https://www.zhipin.com/job_detail/84e81e27c933269e1Xxz3dq1E1I~.html?ka=search_list_1") def get_jobs_info(url): r=requests.get(url,headers=headers) bs = BeautifulSoup(r.text,"html.parser") jobs = [] for job in bs.find_all("div",class_="job-primary"): #print("**************************************************************") one_job = [] for child in job.descendants: if child.name == 'div'and child['class'] == ['info-primary']: jobdetails = parse_job_detail("https://www.zhipin.com/%s" % (child.h3.a.get('href'))) one_job.append(child.h3.div.text) #title #print(one_job) one_job.append(child.h3.span.text) #salary #one_job.append(child.h3.a.get('href')) #link one_job.append(jobdetails[0]) #requirements one_job.append(jobdetails[1]) #responsbility index = 0 for c in child.p: if index == 0: #print(c) one_job.append(c) #地区 elif index == 2: #print(c) one_job.append(c) #经验 elif index == 4: #print(c) one_job.append(c) #学历 index += 1 elif child.name == 'div' and child['class'] == ['info-company']: #print(child.a.string) index = 0 for c in child.p: if index == 0: #print(c) #行业 one_job.append(c) elif index == 2: #print(c) #公司发展阶段 A/B/C/D轮/上市 one_job.append(c) elif index == 4: #print(c) #规模 one_job.append(c) index += 1 pass #print(one_job) jobs.append(one_job) return jobs jobs_info=get_jobs_info("https://www.zhipin.com/job_detail/?query=nlp&scity=101190100&industry=&position=")
数据抓取完成后
数据探索
这部分,需要对pandas,seaborn有一些了解.
下面我们就可以用seaborn对数据做可视化处理了.
解决sns显示中文字体的问题 from matplotlib.font_manager import FontProperties myfont=FontProperties(fname=r'C:\Windows\Fonts\simhei.ttf',size=14) sns.set(font=myfont.get_name())
- 学历
先来看看学历的要求.(说到这我就心痛,为什么当初要放弃读研,真想抽自己两耳光!!!! 直接导致了现在接近一半的职位连门槛都跨不进去)。
可以看到NLP工程师对学历的要求还是比较高,图标里硕士学历要求基本接近40%.实际上,要接近50%,因为有的岗位在职位搜索页面标注的是本科即可,但是实际上职位详情里又说明了要求硕士.
所以,有志于NLP的小伙伴能读研的还是读研吧,有志于NLP的小伙伴能读研的还是读研吧,有志于NLP的小伙伴能读研的还是读研吧,重要的事情说三遍.
- 经验.
可以看到3年左右经验是比较受欢迎的.这也符合常识,首先NLP这几年是随着深度学习的发展开始火起来,经验特别丰富的从业者并不多.而且,不光是NLP,别的岗位也是3/5/8年比较吃香,因为此时你已经是这个级别的熟练工种了.
- 学历+经验
依然类似的结论,在各个学历下,都是3年左右的需求比较多.
- 规模
首先,千人以上的公司招聘需求相对大,比较好理解. 比较意外的是100-499的中小公司招聘需求相对较多.可能是最近几年随着深度学习的兴起,很多AI相关业务的A轮/B轮的创业公司.
验证一下我们上面的猜测,100-499规模中,A/B轮的比较多.
- 地区
排除没有标明具体地区的,剩下的雨花台铁心桥一带需求最多,因为那边是"宇宙的中心",大量的科技公司和码农聚集到软件大道一带. 剩下的江宁区的岗位也相对多.
- 薪水
大部分集中在15-30k
我们取月薪的均值再看一眼.这里我们添加新的一列"平均月薪".
#处理月薪数据 def f(s): #x="17k-18k" l = s.replace('k','').split('-') tmp=[int(e) for e in l] return sum(tmp)/len(tmp) df["平均月薪"]=df["月薪"].apply(f)
那种4k的基本是实习生.这么一看平均有22k,很诱人,有没有. 考虑到用人单位说的15-30k,一般指15k.... 我们再处理一下数据,绘图
def min_salary(s): #x="17k-18k" l = s.replace('k','').split('-') return int(l[0]) df["最低月薪"]=df["月薪"].apply(min_salary)
再看看不同规模公司中,不同学历与月薪的关系.小公司里本科生更多.大公司里硕士生占比提高.
NLP工程师需要会什么?
之前的代码里,我们已经抓取到了任职描述和岗位要求,现在我们使用jieba去做分词.
- 注意去掉stopwords
- 词典添加自定义词.比如希望'机器学习'被认为是一个完整的词,而不是‘机器’、‘学习’两个词.
f = open("./词表/哈工大停用词表.txt",encoding='utf-8') stopword_list = [line.strip() for line in f.readlines()]
self_defined_list = ['1','2','3','4','5','6','以上学历','关于','\n'] stopword_list.extend(self_defined_list) print(stopword_list) def add_self_defined_words(): jieba.add_word('机器学习') jieba.add_word('深度学习') def get_words(serie): clean_contents=[] for s in serie: s_tmp = ''.join(s) #clean_s= re.sub(r'[^\u4e00-\u9fa5]', '', s_tmp) #https://github.com/fxsjy/jieba/issues/528 这个会去除中文词之外的词 clean_s = s_tmp clean_contents.append(clean_s) add_self_defined_words() word_list = [word for word in jieba.cut(''.join(clean_contents),cut_all=False) if word not in stopword_list] print(word_list) tags=jieba.analyse.extract_tags(''.join(clean_contents), topK=20) print(tags) return word_list,tags require_word_list,require_tags = get_words(df["任职要求"]) responsibility_word_list,responsibility_tags = get_words(df["岗位职责"])
结巴的topk关键词抽取使用的是tfidf,不是词频.仅供参考.这里我们其实更关心词频.
可以看到经验还是很重要的.不管是相关工作经验还是研究经验.
同样的看下岗位职责
为了探索特定词的词频,写了函数count_specific_word,考虑了相似词,比如Python和python其实想表达的是一个意思.
一般框架名都为英文比如tensorflow/hadoop等,写了函数get_englishword_list去获取这些英文词,情况如下:
可以发现tensorflow是最常被要求掌握的深度学习框架.
#获取特定词的出现次数 def count_specific_word(serie,word_list): index = [False] * len(serie) for w in word_list: tmp_list = list(serie == w) #print(list(tmp_list).count(True)) index=list(np.logical_or(tmp_list,index)) #注意一下两个boolean list相应位置and or的用法 #print(index.count(True)) return list(index).count(True) print(count_specific_word(require_word_series,["TensorFlow"])) print(count_specific_word(require_word_series,["经验"])) print(count_specific_word(require_word_series,["研究生","硕士"])) print(count_specific_word(require_word_series,["深度学习","机器学习"])) print(count_specific_word(require_word_series,["python","Python"])) #把中文去掉 def get_englishword_list(): l = [] for w in require_word_list: w=re.sub(r'[\u4e00-\u9fa5\n]', '',w) if w == "": continue else: #print(w) l.append(w.lower()) print(l) return l enw_serie = pd.Series(get_englishword_list()) enw_serie.value_counts()
为了获得更直观的印象,我们将关键词用词云绘制.
from wordcloud import WordCloud, ImageColorGenerator from scipy.misc import imread import matplotlib.pyplot as plt def picture(wordlist): font='C:\Windows\Fonts\simhei.ttf' wc = WordCloud(background_color="white",font_path=font,max_words=2000) wc.generate(" ".join(wordlist)) plt.figure() plt.imshow(wc, interpolation="bilinear") plt.axis("off") plt.show()
picture(require_word_list),picture(responsibility_word_list)
将两组词合起来绘制出的词云如下:
总结:当前的NLP工程师招聘,基本上都要求有工作经验或研究经验的.(实际上意味着你如果你没有在学生阶段有NLP的经验的话,那么这个岗位基本也就与你无缘了...工作后会因为没有相关经验很难切入这个领域...不切入这个领域又很难积累经验...死循环)。 需要掌握python/java等,需要了解深度学习,最好能掌握诸如tensorflow的框架,具体要掌握的nlp相关技能会涉及数据挖掘、文本分词分类、实体抽取、知识图谱构件等.
最后,如果有南京地区的同学,求内推....