Python数据分析——数据分析岗位最新招聘情况

本次主要围绕数据分析岗位的招聘情况,进行一个简单的数据分析
环境win8,python3.7,pycharm,jupyternotebook
正文1.明确分析目的
了解数据分析岗位的最新招聘情况,包括地区分布,学历要求,经验要求,薪资水平等.
2.数据收集
这里借助爬虫,爬取招聘网站的招聘信息,进而分析出相关的薪资以及招聘要求.
2.1目标站点分析
通过对目标站点的分析,我们需要确定目标站点的请求方式,以及网页结构.
2.2新建scrapy项目
1.在cmd命令行窗口中任意路径下执行以下代码,比如在”D:\python\Tests”目录下新建zhaopin项目.
d:cdD:\python\Testsscrapystartprojectzhaopin
2.在完成了zhaopin项目创建之后,接下来就是在zhaopin项目文件夹中新建spider爬虫主程序
cdzhaopinscrapygenspiderzhaopinSpiderzhaopin.com
这样就完成项目zhaopin的创建,开始编写我们的程序吧.
2.3定义items
在items.py文件中定义需要爬取的招聘信息.
importscrapyfromscrapy.itemimportItem,FieldclasszhaopinItem(Item):#definethefieldsforyouritemherelike:#name=scrapy.Field()JobTitle=Field()#职位名称CompanyName=Field()#公司名称CompanyNature=Field()#公司性质CompanySize=Field()#公司规模IndustryField=Field()#所属行业Salary=Field()#薪水Workplace=Field()#工作地点Workyear=Field()#要求工作经验Education=Field()#要求学历RecruitNumbers=Field()#招聘人数ReleaseTime=Field()#发布时间Language=Field()#要求语言Specialty=Field()#要求专业PositionAdvantage=Field()#职位福利
2.4编写爬虫主程序
在zhaopinSpider.py文件中编写爬虫主程序
2.5保存到csv文件
通过pipelines项目管道保存至csv文件
classJob51Pipeline(object):defprocess_item(self,item,spider):withopen(r’D:\Data\ZhaoPin.csv’,‘a’,encoding=‘gb18030’)asf:job_info=[item[‘JobTitle’],item[‘CompanyName’],item[‘CompanyNature’],item[‘CompanySize’],item[‘IndustryField’],item[‘Salary’],item[‘Workplace’],item[‘Workyear’],item[‘Education’],item[‘RecruitNumbers’],item[‘ReleaseTime’],item[‘Language’],item[‘Specialty’],item[‘PositionAdvantage’],‘\n’]f.write(“,”.join(job_info))returnitem
2.6配置setting
设置用户代理,下载延迟0.5s,关闭cookie追踪,调用pipelines
USER_AGENT=‘Mozilla/5.0(WindowsNT6.3;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/68.0.3440.106Safari/537.36’DOWNLOAD_DELAY=0.5COOKIES_ENABLED=FalseITEM_PIPELINES={‘job51.pipelines.Job51Pipeline’:300,}
2.7运行程序
新建main.py文件,并执行以下代码
fromscrapyimportcmdlinecmdline.execute(‘scrapycrawlzhaopin’.split())
这样开始了数据爬取,最终爬取到9000多条数据,在分析这些数据之前,先看看数据都是什么样,进入数据概览环节.
3.数据概览
3.1读取数据
importpandasaspddf=pd.read_csv(r’D:\aPython\Data\DataVisualization\shujufenxishiJob51.csv’)#由于原始数据中没有字段,需要为其添加字段df.columns=[‘JobTitle’,‘CompanyName’,‘CompanyNature’,‘CompanySize’,‘IndustryField’,‘Salary’,‘Workplace’,‘Workyear’,‘Education’,‘RecruitNumbers’,‘ReleaseTime’,‘Language’,‘Specialty’,‘PositionAdvantage’]df.info()
抛出异常:UnicodeDecodeError:‘utf-8’codeccan’tdecodebyte0xbdinposition0:invalidstartbyte
解决办法;用Notepad++将编码转换为utf-8bom格式
转换之后,再次执行
抛出异常:ValueError:Lengthmismatch:Expectedaxishas15elements,newvalueshave14elements
解决办法:在列表[‘JobTitle…..PositionAdvantage’]后面追加’NNN’,从而补齐15个元素.
追加之后,再次执行,执行结果为:
<class’pandas.core.frame.DataFrame’>RangeIndex:9948entries,0to9947Datacolumns(total15columns):JobTitle9948non-nullobjectCompanyName9948non-nullobjectCompanyNature9948non-nullobjectCompanySize9948non-nullobjectIndustryField9948non-nullobjectSalary9948non-nullobjectWorkplace9948non-nullobjectWorkyear9948non-nullobjectEducation7533non-nullobjectRecruitNumbers9948non-nullobjectReleaseTime9948non-nullobjectLanguage901non-nullobjectSpecialty814non-nullobjectPositionAdvantage8288non-nullobjectNNN0non-nullfloat64dtypes:float64(1),object(14)memoryusage:1.1+MB
可以了解到的信息:目前的数据维度9948行X15列,Education,Language,Specialty,PositionAdvantage有不同程度的缺失(NNN是最后添加,仅仅是用来补齐15元素),14个python对象(1个浮点型)
3.2描述性统计
由于我们所需信息的数据类型都是python对象,故使用以下代码
#注意是大写的字母odf.describe(include=[‘O’])
从以下信息(公司名称部分我没有截图)中可以得到:
职位名称中’数据分析师’最多,多为民营公司,公司规模150-500人最多,行业领域金融/投资/证券最多,薪资中6-8千/月最多,大多对工作经验没有要求,学历要求多为本科,多数均招1人等信息.
职位名称的种类就有4758种,他们都是我们本次分析的数据分析师岗位吗,先来确认下:
zhaopin.JobTitle.unique()array([‘零基础免费培训金融外汇数据分析师’,‘数据分析师(周末双休+上班舒适)’,‘数据分析师’,…,‘数据分析实习(J10635)’,‘数据分析实习(J10691)’,‘数据分析实习(J10713)’],dtype=object)
这仅仅显示了职位名称中的一部分,而且还都符合要求,换种思路先看20个
JobTitle=zhaopin.groupby(‘JobTitle’,as_index=False).count()JobTitle.JobTitle.head(20)0(AI)机器学习开发工程师讲师1(ID67391)美资公司数据分析2(ID67465)美资公司数据分析3(ID67674)500强法资汽车制造商数据分析专员(6个月)4(ID67897)知名500强法资公司招聘数据分析专员5(Senior)DataAnalyst6(免费培训)数据分析师+双休+底薪7(实习职位)BusinessDataAnalyst/业务数据分析8(急)人力销售经理9(提供食宿)银行客服+双休10(日语)股票数据分析员/EquityDataAnalyst-Japanese/11(越南语)股票数据分析员/EquityDataAnalyst-Vietnam12(跨境电商)产品专员/数据分析师13(韩语)股票数据分析员/EquityDataAnalyst-Korean14*数据分析15-数据分析师助理/实习生16-数据分析师助理/统计专员+双休五险+住宿17-无销售不加班金融数据分析师月入10k18-金融数据分析师助理6k-1.5w19-金融数据分析师双休岗位分红Name:JobTitle,dtype:object 可以看到还有机器学习开发讲师,人力销售经理,银行客服等其他无效数据. 现在我们对数据有了大致的认识,下来我们开始数据预处理. 4.数据预处理 4.1数据清洗 数据清洗的目的是不让有错误或有问题的数据进入加工过程,其主要内容包括:重复值,缺失值以及空值的处理 4.1.1删除重复值 如果数据中存在重复记录,而且重复数量较多时,势必会对结果造成影响,因此我们应当首先处理重复值. #删除数据表中的重复记录,并将删除后的数据表赋值给zhaopinzhaopin=df.drop_duplicates(inplace=False)zhaopin.shape(8927,15) 对比之前的数据,重复记录1021条. 4.1.2过滤无效数据 我们了解到职位名称中存在无效数据,我们对其的处理方式是过滤掉. #筛选名称中包含’数据’或’分析’或’Data’的职位zhaopin=zhaopin[zhaopin.JobTitle.str.contains(‘.?数据.?|.?分析.?|.?Data.?’)]zhaopin.shape(7959,15) 4.1.3缺失值处理 在pandas中缺失值为NaN或者NaT,其处理方式有多种: 1.利用均值等集中趋势度量填充 2.利用统计模型计算出的值填充 3.保留缺失值 4.删除缺失值 #计算每个特征中缺失值个数zhaopin.isnull().sum()JobTitle0CompanyName0CompanyNature0CompanySize0IndustryField0Salary0Workplace0Workyear0Education1740RecruitNumbers0ReleaseTime0Language7227Specialty7244PositionAdvantage1364NNN7959dtype:int64 –Education:缺失值占比1740/7959=21.86%,缺失很有可能是”不限学历”,我们就用”不限学历”填充 zhaopin.Education.fillna(‘不限学历’,inplace=True) –Language:缺失值占比7227/7959=90.80%,缺失太多,删除特征 –Specialty:缺失值占比7244/7959=91.02%,同样缺失很多,删除 zhaopin.drop([‘Specialty’,‘Language’],axis=1,inplace=True) –PositionAdvantage:缺失占比1364/7959=17.14%,选用众数中的第一个’五险一金’填充 zhaopin.PositionAdvantage.fillna(zhaopin.PositionAdvantage.mode()[0],inplace=True) –NNN:没有任何意义,直接删除 zhaopin.drop([“NNN”],axis=1,inplace=True) 最后,检查缺失值是否处理完毕 zhaopin.isnull().sum()JobTitle0CompanyName0CompanyNature0CompanySize0IndustryField0Salary0Workplace0Workyear0Education0RecruitNumbers0ReleaseTime0PositionAdvantage0dtype:int64 4.2数据加工 由于现有的数据不能满足我们的分析需求,因此需要对现有数据表进行分列,计算等等操作. 需要处理的特征有:Salary,Workplace 1.Salary 将薪资分为最高薪资和最低薪资,另外了解到薪资中单位有元/小时,元/天,万/月,万/年,千/月,统一将其转化为千/月 importre#将5种单元进行编号zhaopin[‘Standard’]=np.where(zhaopin.Salary.str.contains(‘元.?小时’),0,np.where(zhaopin.Salary.str.contains(‘元.?天’),1,np.where(zhaopin.Salary.str.contains(‘千.?月’),2,np.where(zhaopin.Salary.str.contains(‘万.?月’),3,4))))#用’-‘将Salary分割为LowSalary和HighSalarySalarySplit=zhaopin.Salary.str.split(’-‘,expand=True)zhaopin[‘LowSalary’],zhaopin[‘HighSalary’]=SalarySplit[0],SalarySplit[1]#Salary中包含’以上’,‘以下’或者两者都不包含的进行编号zhaopin[‘HighOrLow’]=np.where(zhaopin.LowSalary.str.contains(‘以.?下’),0,np.where(zhaopin.LowSalary.str.contains(‘以.?上’),2,1))#匹配LowSalary中的数字,并转为浮点型Lower=zhaopin.LowSalary.apply(lambdax:re.search(‘(\d+.?\d*)’,x).group(1)).astype(float)#对LowSalary中HighOrLow为1的部分进行单位换算,全部转为’千/月’zhaopin.LowSalary=np.where(((zhaopin.Standard==0)&(zhaopin.HighOrLow==1)),Lower*8*21⁄1000,np.where(((zhaopin.Standard==1)&(zhaopin.HighOrLow==1)),Lower*21⁄1000,np.where(((zhaopin.Standard==2)&(zhaopin.HighOrLow==1)),Lower,np.where(((zhaopin.Standard==3)&(zhaopin.HighOrLow==1)),Lower*10,np.where(((zhaopin.Standard==4)&(zhaopin.HighOrLow==1)),Lower/1210,Lower)))))#对HighSalary中的缺失值进行填充,可以有效避免匹配出错.zhaopin.HighSalary.fillna(‘0千/月’,inplace=True)#匹配HighSalary中的数字,并转为浮点型Higher=zhaopin.HighSalary.apply(lambdax:re.search(‘(\d+.?\d).*?’,str(x)).group(1)).astype(float)#对HighSalary中HighOrLow为1的部分完成单位换算,全部转为’千/月’zhaopin.HighSalary=np.where(((zhaopin.Standard==0)&(zhaopin.HighOrLow==1)),zhaopin.LowSalary/21*26,np.where(((zhaopin.Standard==1)&(zhaopin.HighOrLow==1)),zhaopin.LowSalary/21*26,np.where(((zhaopin.Standard==2)&(zhaopin.HighOrLow==1)),Higher,np.where(((zhaopin.Standard==3)&(zhaopin.HighOrLow==1)),Higher*10,np.where(((zhaopin.Standard==4)&(zhaopin.HighOrLow==1)),Higher/12*10,np.where(zhaopin.HighOrLow==0,zhaopin.LowSalary,zhaopin.LowSalary))))))#查看当HighOrLow为0时,Standard都有哪些,输出为2,4zhaopin[zhaopin.HighOrLow==0].Standard.unique()#完成HighOrLow为0时的单位换算zhaopin.loc[(zhaopin.HighOrLow==0)&(zhaopin.Standard==2),‘LowSalary’]=zhaopin[(zhaopin.HighOrLow==0)&(zhaopin.Standard==2)].HighSalary.apply(lambdax:0.8*x)zhaopin.loc[(zhaopin.HighOrLow==0)&(zhaopin.Standard==4),‘HighSalary’]=zhaopin[(zhaopin.HighOrLow==0)&(zhaopin.Standard==4)].HighSalary.apply(lambdax:x/12*10)zhaopin.loc[(zhaopin.HighOrLow==0)&(zhaopin.Standard==4),‘LowSalary’]=zhaopin[(zhaopin.HighOrLow==0)&(zhaopin.Standard==4)].HighSalary.apply(lambdax:0.8*x)#查看当HighOrLow为2时,Srandard有哪些,输出为4zhaopin[zhaopin.HighOrLow==2].Standard.unique()#完成HighOrLow为2时的单位换算zhaopin.loc[zhaopin.HighOrLow==2,‘LowSalary’]=zhaopin[zhaopin.HighOrLow==2].HighSalary.apply(lambdax:x/12*10)zhaopin.loc[zhaopin.HighOrLow==2,‘HighSalary’]=zhaopin[zhaopin.HighOrLow==2].LowSalary.apply(lambdax:1.2*x)zhaopin.LowSalary,zhaopin.HighSalary=zhaopin.LowSalary.apply(lambdax:‘%.1f’%x),zhaopin.HighSalary.apply(lambdax:‘%.1f’%x) 2.Workplace 对工作地区进行统一 #查看工作地有哪些zhaopin.Workplace.unique()#查看工作地点名字中包括省的有哪些,结果显示全部为xx省,且其中不会出现市级地区名zhaopin[zhaopin.Workplace.str.contains(‘省’)].Workplace.unique()#将地区统一到市级zhaopin[‘Workplace’]=zhaopin.Workplace.str.split(‘-’,expand=True)[0] 3.删除重复多余信息 zhaopin.drop([‘Salary’,‘Standard’,‘HighOrLow’],axis=1,inplace=True) 到目前为止,我们对数据处理完成了,接下来就是分析了. 5.可视化分析 5.1企业类型 importmatplotlibimportmatplotlib.pyplotaspltCompanyNature_Count=zhaopin.CompanyNature.value_counts()#设置中文字体font={‘family’:‘SimHei’}matplotlib.rc(‘font’,
可以看出招聘中主要以民营企业,合资企业和上市公司为主.
5.2企业规模
CompanySize_Count=zhaopin.CompanySize.value_counts()index,bar_width=np.arange(len(CompanySize_Count)),0.6fig=plt.figure(figsize=(8,6))plt.barh(index(-1)+bar_width,CompanySize_Count,tick_label=CompanySize_Count.index,height=bar_width)#添加数据标签forx,yinenumerate(CompanySize_Count):plt.text(y+0.1,x(-1)+bar_width,‘%s’%y,va=‘center’)plt.title(‘数据分析岗位各公司规模总数分布条形图’,fontsize=24)
招聘数据分析岗位的公司规模主要以50-500人为主
5.3地区
frompyechartsimportGeofromcollectionsimportCounter#统计各地区出现次数,并转换为元组的形式data=Counter(place).most_common()#生成地理坐标图geo=Geo(“数据分析岗位各地区需求量”,title_color=“#fff”,title_pos=“center”,width=1200,height=600,background_color=‘#404a59’)attr,value=geo.cast(data)#添加数据点geo.add(“,attr,value,visual_range=[0,100],visual_text_color=‘#fff’,symbol_size=5,is_visualmap=True,is_piecewise=True)geo.show_config()geo.render()
可以看出北上广深等经济相对发达的地区,对于数据分析岗位的需求量大.
参考自:https://blog.csdn.net/qq_41841569/article/details/82811153?utm_source=blogxgwz1
5.4学历和工作经验
fig,ax=plt.subplots(1,2,figsize=(18,8))Education_Count=zhaopin.Education.value_counts()Workyear_Count=zhaopin.Workyear.value_counts()patches,l_text,p_text=ax[0].pie(Education_Count,autopct=‘%.2f%%’,labels=Education_Count.index)m=-0.01fortinl_text[6:]:t.set_y(m)m+=0.1print(t)forpinp_text[6:]:p.set_y(m)m+=0.1ax[0].set_title(‘数据分析岗位各学历要求所占比例’,fontsize=24)index,bar_width=np.arange(len(Workyear_Count)),0.6ax[1].barh(index*(-1)+bar_width,Workyear_Count,tick_label=Workyear_Count.index,height=bar_width)ax[1].set_title(‘数据分析岗位工作经验要求’,fontsize=24)
学历要求多以本科,大专为主,工作经验要求中无工作经验要求为主,可见招聘主要面向的是应届毕业生.
5.4薪资水平
1.薪资与岗位需求关系
fig=plt.figure(figsize=(9,7))#转换类型为浮点型zhaopin.LowSalary,zhaopin.HighSalary=zhaopin.LowSalary.astype(float),zhaopin.HighSalary.astype(float)#分别求各地区平均最高薪资,平均最低薪资Salary=zhaopin.groupby(‘Workplace’,as_index=False)[‘LowSalary’,‘HighSalary’].mean()#分别求各地区的数据分析岗位数量,并降序排列Workplace=zhaopin.groupby(‘Workplace’,as_index=False)[‘JobTitle’].count().sort_values(‘JobTitle’,ascending=False)#合并数据表Workplace=pd.merge(Workplace,Salary,how=‘left’,on=‘Workplace’)#用前20名进行绘图Workplace=Workplace.head(20)plt.bar(Workplace.Workplace,Workplace.JobTitle,width=0.8,alpha=0.8)plt.plot(Workplace.Workplace,Workplace.HighSalary*1000,‘–’,color=‘g’,alpha=0.9,label=‘平均最高薪资’)plt.plot(Workplace.Workplace,Workplace.LowSalary*1000,‘-.’,color=‘r’,alpha=0.9,label=‘平均最低薪资’)#添加数据标签forx,yinenumerate(Workplace.HighSalary*1000):plt.text(x,y,‘%.0f’%y,ha=‘left’,va=‘bottom’)forx,yinenumerate(Workplace.LowSalary*1000):plt.text(x,y,‘%.0f’%y,ha=‘right’,va=‘bottom’)forx,yinenumerate(Workplace.JobTitle):plt.text(x,y,‘%s’%y,ha=‘center’,va=‘bottom’)plt.legend()plt.title(‘数据分析岗位需求量排名前20地区的薪资水平状况’,fontsize=20)
可以看出,随着需求量的减少,薪资水平也有所降低.
2.薪资与经验关系
#求出各工作经验对应的平均最高与平均最低薪资Salary_Year=zhaopin.groupby(‘Workyear’,as_index=False)[‘LowSalary’,‘HighSalary’].mean()#求平均薪资Salary_Year[‘Salary’]=(Salary_Year.LowSalary.add(Salary_Year.HighSalary)).div(2)#转换列,得到想要的顺序Salary_Year.loc[0],Salary_Year.loc[6]=Salary_Year.loc[6],Salary_Year.loc[0]#绘制条形图plt.barh(Salary_Year.Workyear,Salary_Year.Salary,height=0.6)forx,yinenumerate(Salary_Year.Salary):plt.text(y+0.1,x,‘%.2f’%y,va=‘center’)plt.title(‘各工作经验对应的平均薪资水平(单位:千/月)’,fontsize=20)
工作经验越丰富,薪资越高.
3.薪资与学历关系
#计算平均薪资Salary_Education=zhaopin.groupby(‘Education’,as_index=False)[‘LowSalary’,‘HighSalary’].mean()Salary_Education[‘Salary’]=Salary_Education.LowSalary.add(Salary_Education.HighSalary).div(2)Salary_Education=Salary_Education.sort_values(‘Salary’,ascending=True)#绘制柱形图plt.bar(Salary_Education.Education,Salary_Education.Salary,width=0.6)forx,yinenumerate(Salary_Education.Salary):plt.text(x,y,‘%.2f’%y,ha=‘center’,va=‘bottom’)plt.title(‘各学历对应的平均工资水平(单位:千/月)’,fontsize=20)
学历越高,对应的薪资水平越高
总结1.数据分析岗位中企业类型以民营企业,合资企业和上市公司为主,企业规模多为50-500人.
2.数据分析岗位的学历要求以本科,大专为主,经验中无工作经验占多数,可见主要面向的是应届毕业生.
3.北上广深杭等经济相对发达的地区对数据分析岗位的需求量大,且薪资水平较高于其他地区;学历越高,经验越丰富对应的薪资水平也会增高.
作者:Star_Zhao,若侵删。