數(shù)據(jù)分析行業(yè)薪資的秘密,你想知道的都在這里(2)
接上篇:數(shù)據(jù)分析行業(yè)薪資的秘密,你想知道的都在這里(1)
第二部分:職位信息清洗及數(shù)據(jù)提取
數(shù)據(jù)分析師的收入怎么樣?哪些因素對(duì)于數(shù)據(jù)分析的薪資影響***?哪些行業(yè)對(duì)數(shù)據(jù)分析人才的需求量***?我想跳槽,應(yīng)該選擇大公司大平臺(tái)還是初創(chuàng)的小公司?按我目前的教育程度,工作經(jīng)驗(yàn),和掌握的工具和技能,能獲得什么樣水平的薪資呢?
我們使用python抓取了2017年6月26日拉鉤網(wǎng)站內(nèi)搜索“數(shù)據(jù)分析”關(guān)鍵詞下的450條職位信息。通過對(duì)這些職位信息的分析和建模來給你答案。
本系列文章共分為五個(gè)部分,分別是數(shù)據(jù)分析職位信息抓取,數(shù)據(jù)清洗及預(yù)處理,數(shù)據(jù)分析職位分布分析,數(shù)據(jù)分析薪資影響因素分析,以及數(shù)據(jù)建模和薪資預(yù)測。這是第二篇:職位信息清洗及數(shù)據(jù)提取。
第二篇文章是對(duì)獲取的數(shù)據(jù)進(jìn)行清洗,預(yù)處理和特征提取。在***篇文章中我們抓取了拉勾網(wǎng)的450條職位信息及職位描述。但這些信息無法直接用于數(shù)據(jù)分析,我們需要對(duì)抓取到的信息進(jìn)行清洗,規(guī)范現(xiàn)有數(shù)據(jù)的格式,提取信息中的數(shù)據(jù)及特征,為后續(xù)的數(shù)據(jù)分析和建模做準(zhǔn)備。下面開始介紹苦逼的
數(shù)據(jù)清洗流程介紹。
數(shù)據(jù)清洗前的準(zhǔn)備工作
首先是開始前的準(zhǔn)備工作,導(dǎo)入所需要的庫文件,包括常用的numpy和pandas庫用于計(jì)算平均薪資以及對(duì)字符進(jìn)行分列等操作,正則表達(dá)式re庫用于字符的查找和替換操作,結(jié)巴分詞庫jieba用于對(duì)職位描述進(jìn)行分詞操作,自然語言處理nltk庫用于計(jì)算職位描述的文字豐富度指標(biāo),還有KMeans用于對(duì)平均
薪資進(jìn)行聚類操作。
- #導(dǎo)入所需庫文件
- import re
- import numpy as np
- import pandas as pd
- import jieba as jb
- import jieba.analyse
- import jieba.posseg as pseg
- import nltk
- from sklearn import preprocessing
- from sklearn.cluster import KMeans
導(dǎo)入我們之前抓取并保存的數(shù)據(jù)表,并查看數(shù)據(jù)表的維度以及各字段名稱。后面我們會(huì)經(jīng)常使用這些字段名稱。
- #導(dǎo)入之前抓取并保存的數(shù)據(jù)表
- lagou=pd.DataFrame(pd.read_csv('lagou_data_analysis_2017-06-26.csv',header=0,encoding='GBK'))
- #查看數(shù)據(jù)表維度及字段名稱
- lagou.columns,lagou.shape
職位信息清洗及預(yù)處理
開始對(duì)職位信息的各個(gè)字段進(jìn)行清洗和預(yù)處理,主要清洗的內(nèi)容包括文本信息提取和處理,內(nèi)容搜索和替換,字段內(nèi)的空格處理,數(shù)值信息提取和計(jì)算,英文字母統(tǒng)一大小寫等等。我們將先展示清洗前的原始字段,然后在展示清洗后的新字段內(nèi)容。
行業(yè)字段清洗及處理
***個(gè)清洗的字段是行業(yè)字段,抓取到的行業(yè)字段比較混亂,有些只有一個(gè)行業(yè)名稱,有些則有兩級(jí)的行業(yè)名稱。我們保留行業(yè)字段***部分的信息,對(duì)有兩部分行業(yè)名稱的字段取前一個(gè)。
- #查看原始industryField字段信息
- lagou[['industryField']].head()
由于行業(yè)名稱之間有的以頓號(hào)分割,有的以逗號(hào)分割,我們先將所有的分隔符統(tǒng)一為逗號(hào),然后對(duì)這個(gè)字段進(jìn)行分列。并將分列后的字段重新拼接回原數(shù)據(jù)表中。
- #對(duì)industryField字段進(jìn)行清洗及分列
- #創(chuàng)建list存儲(chǔ)清洗后的行業(yè)字段
- industry=[]
- #將頓號(hào)分隔符替換為逗號(hào)
- for x in lagou['industryField']:
- c=x.replace("、", ",")
- industry.append(c)
- #替換后的行業(yè)數(shù)據(jù)改為Dataframe格式
- industry=pd.DataFrame(industry,columns=["industry"])
- #對(duì)行業(yè)數(shù)據(jù)進(jìn)行分列
- industry_s=pd.DataFrame((x.split(',') for x in industry["industry"]),index=industry["industry"].index,columns=['industry_1','industry_2'])
- #將分列后的行業(yè)信息匹配回原數(shù)據(jù)表
- lagou=pd.merge(lagou,industry_s,right_index=True, left_index=True)
- #清除字段兩側(cè)空格
- lagou["industry_1"]=lagou["industry_1"].map(str.strip)
以下是清洗后的行業(yè)字段。
- #查看清洗后的行業(yè)字段
- lagou[["industry_1","industry_2"]].head()
融資階段字段清洗及處理
第二個(gè)清洗的字段是融資階段字段,抓取下來的原始信息中對(duì)融資階段進(jìn)行了雙重標(biāo)識(shí),例如成長型(A輪)。由于***個(gè)標(biāo)識(shí)”成長型”定義比較寬泛,我們提取第二個(gè)括號(hào)中的標(biāo)識(shí)。
- #查看清洗前的financeStage字段
- lagou[['financeStage']].head()
首先建立一個(gè)字典,將數(shù)據(jù)表中融資階段的每一條信息與字典中的Key進(jìn)行查找。如果融資階段信息中包含字典中的任何一個(gè)key,我們就把這個(gè)key對(duì)應(yīng)的value記錄下來。
- #提取并處理financeStage中的融資信息
- #創(chuàng)建一個(gè)字典
- f_dict = {'未融資':'未融資',
- '天使輪':'天使輪',
- 'A輪':'A輪',
- 'B輪':'B輪',
- 'C輪':'C輪',
- 'D輪':'D輪',
- '不需要':'不需要融資',
- '上市公司':'上市公司'
- }
- #創(chuàng)建list存儲(chǔ)清洗后的信息
- financeStage2=[]
- #逐一提取financeStage字段中的每一條信息
- for i in range(len(lagou['financeStage'])):
- #逐一提取字典中的每一條信息
- for (key, value) in f_dict.items():
- #判斷financeStage字段中是否包含字典中的任意一個(gè)key
- if key in lagou['financeStage'][i]:
- #如何包含某個(gè)key,則把對(duì)應(yīng)的value保存在list中
- financeStage2.append(value)
- #把新保存的list添加到原數(shù)據(jù)表中
- lagou["financeStage1"]=financeStage2
- #查看清洗后的financeStage字段
- lagou[["financeStage1"]].head()
職位名稱字段清洗及處理
第三個(gè)清洗的字段是職位名稱,這里我們要提取職位里的title信息。沒有title信息的都統(tǒng)一歸為其他。具體方法是將每個(gè)職位名稱與現(xiàn)有的title列表逐一判斷,如果職位名稱中含有title關(guān)鍵字就被劃分到這個(gè)類別下。否則被歸為其他類。
- #查看清洗前的positionName字段
- lagou[['positionName']].head()
- #提取并處理positionName中的職位信息
- #創(chuàng)建list存儲(chǔ)清洗后的信息
- positionName3=[]
- #對(duì)職位名稱進(jìn)行判斷歸類
- for i in range(len(lagou['positionName'])):
- if '實(shí)習(xí)' in lagou['positionName'][i]:
- positionName3.append("實(shí)習(xí)")
- elif '助理' in lagou['positionName'][i]:
- positionName3.append("助理")
- elif '專員' in lagou['positionName'][i]:
- positionName3.append("專員")
- elif '主管' in lagou['positionName'][i]:
- positionName3.append("主管")
- elif '經(jīng)理' in lagou['positionName'][i]:
- positionName3.append("經(jīng)理")
- elif '專家' in lagou['positionName'][i]:
- positionName3.append("專家")
- elif '總監(jiān)' in lagou['positionName'][i]:
- positionName3.append("總監(jiān)")
- elif '工程師' in lagou['positionName'][i]:
- positionName3.append("工程師")
- else:
- #以上關(guān)鍵詞都不包含的職位歸為其他
- positionName3.append("其他")
- #把新保存的list添加到原數(shù)據(jù)表中
- lagou["positionName1"]=positionName3
- #查看清洗后的positionName字段
- lagou[["positionName1"]].head()
薪資范圍字段清洗及處理
第四個(gè)清洗的字段是薪資范圍。抓取到的數(shù)據(jù)中薪資范圍是一個(gè)區(qū)間值,比較分散,無法直接使用。我們對(duì)薪資范圍進(jìn)行清洗,去掉無關(guān)的信息并只保留薪資上限和下限兩個(gè)數(shù)字,然后使用這兩個(gè)數(shù)字計(jì)算出平均薪資值。
- #查看清洗前的salary字段
- lagou[['salary']].head()
- #提取并計(jì)算平均薪資
- #創(chuàng)建list用于存儲(chǔ)信息
- salary1=[]
- #對(duì)salary字段進(jìn)行清洗
- for i in lagou['salary']:
- #設(shè)置要替換的正則表達(dá)式k|K
- p = re.compile("k|K")
- #按正則表達(dá)式對(duì)salary字段逐條進(jìn)行替換(替換為空)
- salary_date = p.sub("", i)
- #完成替換的信息添加到前面創(chuàng)建的新list中
- salary1.append(salary_date)
- #將清洗后的字段合并到原數(shù)據(jù)表中
- lagou['salary1']=salary1
- #對(duì)薪資范圍字段進(jìn)行分列
- salary_s=pd.DataFrame((x.split('-') for x in lagou['salary1']),index=lagou['salary1'].index,columns=['s_salary1','e_salary1'])
- #更改字段格式
- salary_s['s_salary1']=salary_s['s_salary1'].astype(int)
- #更改字段格式
- salary_s['e_salary1']=salary_s['e_salary1'].astype(int)
- #計(jì)算平均薪資
- #創(chuàng)建list用于存儲(chǔ)平均薪資
- salary_avg=[]
- #逐一提取薪資范圍字段
- for i in range(len(salary_s)):
- #對(duì)每一條信息字段計(jì)算平均薪資,并添加到平均薪資list中。
- salary_avg.append((salary_s['s_salary1'][i] + salary_s['e_salary1'][i])/2)
- #將平均薪資拼接到薪資表中
- salary_s['salary_avg']=salary_avg
- #將薪資表與原數(shù)據(jù)表進(jìn)行拼接
- lagou=pd.merge(lagou,salary_s,right_index=True, left_index=True)
- #查看清洗以后的salary_avg字段
- lagou[["salary_avg"]].head()
職位信息中的數(shù)據(jù)提取
在職位描述字段中,包含了非常詳細(xì)和豐富的信息。比如數(shù)據(jù)分析人才的能力要求和對(duì)各種數(shù)據(jù)分析工具的掌握程度等。我們對(duì)這個(gè)字段的一些特征進(jìn)行指標(biāo)化,對(duì)有價(jià)值的信息進(jìn)行提取和統(tǒng)計(jì)。
職位描述字段中的數(shù)據(jù)提取
第五個(gè)清洗的字段是職位描述,準(zhǔn)確的說從職位描述字段中提取信息。職位描述中包含了大量關(guān)于職位信息,工作內(nèi)容,和個(gè)人能力方面的信息,非常有價(jià)值。但無法直接拿來使用。需要進(jìn)行信息提取。我們將對(duì)職位描述字段進(jìn)行三方面的信息提取。
***是提取職位描述中對(duì)于個(gè)人能力的要求,換句話說就是數(shù)據(jù)分析人員使用工具的能力。我們整理了10個(gè)最常見的數(shù)據(jù)分析工具。來看下每個(gè)職位描述中都出行了哪些工具名稱。由于一些工具間存在可替代性,所以每個(gè)職位描述中可能會(huì)出現(xiàn)多個(gè)工具的名稱。沒出現(xiàn)一個(gè)工具名稱,我們就會(huì)在相應(yīng)的工具下表示1,如果沒有出現(xiàn)則標(biāo)識(shí)為0。
- #查看清洗以前的job_detail字段
- lagou[['job_detail']].head()
- #提取職位描述字段,并對(duì)英文統(tǒng)一轉(zhuǎn)化為小寫
- lagou['job_detail']=lagou['job_detail'].map(str.lower)
- #提取職位描述中的工具名稱
- tools=['sql','python','excel','spss','matlab','sas','r','hadoop','spark','tableau']
- #創(chuàng)建list用于存儲(chǔ)數(shù)據(jù)
- tool=np.array([[0 for i in range(len(tools))] for j in range(len((lagou['job_detail'])))])
- #逐一提取職位描述信息
- for i in range(len(lagou['job_detail'])):
- #逐一提取工具名稱
- for t in tools:
- #獲得工具名稱的索引位置(第幾個(gè)工具)
- index=tools.index(t)
- #判斷工具名稱是否出現(xiàn)在職位描述中
- if t in lagou['job_detail'][i]:
- #如果出現(xiàn),在該工具索引位置(列)填1
- tool[i][index]=1
- else:
- #否則在該工具索引位置(列)填0
- tool[i][index]=0
- #將獲得的數(shù)據(jù)轉(zhuǎn)換為Dataframe格式
- analytics_tools=pd.DataFrame(tool,columns=tools)
- #按行(axis=1)對(duì)每個(gè)職位描述中出現(xiàn)的工具數(shù)量進(jìn)行求和
- tool_num=analytics_tools.sum(axis=1)
- #將工具數(shù)量求和拼接到原數(shù)據(jù)表中
- analytics_tools["tool_num"]=tool_num
- #將表與原數(shù)據(jù)表進(jìn)行拼接
- lagou=pd.merge(lagou,analytics_tools,right_index=True, left_index=True)
- #查看從job_detail中提取的分析工具信息
- lagou[['sql','python','excel','spss','matlab','sas','r','hadoop','spark','tableau','tool_num']].head()
職位描述所使用的字?jǐn)?shù)統(tǒng)計(jì)
第二是計(jì)算職位描述所使用的字?jǐn)?shù),我們猜測初級(jí)簡單的工作描述會(huì)比較簡單,而高級(jí)復(fù)雜的工作描述則會(huì)更復(fù)雜一些。因此職位描述中不同的字?jǐn)?shù)里也可能隱藏著某種信息或關(guān)聯(lián)。
- #計(jì)算職位描述的字?jǐn)?shù)
- #創(chuàng)建list用于存儲(chǔ)新數(shù)據(jù)
- jd_num=[]
- #逐一提取職位描述信息
- for i in range(len(lagou['job_detail'])):
- #轉(zhuǎn)換數(shù)據(jù)格式(list轉(zhuǎn)換為str)
- word_str = ''.join(lagou['job_detail'][i])
- #對(duì)文本進(jìn)行分詞
- word_split = jb.cut(word_str)
- #使用|分割結(jié)果并轉(zhuǎn)換格式
- word_split1 = "| ".join(word_split)
- #設(shè)置字符匹配正則表達(dá)式
- pattern=re.compile('\w')
- #查找分詞后文本中的所有字符并賦值給word_w
- word_w=pattern.findall(word_split1)
- #計(jì)算word_w中字符數(shù)量并添加到list中
- jd_num.append(len(word_w))
- #對(duì)字符數(shù)量進(jìn)行歸一化
- min_max_scaler = preprocessing.MinMaxScaler()
- min_max_jd_num = min_max_scaler.fit_transform(jd_num)
- #將歸一化的數(shù)據(jù)添加到原數(shù)據(jù)表中
- lagou['jd_num']=min_max_jd_num
- #查看職位描述字?jǐn)?shù)
- jd_num[:10]
- #查看歸一化的職位描述字段
- lagou[['jd_num']].head()
職位描述的詞匯豐富度統(tǒng)計(jì)
第三是計(jì)算職位描述中的文字豐富度指標(biāo)。和前面的字?jǐn)?shù)統(tǒng)計(jì)一樣。初級(jí)職位所對(duì)應(yīng)的工作會(huì)相對(duì)簡單,在描述上也會(huì)比較簡單。高級(jí)職位則可能需要更詳細(xì)的和負(fù)責(zé)的描述。因此文字豐富度指標(biāo)上也會(huì)更高一些。
- #計(jì)算職位描述文字豐富度
- #創(chuàng)建新list用于存儲(chǔ)數(shù)據(jù)
- diversity=[]
- #逐一提取職位描述信息
- for i in range(len(lagou['job_detail'])):
- #轉(zhuǎn)換數(shù)據(jù)格式(list轉(zhuǎn)換為str)
- word_str = ''.join(lagou['job_detail'][i])
- #將文本中的英文統(tǒng)一轉(zhuǎn)化為小寫
- word_str=word_str.lower()
- #查找職位描述中的所有中文字符
- word_list=re.findall(r'[\u4e00-\u9fa5]', word_str)
- #轉(zhuǎn)換數(shù)據(jù)格式(list轉(zhuǎn)換為str)
- word_str1=''.join(word_list)
- #對(duì)文本進(jìn)行分詞
- word_split = jb.cut(word_str1)
- #使用空格分割結(jié)果并轉(zhuǎn)換格式
- word_split1 = " ".join(word_split)
- #使用nltk對(duì)句子進(jìn)行分詞
- tokens = nltk.word_tokenize(word_split1)
- #轉(zhuǎn)化為text對(duì)象
- text = nltk.Text(tokens)
- #計(jì)算職位描述的文字豐富度(唯一詞/所有詞)
- word_diversity=len(set(text)) / len(text)
- #將文本詞匯豐富度數(shù)據(jù)添加到list中
- diversity.append(word_diversity)
- #將文字豐富度匹配到原數(shù)據(jù)表中
- lagou["diversity"]=diversity
- #查看職位描述豐富度字段
- lagou[["diversity"]].head()
對(duì)數(shù)據(jù)分析的薪資進(jìn)行聚類
完成清洗和數(shù)據(jù)提取后,平均薪資已經(jīng)比薪資范圍要具體的多了,但仍然比較離散。我們對(duì)這些平均薪資進(jìn)行聚類來支持后面的建模和預(yù)測工作。以下是具體的代碼和聚類結(jié)果。我們將類別標(biāo)簽添加到原始數(shù)據(jù)表中。
- #提取平均工作年限,平均薪資和平均公司規(guī)模字段
- salary_type = np.array(lagou[['salary_avg']])
- #進(jìn)行聚類分析
- clf=KMeans(n_clusters=3)
- #訓(xùn)練模型
- clf=clf.fit(salary_type)
- #將距離結(jié)果標(biāo)簽合并到原數(shù)據(jù)表中
- lagou['cluster_label']= clf.labels_
- #輸出聚類結(jié)果
- clf.cluster_centers_
聚類后平均薪資被分為三個(gè)類別,第1類是薪資均值為19.3K的區(qū)間,分類標(biāo)記為0。第二類是薪資均值為8.2K的區(qū)間,分類標(biāo)記為1,。第三類是薪資均值為32.1的區(qū)間,分類標(biāo)記為3。
- #對(duì)平均薪資進(jìn)行聚類預(yù)測
- clf.predict(9),clf.predict(25),clf.predict(30)
- #查看數(shù)據(jù)表中的類別標(biāo)識(shí)字段
- lagou[['salary_avg','cluster_label']].head()
查看清洗及處理后的數(shù)據(jù)表
到這里我們完成了對(duì)450個(gè)職位信息的字段清洗和數(shù)據(jù)提取工作。下面我們再來查看下數(shù)據(jù)表的維度,名稱以及數(shù)據(jù)表中的數(shù)據(jù)。在下一篇文章中我們將使用這個(gè)數(shù)據(jù)表對(duì)數(shù)據(jù)分析職位的分布情況以及薪資的影響因素進(jìn)行分析,并通過建模對(duì)薪資收入進(jìn)行預(yù)測。
- #查看數(shù)據(jù)表維度及字段名稱
- lagou.columns,lagou.shape
- #查看清洗完的數(shù)據(jù)表
- lagou.head()
本篇文章我們對(duì)抓取到的職位信息進(jìn)行了清洗和數(shù)據(jù)提取。數(shù)據(jù)清洗是一個(gè)苦逼的工作,但卻是分析和建模過程中必不可少的一個(gè)步驟。經(jīng)過清洗后我們就可以對(duì)職位數(shù)據(jù)進(jìn)行分析和建模了,后面的文章中我們將從職位需求分布和薪資影響因素兩個(gè)方面進(jìn)行分析,并在***對(duì)數(shù)據(jù)分析行業(yè)的薪資進(jìn)行建模,對(duì)薪資分類和具體的薪資值進(jìn)行預(yù)測。請繼續(xù)關(guān)注。