智聯Python相關職位的數據分析及可視化-Pandas&Matplotlib篇

上一篇,我用了Excel對爬蟲採集到的智聯招聘數據進行了數據分析及可視化,用到軟體是Excel, 這一篇,我們打算完全用Python來做同樣的事。用到的庫有Pandas、Matplotlib。np、pd、plt分別是numpy、pandas、matplotlib.pyplot的常用縮寫。

Numpy(Numerical Python的簡稱)是Python科學計算的基礎包。它提供了以下功能:

  1. 快速高效的多維數組對象ndarray。
  2. 用於對數組執行元素級計算以及直接對數組執行數學運算的函數。
  3. 用於讀寫硬碟上基於數組的數據集的工具。
  4. 線性代數運算、傅里葉變換,以及隨機數生成。
  5. 用於將C、C++、Fortran代碼集成到Python的工具。

除了為Python提供快速的數組處理能力,Numpy在數據分析方面還有另外一個主要作用,即作為在演算法之間傳遞數據的容器。對於數值型數據,Numpy數組在存儲和處理數據時要比內置的Python數據結構高效的多。此外,由低級語言(比如C和Fortran)編寫的庫可以直接操作Numpy數組中的數據,無需進行任何數據複製工作。

Pandas這個名字本身源於panel data(面板數據,這是計量經濟學中關於多維結構化數據集的一個術語)以及Python data analysis。pandas提供了使我們能夠快速便捷地處理結構化數據的大量數據結構和函數。Pandas中用的最多的是DataFrame,它是一個面向列的二維表結構,且含有行標和列標。pandas兼具numpy高性能的數組計算功能以及電子表格和關係型資料庫(如SQL)靈活的數據處理功能。它提供了複雜精細的索引功能,以便更為便捷地完成重塑、切片和切塊、聚合以及選取數據子集等操作。

Matplotlib是Python中常用的可視化繪圖庫,可以通過簡單的幾行代碼生成直方圖,功率譜,條形圖,錯誤圖,散點圖等。Seaborn、ggplot、等諸多Python可視化庫均是在此基礎上開發的,所以學會matplotlib的基礎操作還是很有必要的!它和Ipython結合的很好,提供了一種非常好用的互動式數據繪圖環境。繪製的圖表也是互動式的,你可以利用繪圖窗口中的工具欄放大圖表中的某個區域或對整個圖表進行平移瀏覽。

數據來源:

Python爬蟲爬取了智聯招聘關鍵詞:【Python】、全國30個主要城市的搜索結果,總職位條數:18326條(行),其中包括【職位月薪】、【公司鏈接】、【工作地點】、 【崗位職責描述】等14個欄位列,和一個索引列【ZL_Job_id】共計15列。數據存儲在本地MySql伺服器上,從伺服器上導出json格式的文件,再用Python進行數據讀取分析和可視化。

數據簡單清洗:

1.首先在終端中打開輸入ipython --pylab。在Ipython的shell界面里導入常用的包numpy、pandas、matplotlib.pyplot。用pandas的read_json()方法讀取json文件,並轉化為用df命名的DataFrame格式文件。(DataFrame格式是Pandas中非常常用且重要的一種數據存儲格式、類似於Mysql和Excel中的表。)

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltdf = pd.read_json("/Users/zhaoluyang/Desktop/Python_全國JSON.json")#查看df的信息df.info()df.columns

可以看到讀取的df格式文件共有15列,18326行,pandas默認分配了索引值從0~18325。還有一點值得注意的:全部的15列都有18326個非空值,因為當初寫爬蟲代碼時設置了, 如果是空值,譬如:有一條招聘信息其中【福利標籤】空著沒寫,那麼就用字元串代替,如「found no element」。

2.讀取JSON文件時pandas默認分配了從0開始的索引,由於文件"ZL_Job_id"列中自帶索引,故將其替換!替換後,用sort_index()給索引重新排列。

df.index = df["ZL_Job_id"]#索引列用"ZL_Job_id"列替換。del(df["ZL_Job_id"])#刪除原文件中"ZL_Job_id"列。df_sort = df.sort_index()#給索引列重新排序。df = df_sortdf[["工作地點","職位月薪"]].head(10)

3.下面,將進行【職位月薪】列的分列操作,新增三列【bottom】、【top】、【average】分別存放最低月薪、最高月薪和平均月薪。 其中try語句執行的是絕大多數情況:職位月薪格式如:8000-10000元/月,為此需要對【職位月薪】列用正則表達式逐個處理,並存放至三個新列中。 處理後bottom = 8000,top = 10000,average = 9000. 其中不同語句用於處理不同的情況,譬如【職位月薪】=『面議』、『found no element』等。對於字元形式的『面議』、『found no element』 處理後保持原字元不變,即bottom = top = average = 職位月薪。

q1,q2,q3,q4用來統計各個語句執行次數.其中q1統計職位月薪形如『6000-8000元/月』的次數;q2統計形如月收入『10000元/月以下』;q3代表其他情況如『found no element』,『面議』的次數;q4統計失敗的特殊情況。

import redf["bottom"] = df["top"] = df["average"] = df["職位月薪"]pattern = re.compile("([0-9]+)")q1=q2=q3=q4=0for i in range(len(df["職位月薪"])): item = df["職位月薪"].iloc[i].strip() result = re.findall(pattern,item) try: if result: try: #此語句執行成功則表示result[0],result[1]都存在,即職位月薪形如『6000-8000元/月』 df["bottom"].iloc[i],df["top"].iloc[i] = result[0],result[1] df["average"].iloc[i] = str((int(result[0])+int(result[1]))/2) q1+=1 except: #此語句執行成功則表示result[0]存在,result[1]不存在,職位月薪形如『10000元/月以下』 df["bottom"].iloc[i] = df["top"].iloc[i] = result[0] df["average"].iloc[i] = str((int(result[0])+int(result[0]))/2) q2+=1 else: #此語句執行成功則表示【職位月薪】中並無數字形式存在,可能是『面議』、『found no element』 df["bottom"].iloc[i] = df["top"].iloc[i] = df["average"].iloc[i] = item q3+=1 except Exception as e: q4+=1 print(q4,item,repr(e))for i in range(100):#測試一下看看職位月薪和bottom、top是否對的上號 print(df.iloc[i][["職位月薪","bottom","top","average"]])#或者df[["職位月薪","bottom","top","average"]].iloc[i]也可df[["職位月薪","bottom","top","average"]].head(10)

經過檢查,可以發現【職位月薪】和新增的bottom、top、average列是能對的上。其中形如『6000-8000元/月』的有16905條、形如『10000元以下』的 有61條、"found no element"和"面議"加起來有1360條,總數18326條,可見是正確的。

4.進行【工作地點】列的處理,新增【工作城市】列,將工作地點中如『蘇州-姑蘇區』、『蘇州-工業園區』等統統轉化為『蘇州』存放在【工作城市】列。

df["工作城市"] = df["工作地點"]pattern2 = re.compile("(.*?)(-)")df_city = df["工作地點"].copy()for i in range(len(df_city)): item = df_city.iloc[i].strip() result = re.search(pattern2,item) if result: print(result.group(1).strip()) df_city.iloc[i] = result.group(1).strip() else: print(item.strip()) df_city.iloc[i] = item.strip()df["工作城市"] = df_citydf[["工作地點","工作城市"]].head(20)

檢查一下,沒有錯誤,可以進行下一步的操作了!

數據分析和可視化

從可讀性來看,應該是先進行數據清洗,然後進行分析及可視化,但是實際過程中,往往是交織在一起的, 所有下面讓我們一步步來,完成所有的清洗、分析和可視化工作。除了具體的公司和職位名稱以外,我們還比較關心幾個關鍵詞: 平均月薪、工作經驗、工作城市、最低學歷和崗位職責描述,這裡崗位職責描述以後會用python分詞做詞雲圖,所以目前篩選出 【平均月薪】、【工作經驗】、【工作城市】、【最低學歷】這四個標籤,這些標籤可以兩兩組合產生各種數據。譬如我想知道各個城市的招聘數量分布情況, 會不會大部分的工作機會都集中在北上廣深?是不是北上廣深的平均工資也高於其他城市?我想知道Python這個關鍵詞的18000多條招聘數據中 對學歷的要求和對工作經驗的要求,以及它們分別佔比多少?我還想知道平均月薪和工作經驗的關係?最低學歷和平均月薪的關係? 和上一篇(Execel篇)類似,不同的是,這次我們完全用Python實現同樣的操作。

1.各個城市職位數量及分布

根據猜想,北上廣深,一定佔據了Python這個關鍵詞下大部分的工作機會,會不會符合28定律?20%的城市佔據了80%的崗位? 有可能!我們先用df.工作城市.value_counts()看一下究竟有多少個城市,以及他們各自有多少條工作數據?

df.工作城市.value_counts()#等價於df["工作城市"].value_counts()#再用count()來看一下統計出來的城市數量df.工作城市.value_counts().count()type(df.工作城市.value_counts())#用type()查看下類型。

可以看到,明明設置的是搜索30個城市,怎麼變成了40?像延邊、琿春、白山。。。。是什麼鬼?想了一下,這些城市是搜索關鍵詞城市『吉林市』時,自動冒出來的;還有95個『found no element』,是這些職位鏈接本身就沒有填寫工作城市,為了避免干擾,要把他們統統替換成空值。用df_工作城市 = df["工作城市"].replace()

#將原來df["工作城市"]列中選定的欄位替換成空值nandf_工作城市 = df["工作城市"].replace(["found no element","松原","遼源","琿春","白山","公主嶺","白城","延邊","四平","通化"],np.nan)#查看替換後各個城市職位計數df_工作城市.value_counts()#查看替換後城市所包含的職位總數;查看替換後的城市數量,是否等於30.df_工作城市#將新的[df_工作城市]列添加到df表中,留作備用df["df_工作城市"] = df_工作城市

看了一下,沒有問題,現在df_工作城市中篩選出了30個城市,合計18211條職位數據。 為了數據完整性,df表保持原樣,我們用df_工作城市直接操作,進行下一步的可視化。先直接上代碼和圖,再一一解釋下。

fig1 = plt.figure(1,facecolor = "black")#設置視圖畫布1ax1 = fig1.add_subplot(2,1,1,facecolor="#4f4f4f",alpha=0.3)#在視圖1中設置子圖1,背景色灰色,透明度0.3(figure.add_subplot 和plt.suplot都行)plt.tick_params(colors="white")#設置軸的顏色為白色df_工作城市.value_counts().plot(kind="bar",rot=0,color="#ef9d9a")#畫直方圖圖#設置圖標題,x和y軸標題title = plt.title("城市——職位數分布圖",fontsize=18,color="yellow")#設置標題xlabel = plt.xlabel("城市",fontsize=14,color="yellow")#設置X軸軸標題ylabel = plt.ylabel("職位數量",fontsize=14,color="yellow")#設置Y軸軸標題#設置說明,位置在圖的右上角text1 = ax1.text(25,4500,"城市總數:30(個)",fontsize=12, color="cyan")#設置說明,位置在圖的右上角text2 = ax1.text(25,4000,"職位總數:18326(條)",fontsize=12, color="cyan")text3 = ax1.text(25,3500,"有效職位:18211(條)",fontsize=12, color="red")#添加每一個城市的坐標值for i in range(len(list_1)): ax1.text(i-0.3,list_1[i],str(list_1[i]),color="yellow")#可以用plt.grid(True)添加柵格線#可以用下面語句添加註釋箭頭。指向上海,xy為坐標值、xytext為注釋坐標值,facecolor為箭頭顏色。#arrow = plt.annotate("職位數:3107", xy=(1,3107), xytext=(3, 4000),color="blue",arrowprops=dict(facecolor="blue", shrink=0.05))ax2 = fig1.add_subplot(2,1,2)#設置子圖2,是位於子圖1下面的餅狀圖#為了方便,顯示前8個城市的城市名稱和比例、其餘的不顯示,用空字元列表替代,為此需要構造列表label_list和一個空字元列表[""]*23。x = df_工作城市.value_counts().values#x是數值列表,pie圖的比例根據數值佔整體的比例而劃分label_list = []#label_list是構造的列表,裝的是前8個城市的名稱+職位佔比。for i in range(8): t = df_工作城市.value_counts().values[i]/df_工作城市.value_counts().sum()*100 city = df_工作城市.value_counts().index[i] percent = str("%.1f%%"%t) label_list.append(city+percent)#labels參數原本是與數值對應的標籤列表,此處30個城市過多,所以只取了前8個城市顯示。#explode即餅圖中分裂的效果explode=(0.1,1,1,。。)表示第一塊圖片顯示為分裂效果labels = label_list + [""]*22explode = tuple([0.1]+[0]*29)plt.pie(x,explode=explode,labels=labels,textprops={"color":"yellow"})#可加參數autopct="%1.1f%%"來顯示餅圖中每一塊的比例,但是此處30個城市,如果全顯示的話會非常擁擠不美觀,所以只能手動通過labels參數來構造。#若要顯示標準圓形,可以添加:plt.axis("equal")

可以看見,這個曲線下降的弧度還是挺美的,北上深杭廣5個城市佔據了超過60%以上的職位數。其中北京當之無愧的佔據了四分之一的Python工作數量,不愧為帝都。 上海以3107條職位排名第二,可見上海雖然經濟超越北京,在互聯網環境和工作機遇方面還需努力!深圳作為中國的科技中心,排名第三我是沒疑問的,杭州竟然超過廣州排名第四!不過也可以想到,阿里巴巴、百草味等等電商產業帶動了整個杭州的互聯網文化!

【北上深杭廣】+成都、南京、鄭州,這8個城市佔據了全國30座城市中,近80%的工作機會!剩下的22個城市合起來只佔據了20%,果然,是基本符合28定律的。。。

2.工作經驗-職位數量及分布

Python雖然是一名比較老的語言,但是在人們的印象中火起來也就最近幾年,Python相關的工作對於【工作經驗】是怎樣要求的呢?讓我們來看看!

df.工作經驗.value_counts()#統計【工作經驗】下各個欄位的累計和

可以看見出現了一些很數字少量的欄位譬如「5年以上」,「2年以上」,「1-2年」,「1年以上」等,這些標籤下職位的數量都在10以內,不太具備統計意義,所以我們作圖的時候不想讓他們出現,必須篩選掉。 下面我們還是通過同樣的步驟來清除掉此類數據。

df_工作經驗 = df["工作經驗"].replace(["found no element","3年以上","1年以上","5年以上","2年以上","1-2年"],np.nan)df_工作經驗.value_counts()df_工作經驗.value_counts().sum()

現在,可以進行下一步可視化了,還是做2張圖:直方圖和餅圖。通過這兩張圖可以直觀地看到這麼多職位中對不同工作經驗的要求佔比,好做到心裡有數!

fig2 = plt.figure(2,facecolor = "black")ax2_1 = fig2.add_subplot(2,1,1,facecolor="#4f4f4f",alpha=0.3)plt.tick_params(colors="white")df_工作經驗.value_counts().plot(kind = "bar",rot = 0,color="#7fc8ff")title = plt.title("工作經驗——職位數分布圖",fontsize = 18,color = "yellow")xlabel = plt.xlabel("工作經驗",fontsize = 14,color = "yellow")ylabel = plt.ylabel("職位數量",fontsize = 14,color = "yellow")plt.grid(True)text1_ = ax2_1.text(5,5600,"城市總數:30(個)",fontsize=12, color="yellow")text2 = ax2_1.text(5,4850,"職位總數:18326(條)",fontsize=12, color="yellow")text3 = ax2_1.text(5,4100,"有效職位:18215(條)",fontsize=12, color="cyan") #設置子圖2,是位於子圖1下面的餅狀圖ax2_2 = fig2.add_subplot(2,1,2)#x是數值列表,pie圖的比例根據數值佔整體的比例而劃分x2 = df_工作經驗.value_counts().valueslabels = list(df_工作經驗.value_counts().index[:5])+ [""]*2explode = tuple([0.1,0.1,0.1,0.1,0.1,0.1,0.1])plt.pie(x2,explode=explode,labels=labels,autopct="%1.1f%%",textprops={"color":"yellow"})plt.axis("equal")#顯示為等比例圓形#設置圖例,方位為右下角legend = ax2_2.legend(loc="lower right",shadow=True,fontsize=12,edgecolor="cyan")

總共得到18215條職位。從直方圖裡可以明顯看出工作機會集中在"不限"、"1-3年"、"3-5年", 其中工作經驗要求3年以下的(【無經驗】+【不限】+【1年以下】+【1-3年】)合計11501條職位,佔比超過63%,看來即使是初入門者,大家的機會也還是有不少的! (PS:最後,在df表中添加一列"df_工作經驗",以後篩選時就可以直接用了,df["df_工作經驗"]=df_工作經驗)

3.工作經驗-平均月薪

這個嘛,大家閉著眼都能想到!肯定是工作經驗越久的拿錢越多了!再猜猜?無經驗的和5-10年經驗的收入差距有多大?這個,嘿嘿就不好猜了,讓我們來看看吧!

1.第一步,要想統計工作經驗和平均月薪的關係,那麼我們先看看df中對應的列df.工作經驗和df.average。之前我們構造了一列df_工作經驗,把df.工作經驗中幾個樣本容量小於10的值和『found no element』全篩選掉了,故df_工作經驗還能繼續使用。現在,讓我們看看df.average的信息。

df.average.value_counts()

可以看到,其中有1265個值是『面議』,有95個值是『found no element』,這些值需要替換成空值,不然會影響下一步工資的計算。

df_平均月薪 = df["average"].replace(["面議","found no element"],np.nan)

2.好了,第一步的簡單數據清洗完成了,我們可以思考下一步了,現在我們想要得到的是不同工作經驗欄位下的平均月薪

A. 首先我需要把df_工作經驗和df_平均月薪這兩列元素放在一起,構造一個DataFrame用於存放df_工作經驗和df_平均月薪這兩列元素,且方便進一步的groupby操作。

B. 其次我需要把df_平均月薪列根據df_工作經驗進行分組(用groupby),分組後我可以求得df_工作經驗下各個欄位的月薪的計數、最大值最小值、累加和、平均值等一系列數據。

C. 當然此處我只需要平均值。對分組後的grouped用mean()方法,就可以輕鬆統計分組內各項的平均值了。

df3=pd.DataFrame(data={"工作經驗":df["df_工作經驗"],"平均月薪":df_平均月薪})df3.info()grouped3 = df3["平均月薪"].groupby(df3["工作經驗"])grouped3.mean()

在進行grouped3.mean()時,我們發現報錯了:DataError: No numeric types to aggregate,看一下,原來df_平均月薪列里的值都是字元型str,並不是數值型的float,因為前面的步驟沒有做好,留下了這個bug,無奈我們需要對值類型做個轉換。

#構造一個listi存放轉化後float型的『平均月薪』import repattern = re.compile("([0-9]+)")listi = []for i in range(len(df.average)): item = df.average.iloc[i].strip() result = re.findall(pattern,item) try: if result: listi.append(float(result[0])) elif (item.strip()=="found no element" or item.strip()=="面議"): listi.append(np.nan) else: print(item) except Exception as e: print(item,type(item),repr(e))#將df3.平均月薪列替換掉,同時給df新增一列"df_平均月薪"做備用。df3["平均月薪"] = listidf["df_平均月薪"] = df3["平均月薪"]#看看更新後的數據是否正確df3["平均月薪"].value_counts()#統計每個月薪欄位的個數df3["平均月薪"][:10]#查看前10個值type(df3["平均月薪"][1])#看看現在月薪的類型是不是浮點型df3["平均月薪"].value_counts().sum()#看看月薪樣本總數df3["平均月薪"].mean()#看看這16966個月薪樣本的平均值是多少?

可以看到,替換後的df3["平均月薪"]值從str變為了可以計算的float,月薪樣本總數16966個,樣本的平均月薪14197元。好,現在終於OK了,讓我們再回到之前的步驟:

grouped3 = df3["平均月薪"].groupby(df3["工作經驗"])grouped3.mean()

好了,完美,格式對了,數據有了,現在可以來畫圖了!但是再看看,還不是那麼完美,數據大小排列很亂,而且小數點那麼多。。。好吧,讓我們再簡單處理下

#新增一個平均值,即所有非空df3["平均月薪"]的平均值s3 = pd.Series(data = {"平均值":df3["平均月薪"].mean()})result3 = grouped3.mean().append(s3)#sort_values()方法可以對值進行排序,默認按照升序,round(1)表示小數點後保留1位小數。result3.sort_values(ascending=False).round(1)

3.數據可視化

這次我們畫一個躺倒的柱狀圖(barh),用ggplot的風格來畫。

matplotlib.style.use("ggplot")fig3 = plt.figure(3,facecolor = "black")ax3 = fig3.add_subplot(1,1,1,facecolor="#4f4f4f",alpha=0.3)result3.sort_values(ascending=False).round(1).plot(kind="barh",rot=0)#設置標題、x軸、y軸的標籤文本title = plt.title("工作經驗——平均月薪分布圖",fontsize = 18,color = "yellow")xlabel= plt.xlabel("平均月薪",fontsize = 14,color = "yellow")ylabel = plt.ylabel("工作經驗",fontsize = 14,color = "yellow")#添加值標籤list3 = result3.sort_values(ascending=False).valuesfor i in range(len(list3)): ax3.text(list3[i],i,str(int(list3[i])),color="yellow")#設置標識箭頭arrow = plt.annotate("Python平均月薪:14197元/月", xy=(14197,3.25), xytext=(20000,4.05),color="yellow",fontsize=16,arrowprops=dict(facecolor="cyan", shrink=0.05))#設置圖例注釋(16966來源:df2["平均月薪"].value_counts().sum())text= ax3.text(27500,6.05,"月薪樣本數:16966(個)",fontsize=16, color="cyan")#設置軸刻度文字顏色為白色plt.tick_params(colors="white")

通過圖表,我們可以直觀地看到,Python關鍵詞下的職位月薪是隨著工作經驗增長而遞增的(這不是說了一句廢話么?!囧) 其中【無經驗】的平均月薪最低,只有5842,相比之下【10年以上】經驗的,平均月薪達到了恐怖的34890,約達到了【無經驗】月薪的6倍之多!!! 【1年以下】的平均月薪7579,還勉強湊合,【1-3年】的已經破萬了,達到了近12000元/月的水準。最後讓我們看看平均值吧,由於『被平均』的緣故,16966條月薪樣本的均值是14197元,有沒有讓你滿意呢?

4.工作城市-平均月薪

對了,剛才說到北上廣深佔據了全國大部分的工作機會,那麼北上廣深的平均月薪如何呢?會不會也碾壓小城市?讓我們來看看! 和之前的套路一樣,我們還是要構造一個DataFrame,包含兩列,一列是【平均月薪】,一列是【工作城市】,然後對df4進行groupby操作,還是很簡單的!不過,經過上次的教訓,平均月薪一定要是數值型的,str型的計算不了。

#此處df["df_工作城市"]是之前經過篩選後的30個城市數據df4=pd.DataFrame(data={"工作城市":df["df_工作城市"],"平均月薪":df["df_平均月薪"]})df4.info()grouped4 = df4["平均月薪"].groupby(df4["工作城市"])grouped4.mean()#查看對30個城市分組後,各個城市月薪的平均值grouped4.count().sum()#查看對30個城市分組後篩選出的平均月薪樣本數#新增一個平均值,即所有非空df2["平均月薪"]的平均值s4 = pd.Series(data = {"平均值":df["df_平均月薪"].mean()})result4 = grouped4.mean().append(s4)#sort_values()方法可以對值進行排序,默認按照升序,round(1)表示小數點後保留1位小數。result4.sort_values(ascending=False).round(1)

數據構造好了,進行下一步,可視化。

#可以通過style.available查看可用的繪圖風格,總有一款適合你matplotlib.style.use("dark_background")fig4 = plt.figure(4)ax4 = fig4.add_subplot(1,1,1)#可選facecolor="#4f4f4f",alpha=0.3,設置子圖,背景色灰色,透明度0.3result4.sort_values(ascending=False).round(1).plot(kind="bar",rot=30)#可選color="#ef9d9a"#設置圖標題,x和y軸標題title = plt.title(u"城市——平均月薪分布圖",fontsize=18,color="yellow")#設置標題xlabel = plt.xlabel(u"城市",fontsize=14,color="yellow")#設置X軸軸標題ylabel = plt.ylabel(u"平均月薪",fontsize=14,color="yellow")#設置Y軸軸標題#設置說明,位置在圖的右上角text1 = ax4.text(25,16250,u"城市總數:30(個)",fontsize=12, color="#FF00FF")#設置說明,位置在圖的右上角text2 = ax4.text(25,15100,u"月薪樣本數:16946(條)",fontsize=12, color="#FF00FF")#添加每一個城市的坐標值list_4 = result4.sort_values(ascending=False).valuesfor i in range(len(list_4)): ax4.text(i-0.5,list_4[i],int(list_4[i]),color="yellow")#設置箭頭注釋arrow = plt.annotate(u"全國月薪平均值:14197元/月", xy=(4.5,14197), xytext=(7,15000),color="#9B30FF",fontsize=14,arrowprops=dict(facecolor="#FF00FF", shrink=0.05))#設置軸刻度文字顏色為粉色plt.tick_params(colors="pink")

可以看見,Python這個關鍵詞下,全國16946條樣本的月薪平均值為14197元/月,平均月薪排名前5的城市分別是:北京、上海、深圳、杭州、廣州。哎,記得之前城市—職位數分布圖么?全國30個城市中,職位數排名前5 的也是這5座城市!看來北上廣深杭不僅集中了全國大部分的職位數量、連平均工資也是領跑全國的!不禁讓人覺得越大越強!但是在超級大城市奮鬥,買房總是遙遙無期,房子在中國人的概念里,有著特殊的情節,意味著家,老小妻兒生活的地方,給人一種安全感!我們可以看到還有不少城市的平均月薪也破萬了,在這些相對小點的城市中挑一個,工作安家,買房還是有希望的,哈哈!譬如南京、武漢、蘇州、大連、廈門都挺好的!

5.學歷-職位數量

直覺來看Python這類工作職位,應該是本科及以上經驗要求居多吧?那麼工作經驗【不限】和【大專】的機會佔比多少呢?讓我們來看看! 首先,還是用df["最低學歷"].value_counts()來看一下有哪些欄位,以及各個欄位的統計值。

df["最低學歷"].value_counts()df_最低學歷=df["最低學歷"].replace(["中技","其他","高中","found no element"],np.nan)df_最低學歷.value_counts()df_最低學歷.value_counts().sum()df["df_最低學歷"] = df_最低學歷 #留作備用

可以看到對於學歷要求,最多的集中在大專、本科、碩士、不限還有較少量的博士和中專學歷,至於中技、其他、高中則連10個都不到, 對於這些10個都不到的欄位,我們還是照舊用replace語句將其排除(並沒有歧視低學歷的意思啊囧!)

可以看到排除後還剩餘6個欄位,共計18119個職位,下一步,還是來經典的條形分布圖和餅圖!

fig5 = plt.figure(5)ax5_1 = fig5.add_subplot(2,1,1) #可選facecolor="#4f4f4f",alpha=0.3df_最低學歷.value_counts().plot(kind = "bar",rot=0) #color="#7fc8ff"#設置標題、x軸和y軸標題、圖例文字title = plt.title(u"最低學歷——職位數分布圖",fontsize = 18,color = "yellow")xlabel = plt.xlabel(u"最低學歷",fontsize = 14,color = "yellow")ylabel = plt.ylabel(u"職位數量",fontsize = 14,color = "yellow")text1 = ax5_1.text(4.4,8200,u"職位總數:18119(條)",fontsize=14, color="#B452CD")#設置坐標軸的的顏色和文字大小plt.tick_params(colors="#9F79EE",labelsize=13)#設置坐標值文字list5 = df_最低學歷.value_counts().valuesfor i in range(len(list5)): ax5_1.text(i-0.1,list5[i],int(list5[i]),color="yellow")ax5_2=fig5.add_subplot(2,1,2)xl = df_最低學歷.value_counts().valueslabels = list(df_最低學歷.value_counts().index)explode = tuple([0.1,0,0,0,0,0])plt.pie(xl,explode=explode,labels=labels,autopct="%1.1f%%",textprops={"color":"#B452CD"})plt.axis("equal")legend = ax5_2.legend(loc="lower right",shadow=True,fontsize=12,edgecolor="#B452CD")plt.tick_params(colors="#9F79EE",labelsize=13)

可見【本科】獨佔鰲頭,佔據了超過50%的市場!【不限】和【大專】也合計佔比38%不容小覷!看起來,只要技術過硬,學歷從來都不是問題!!!作為對比【碩士】佔比6%,【博士】更是少到只有1%,果然稀缺到百里挑一!

6.最低學歷-平均月薪

按道理學歷越高,平均月薪越高,類似工作經驗一樣都是正相關,到底是不是呢?來看一下!構造一個DataFrame(df6), 包含兩列最低學歷和平均月薪,我們直接用之前構造好的df中的【df_最低學歷】和【df_平均月薪】即可,然後還是熟悉的groupby(df_最低學歷)

df6=pd.DataFrame(data={"最低學歷":df["df_最低學歷"],"平均月薪":df["df_平均月薪"]})df6.info()grouped6 = df6["平均月薪"].groupby(df6["最低學歷"])#查看grouped6的信息grouped6.mean()grouped6.count()grouped6.count().sum()matplotlib.style.use("ggplot")fig6 = plt.figure(6,facecolor = "black")ax6 = fig6.add_subplot(1,1,1,facecolor="#4f4f4f",alpha=0.3)grouped6.mean().round(1).sort_values().plot(color = "cyan")#在條形圖上疊加一個折線圖grouped6.mean().round(1).sort_values().plot(kind="bar",rot=0)#設置標題、x軸、y軸的標籤文本title = plt.title(u"最低學歷——平均月薪分布圖",fontsize = 18,color = "yellow")xlabel= plt.xlabel(u"最低學歷",fontsize = 14,color = "yellow")ylabel = plt.ylabel(u"平均月薪",fontsize = 14,color = "yellow")#添加值標籤(坐標值文字)list6 = grouped6.mean().round(1).sort_values().valuesfor i in range(len(list6)): ax6.text(i-0.1,list6[i],int(list6[i]),color="yellow")#設置圖例注釋text= ax6.text(0,27000,u"月薪樣本數:16956(個)",fontsize=16, color="cyan")#設置軸刻度的文字顏色plt.tick_params(colors="#9F79EE")

平均月薪14139元,可以看到學歷越高果然工資越高,博士級別的更是碾壓,達到了29562元。只要學歷在【大專】以上,那麼平均月薪都已經過萬了。 BUT,重點來了,學歷並不是萬能的,一個【中專】學歷,有超過5年經驗的,工資一定超過【本科】畢業無工作經驗的。所以大家看看就好,不要當真,哈哈!

7.最低學歷-工作經驗-平均月薪

看了前面的圖表,大家都知道了,學歷越高平均月薪越高,工作經驗越高平均月薪越高,但是我想要看看更細粒度的情形呢? 譬如我想知道【大學+無經驗】和【大學+1-3年】工資的差別,我想看看【大專+3-5年】和【碩士+無經驗】工資的對比究竟誰高? 現在,我不知道,但是接下來讓我們把這些情況用圖表呈現出來,大家就會一目了然!

df7 = pd.DataFrame(data = {"平均月薪":df["df_平均月薪"],"最低學歷":df["df_最低學歷"],"工作經驗":df["df_工作經驗"]})df7.info()grouped7 = df7["平均月薪"].groupby([df7["最低學歷"],df7["工作經驗"]])#查看grouped7的信息grouped7.mean().round(1)grouped7.count()grouped7.count().sum()

其實我們輸入type(grouped7.mean()),會發現它是一個包含了層次化索引的Series結構。其中第一層索引是【最低學歷】 第二層索引是【工作經驗】,數值列【平均月薪】被這兩層索引所分配!下面我們開始準備可視化,還是畫一個bar柱狀圖,不過這次畫的是多列一起呈現的形式,Y軸表示職位月薪、X軸表示最低學歷,在每個學歷欄位下,又分別添加不同工作經驗的列!

grouped7.mean().round(1)[:,"1-3年"]grouped7.mean().round(1)[:,"1-3年"].sort_values()xlist = list(grouped7.mean().round(1)[:,"1-3年"].sort_values().index)grouped7.mean().round(1)[:,"1-3年"].reindex(xlist)print(xlist)

grouped7.mean()將會顯示各組的平均值,round(1)表示小數點保留1位。[:,"1-3年"]是對層次化索引的一種操作,表示選取 grouped7.mean()中索引名字為"工作經驗"下"1-3年欄位"的所有值。此處構造了列表xlist,值是篩選後的"最低學歷"索引, xlist將用於畫條形圖時X軸坐標的標籤文本(表示最低學歷),Y軸相對應的是平均月薪。工作經驗則用條形圖和圖例展示。

#開始畫圖,設置基本參數matplotlib.style.use("dark_background")fig7 = plt.figure(7,facecolor = "black")ax7 = fig7.add_subplot(1,1,1,facecolor="#4f4f4f",alpha=0.3)title = plt.title(u"最低學歷-工作經驗-平均月薪分布圖",fontsize = 18,color = "yellow")xlabel = plt.xlabel(u"最低學歷",fontsize = 14,color = "yellow")ylabel = plt.ylabel(u"平均月薪",fontsize = 14,color = "yellow")plt.tick_params(colors="cyan")#ylist1~7分別是7種條形圖的Y值列表ylist1 = grouped7.mean().round(1)[:,"無經驗"].reindex(xlist).valuesylist2 = grouped7.mean().round(1)[:,"1年以下"].reindex(xlist).valuesylist3 = grouped7.mean().round(1)[:,"不限"].reindex(xlist).valuesylist4 = grouped7.mean().round(1)[:,"1-3年"].reindex(xlist).valuesylist5 = grouped7.mean().round(1)[:,"3-5年"].reindex(xlist).valuesylist6 = grouped7.mean().round(1)[:,"5-10年"].reindex(xlist).valuesylist7 = grouped7.mean().round(1)[:,"10年以上"].reindex(xlist).values#img1~img7分別表示7種條形圖ind = np.arange(6)#ind為x軸寬度,用numpy的array形式表示width = 0.1#條形圖的寬度,要合理設置否則太寬會擺不下img1 = ax7.bar(ind,ylist1,width)img2 = ax7.bar(ind+width,ylist2,width)img3 = ax7.bar(ind+width*2,ylist3,width)img4 = ax7.bar(ind+width*3,ylist4,width)img5 = ax7.bar(ind+width*4,ylist5,width)img6 = ax7.bar(ind+width*5,ylist6,width)img7 = ax7.bar(ind+width*6,ylist7,width)#設置X軸文本和位置調整ax7.set_xticklabels(xlist)ax7.set_xticks(ind + width / 2)#設置文字說明text1 = ax7.text(4.05,52100,u"數據來源:智聯招聘",fontsize=13, color="#9F79EE")text2 = ax7.text(4.05,50200,u"職位關鍵詞:Python",fontsize=13, color="#9F79EE")text3 = ax7.text(4.05,48200,u"工作城市:全國30座城市",fontsize=13, color="#9F79EE")text4 = ax7.text(4.05,46200,u"職位數量:共計16956(條)",fontsize=13, color="#9F79EE")#設置圖例ax7.legend((img1[0],img2[0],img3[0],img4[0],img5[0],img6[0],img7[0]), (u"無經驗",u"1年以下",u"不限",u"1-3年",u"3-5年",u"5-10年",u"10年以上"),fontsize=13,facecolor="black")#設置柵格plt.grid(True)

最後,上一張簡單詞雲圖給大家看看,用的BDP傻瓜式製作,看看就好!

其實展開了還可以分析的東西有不少,譬如Pandas、Matplotlib的用法,譬如更多維度的分析和兩兩組合! 好了,整體的先暫時分析到這,總結一下呢就是:Python+工作經驗+學歷+大城市 = 高薪!但是,工作經驗、學歷和城市其實並沒那麼重要, 關鍵要看自己的Python用的6不6,關鍵在於你知道自己想做什麼,知道自己能做什麼,知道自己做出了什麼!哈哈,當你知道越來越接近這些問題的答案呢,那麼我相信,薪水對你來說已經不那麼重要了!(當然,高薪是必須有的!) 人生苦短,我用Python!

推薦閱讀:

用R語言高效下載圖片
R語言可視化——圖表嵌套(母子圖)
Python 數據可視化?
R語言之數據可視化
有趣!如何用Python-matplotlib繪製雙層餅圖及環形圖?

TAG:Python | Matplotlib | 数据可视化 |