点击跳转到总目录 点击跳转到爬虫部分
说在前面
项目背景
随着科技的飞速发展,数据呈现爆发式的增长,任何人都摆脱不了与数据打交道,社会对于“数据分析”方面的人才需求也在不断增大。因此了解当下企业究竟需要招聘什么样的数据分析人才?需要什么样的技能?不管是对于在校生,还是对于求职者来说,都显得很有必要 本项目基于这个问题,从猎聘网 爬取了全国范围内数据分析岗位的招聘信息。通过八象限法分析了数据分析岗位薪资,学历,工作年限之间的关系。
交叉分析法
交叉分析法又称立体分析法,是在纵向分析法和横向分析法的基础上,从交叉、立体的角度出发,由浅入深、由低级到高级的一种分析方法。这种方法虽然复杂,但它弥补了“各自为政”分析方法所带来的偏差。
八象限法
交叉分析法的具体体现形式十分复杂,常见的有交叉表法、四象限法、八象限法等。这里我们只关注八象限法。八象限法就是通过数据中心点把数据空间分割成8个部分,然后根据坐标的业务意义给空间的每个区域赋予相应业务意义的过程。 八象限法的关键是抽象出三个可评价指标,这三个评价指标应该围绕我们要解决的问题。 在我的项目中,我希望通过三个指标对工作按职位最基本要求和薪资高低进行分类。其具体流程如下: 1.抽象出三个关键评判指标。 2.建立三坐标系统,每个坐标对应一个评判指标。 3.计算三个指标值组成的所有数据点的中心点。 4.把数据点以及它们的中心点绘制在坐标系统中。 5.从中心点出发平行坐标轴绘制三条相互垂直的直线,从而把坐标系分割成八个象限。 6.根据坐标轴的实际业务意义给每个区域命名。 7.选择所需区域并筛选该区域所含的数据点。
八象限法的经典应用-RFM法
RFM分析法的本质是八象限法,是根据美国数据库营销研究所Arthur Hughes的研究,客户数据库中有3个神奇的要素,这3个要素构成了数据分析的最好的指标。它们分别是最近一次消费 (Recency)、消费频率 (Frequency)、消费金额 (Monetary)。 一般来讲,最近一次消费时间离观测窗口结束日期越近的顾客应该是越有价值的顾客,对提供的即时商品或服务也就越有可能有反应。 消费频率是顾客在限定的期间内(观测窗口内)购买产品的次数。购买次数越高的顾客,通常是满意度越高的顾客,也是最有价值、忠诚度最高的顾客。 与消费频率类似,消费金额是顾客在限定的期间内(观测窗口内)的消费金额。 同样,消费金额越高,客户价值越高。 根据这三个参数可以将用户划分为重要挽留客户、重要发展客户、重要保持客户、重要价值客户、一般挽留客户、一般发展客户、一般保持客户、一般价值客户8种类型。然后根据每个种类的客户所表现的行为以及类名所示要达到的目标进行针对性运营
明确目的
干数据分析这行工资咋样?—全国数据分析平均年薪和各市平均年薪 哪个城市需要的人最多?—全国岗位数量排名前10的城市 学历高低与岗位数量的关系 工作年限与岗位数量的关系 学习并使用八象限法分析数据分析岗位薪资,学历,工作年限之间的关系
初始化环境
引入数据分析python库
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib. pyplot as plt
import squarify
from mpl_toolkits. mplot3d import Axes3D
plt. rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
plt. rcParams[ 'axes.unicode_minus' ] = False
print ( np. __version__)
print ( pd. __version__)
print ( mpl. __version__)
设置绘图中文支持
% matplotlib inline
mpl. rcParams[ "font.family" ] = "SimHei"
mpl. rcParams[ "axes.unicode_minus" ] = False
plt. rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
% config InlineBackend. figure_format = 'svg'
排除警告
import warnings
warnings. filterwarnings( "ignore" )
读取数据
liepin = pd. read_excel( "21猎聘.xlsx" , usecols= [ 0 , 1 , 3 , 4 , 5 , 6 , 7 ] , encoding= "utf-8" , sep= "\t" )
data_work = liepin. copy( )
data_work. info( )
data_work. describe( )
数据的预处理
缺失值处理
重复项检查
data_work. duplicated( ) . any ( )
data_work. drop_duplicates( inplace= True )
data_work. duplicated( ) . any ( )
数据重新定序
数据的数值化
data_work. head( 2 )
薪资
对于’薪资’列,我们通过正则化匹配出薪资的最低值和最高值,然后最高值和最低值相加除2求出平均值并乘以月份:面议全部赋值为-1 此环节爬虫爬取时已经处理 薪资异常值处理
data_work = data_work[ data_work[ "年薪" ] < 400000 ]
data_work. info( )
data_work = data_work[ data_work[ "年薪" ] > 0 ]
data_work. info( )
学历要求
对于’学历要求’列,我们可以根据学历从低到高的原则把该列转化为1-4之间数值组成的数值列。 不限1;中专2;大专3;本科4;硕士5;博士5;mba5;
xueli = dict ( data_work[ "学历要求" ] . value_counts( ) )
print ( xueli, len ( xueli) , type ( xueli) , type ( list ( data_work[ "学历要求" ] ) ) )
print ( sorted ( xueli) )
for item, values in zip ( sorted ( set ( data_work[ '学历要求' ] ) ) , [ 4 , 2 , 4 , 2 , 2 , 1 , 3 , 3 , 4 , 3 ] ) :
data_work. loc[ data_work. iloc[ : , 5 ] == item, '学历要求' ] = values
data_work. head( 5 )
工作年限
对于’工作年限’列,我们可以把经验不限1;一年以下1;1-3年2;3年以上3;3-5年3;5-10年4;10年以上4;99年以上4;
nian = dict ( data_work[ "工作年限" ] . value_counts( ) )
print ( nian, len ( nian) , type ( nian) , type ( list ( data_work[ "工作年限" ] ) ) )
print ( sorted ( nian) )
for years, valuesy in zip ( sorted ( set ( data_work[ '工作年限' ] ) ) , [ 2 , 4 , 3 , 3 , 4 , 4 , 1 , 1 ] ) :
data_work. loc[ data_work. iloc[ : , 6 ] == years, '工作年限' ] = valuesy
data_work. head( 10 )
经过处理后的数据
data_work. info( )
data_work. describe( )
八象限法分析
八象限法
八象限法的关键是抽象出三个可评价指标,这三个评价指标应该围绕我们要解决的问题。 在我的项目中,我希望通过三个指标对工作按职位最基本要求和薪资高低进行分类。其具体流程如下: 1.抽象出三个关键评判指标。 2.建立三坐标系统,每个坐标对应一个评判指标。 3.计算三个指标值组成的所有数据点的中心点。 4.把数据点以及它们的中心点绘制在坐标系统中。 5.从中心点出发平行坐标轴绘制三条相互垂直的直线,从而把坐标系分割成八个象限。 6.根据坐标轴的实际业务意义给每个区域命名。 7.选择所需区域并筛选该区域所含的数据点。
a = data_work[ "年薪" ] . mean( )
b = data_work[ "学历要求" ] . mean( )
c = data_work[ "工作年限" ] . mean( )
d = data_work[ "年薪" ] . median( )
print ( "年薪:" , a, d, "学历要求" , b, "工作年限" , c)
import turtle as t
def plot_dsw ( data, delta, color, categories_nr) :
x, y, z, dx, dy, dz = ( 0 , 0 , 0 , categories_nr+ delta, categories_nr+ delta, data. iloc[ : , 3 ] . max ( ) + delta* 10000 )
b = categories_nr/ 2 + 0.5
fig = plt. figure( figsize= ( 6.8 , 5.3 ) , dpi= 180 )
ax = Axes3D( fig)
xc = np. arange( - 1 , dx+ 1 , 0.01 )
yc = b * np. ones( len ( xc) )
zc = 140994.3 * np. ones( len ( xc) )
ax. plot( xc, yc, zc, color= '#191970' )
yc1 = np. arange( - 1 , dy+ 1 , 0.01 )
xc1 = b * np. ones( len ( yc1) )
zc1 = 140994.3 * np. ones( len ( yc1) )
ax. plot( xc1, yc1, zc1, color= '#191970' )
zc2 = np. arange( - 1 , dz+ 10000 , 100 )
yc2 = b * np. ones( len ( zc2) )
xc2 = b * np. ones( len ( zc2) )
ax. plot( xc2, yc2, zc2, color= '#191970' )
xx = [ x, x, x+ dx, x+ dx, x]
yy = [ y, y+ dy, y+ dy, y, y]
kwargs = { 'color' : color}
ax. plot3D( xx, yy, [ z] * 5 , ** kwargs)
ax. plot3D( xx, yy, [ z+ dz] * 5 , ** kwargs)
ax. plot3D( [ x, x] , [ y, y] , [ z, z+ dz] , ** kwargs)
ax. plot3D( [ x, x] , [ y+ dy, y+ dy] , [ z, z+ dz] , ** kwargs)
ax. plot3D( [ x+ dx, x+ dx] , [ y+ dy, y+ dy] , [ z, z+ dz] , ** kwargs)
ax. plot3D( [ x+ dx, x+ dx] , [ y, y] , [ z, z+ dz] , ** kwargs)
Y_p1 = np. arange( 0 , 5 , 0.01 )
X_p1 = 2.5 * np. ones( len ( Y_p1) )
X, Y = np. meshgrid( X_p1, Y_p1)
Z_p1 = np. linspace( 0 , data. iloc[ : , 3 ] . max ( ) , 500 )
Z = np. meshgrid( Z_p1, Z_p1) [ 0 ]
ax. plot_surface( X, Y, Z, alpha= 0.45 , color= 'gray' )
X_p2 = np. arange( 0 , 5 , 0.01 )
Y_p2 = 2.5 * np. ones( len ( X_p2) )
X1, Y1 = np. meshgrid( Y_p2, X_p2)
Z_p2 = np. linspace( 0 , data. iloc[ : , 3 ] . max ( ) , 500 )
Z1 = np. meshgrid( Z_p2, Z_p2) [ 0 ]
ax. plot_surface( Y1, X1, Z1, alpha= 0.35 , color= 'gray' )
X_p2 = np. arange( 0 , 5 , 0.01 )
Z_p2 = 140994.3 * np. ones( len ( X_p2) )
X1, Y1 = np. meshgrid( X_p2, X_p2)
Z1 = np. meshgrid( Z_p2, Z_p2) [ 0 ]
ax. plot_surface( Y1, X1, Z1, alpha= 0.36 , color= 'gray' )
ax. set_xlim( 0 , dx)
ax. set_ylim( 0 , dy)
ax. set_zlim( 0 , dz)
ax. text( 3.8 , 3.8 , 350000 , '高学历高年限高薪资\n-Zone1' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 3.5 , 3.9 , 80000 , '高学历高年限低薪资\n-Zone5' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 4 , - 1 , 190000 , '高学历低年限低薪资\n-Zone8' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 3.5 , .5 , 400000 , '高学历低年限高薪资\n-Zone4' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 0.8 , 3 , 400000 , '低学历高年限高薪资\n-Zone2' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 0 , 3.6 , 100000 , '低学历高年限低薪资\n-Zone6' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 0.5 , 0.6 , 350000 , '低学历低年限高薪资\n-Zone3' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. text( 0.1 , 0.6 , 100000 , '低学历低年限低薪资\n-Zone7' , ( 1 , 1 , 135000 ) , color= 'r' , alpha= 1 )
ax. scatter( data[ '学历要求' ] , data[ '工作年限' ] , data[ '年薪' ] , color= '#FF00FF' )
ax. set_xlabel( '学历要求' , color= 'b' , fontsize= 13 )
ax. set_ylabel( '工作年限' , color= 'b' , fontsize= 13 )
ax. set_zlabel( '年薪' , color= 'b' , fontsize= 13 )
ax. set_title( '数据分析-工作类别分布图' , fontsize= 16 )
plot_dsw( data_work, 1 , '#0000FF' , 4 )
各种工作类别成员筛选
def filter_categories ( data_info, center, zone) :
if zone == 1 :
data_zone1 = data_info. loc[ ( data_info. iloc[ : , 5 ] > center[ 0 ] ) & ( data_info. iloc[ : , 3 ] > center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] > center[ 2 ] ) , '公司全名' ]
return data_zone1
elif zone == 2 :
data_zone2 = data_info. loc[ ( data_info. iloc[ : , 5 ] <= center[ 0 ] ) & ( data_info. iloc[ : , 3 ] > center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] > center[ 2 ] ) , '公司全名' ]
return data_zone2
elif zone == 3 :
data_zone3 = data_info. loc[ ( data_info. iloc[ : , 5 ] <= center[ 0 ] ) & ( data_info. iloc[ : , 3 ] > center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] <= center[ 2 ] ) , '公司全名' ]
return data_zone3
elif zone == 4 :
data_zone4 = data_info. loc[ ( data_info. iloc[ : , 5 ] > center[ 0 ] ) & ( data_info. iloc[ : , 3 ] > center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] <= center[ 2 ] ) , '公司全名' ]
return data_zone4
elif zone == 5 :
data_zone5 = data_info. loc[ ( data_info. iloc[ : , 5 ] > center[ 0 ] ) & ( data_info. iloc[ : , 3 ] <= center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] > center[ 2 ] ) , '公司全名' ]
return data_zone5
elif zone == 6 :
data_zone6 = data_info. loc[ ( data_info. iloc[ : , 5 ] <= center[ 0 ] ) & ( data_info. iloc[ : , 3 ] <= center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] > center[ 2 ] ) , '公司全名' ]
return data_zone6
elif zone == 7 :
data_zone7 = data_info. loc[ ( data_info. iloc[ : , 5 ] <= center[ 0 ] ) & ( data_info. iloc[ : , 3 ] <= center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] <= center[ 2 ] ) , '公司全名' ]
return data_zone7
elif zone == 8 :
data_zone8 = data_info. loc[ ( data_info. iloc[ : , 5 ] > center[ 0 ] ) & ( data_info. iloc[ : , 3 ] <= center[ 1 ] ) \
& ( data_info. iloc[ : , 6 ] <= center[ 2 ] ) , '公司全名' ]
return data_zone8
x = [ ]
for y in range ( 1 , 9 ) :
z = ( filter_categories( data_work, ( 2.5 , 140994.3 , 2.5 ) , y) . shape[ 0 ] )
x. append( z)
print ( x, len ( x) , type ( x) )
可视化展示
柱形图
plt. figure( figsize = ( 500 , 200 ) )
xx = np. array( [ "高学高年高薪1" , "低学高年高薪2" , "低学低年高薪3" , "高学低年高薪4" , "'高学高年低薪5" , "低学高年低薪6" , "低学低年低薪7" , "高学低年低薪8" ] )
yy = np. array( x)
a = xx
b = yy
plt. bar( a, b, width= 0.5 , align= "center" , label= "岗位个数" )
plt. title( "各象限岗位数分布" , loc= "center" )
for ab, cd in zip ( a, b) :
plt. text( ab, cd, cd, ha= "center" , va = "bottom" , fontsize= 12 )
plt. xlabel( '各象限名' )
plt. xticks( rotation= 90 )
plt. ylabel( '岗位数' )
plt. legend( )
饼图
plt. subplot( 1 , 1 , 1 )
xxx = [ "高学高年高薪1" , "低学高年高薪2" , "低学低年高薪3" , "高学低年高薪4" , "'高学高年低薪5" , "低学高年低薪6" , "低学低年低薪7" , "高学低年低薪8" ]
explode = [ 0.1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]
labeldistance = 1.1
plt. pie( yy, labels = xxx, autopct = '%.0f%%' , shadow = True , explode = explode, radius = 1.0 , labeldistance = labeldistance)
plt. title( "各象限岗位数分布" , loc= "center" )
树地图
import squarify
size = np. array( [ 1846 , 848 , 359 , 625 , 1047 , 1063 , 1804 , 1620 ] )
fenlei = np. array( [ "高学高年高薪1" , "低学高年高薪2" , "低学低年高薪3" , "高学低年高薪4" , "'高学高年低薪5" , "低学高年低薪6" , "低学低年低薪7" , "高学低年低薪8" ] )
rate = np. array( [ "20%" , "9%" , "4%" , "7%" , "11%" , "12%" , "20%" , "18" ] )
colors = [ 'steelblue' , '#9999ff' , 'red' , 'indianred' , 'green' , 'yellow' , 'orange' ]
plot = squarify. plot( sizes = size, label = fenlei, color = colors, value = rate, edgecolor = 'white' , linewidth = 3 )
plt. title( '各象限岗位数分布' , fontdict = { 'fontsize' : 12 } )
plt. axis( 'off' )
plt. tick_params( top = 'off' , right = 'off' )
数据可视化
城市和区分开
cheng = [ ]
qu = [ ]
for di in data_work[ "工作地点" ] . astype( str ) . values:
if "-" in di:
shu = di. find( "-" )
cheng. append( di[ : shu] )
qu. append( di[ shu+ 1 : ] )
else :
cheng. append( di)
qu. append( 0 )
print ( len ( cheng) , len ( qu) )
data_work. insert( 7 , "城市" , cheng)
data_work. insert( 8 , "区" , qu)
data_work. info( )
data_work. head( 10 )
全国数据分析平均年薪和各市平均年薪
找出平均年限top10城市
city = dict ( data_work[ "城市" ] . value_counts( ) )
city2 = [ ]
number = [ 344 , 337 , 330 , 326 , 301 , 299 , 298 , 279 , 278 , 271 , 266 , 245 , 240 , 227 , 212 , 207 , 200 ]
for i in number:
city3 = list ( city. keys( ) ) [ list ( city. values( ) ) . index( i) ]
city2. append( city3)
print ( number, city2)
number. append( 298 )
city2. append( "合肥" )
print ( number, len ( number) , city2, len ( city2) )
city2. remove( "哈尔滨" )
number. remove( "271" )
data_work1 = data_work[ [ "年薪" , "城市" ] ]
eeee = [ ]
for iii in range ( len ( city2) ) :
aaaaa = 0
bbbb = [ ]
cccc = 0
for iiii in range ( data_work[ "城市" ] . shape[ 0 ] ) :
aaaaa += 1
data_work1. iloc[ iiii, 1 ]
if data_work1. iloc[ iiii, 1 ] == city2[ iii] :
bbbb. append( aaaaa)
for iiiii in bbbb:
dddd = data_work1. iloc[ iiiii, 0 ]
cccc += ( dddd/ number[ iii] )
eeee. append( int ( cccc) )
print ( city2)
print ( eeee)
city2 = [ '武汉' , '成都' , '西安' , '长沙' , '昆明' , '长春' , '郑州' , '贵阳' , '乌鲁木齐' , '银川' , '太原' , '南昌' , '南宁' , '呼和浩特' , '海口' , '杭州' , '合肥' ]
eeee = [ 157831 , 150958 , 134362 , 163685 , 126710 , 131162 , 125979 , 132517 , 131613 , 106293 , 124896 , 151148 , 131843 , 102599 , 131910 , 187103 , 200522 ]
ffff = [ 13 , 10 , 9 , 8 , 6 , 5 , 4 ]
for i in ffff:
city2. pop( i)
eeee. pop( i)
city2. pop( 6 )
eeee. pop( 6 )
city2. pop( 6 )
eeee. pop( 6 )
print ( city2, eeee)
quan = 140994
柱形图
quan = 140994
ax = plt. axes( )
labels = ax. get_xticklabels( )
plt. plot( city2, eeee, marker= 'o' , label= '各市平均年薪' )
plt. plot( [ quan] * 8 , '--' , label= '全国平均年薪' )
plt. setp( labels, rotation= 30 . )
plt. title( "全国数据分析平均年薪和各市平均年薪" , loc= "center" )
for a, b in zip ( city2, eeee) :
plt. text( a, b, b, ha= 'center' , va= "bottom" , fontsize= 10 )
plt. legend( )
全国岗位数量排名前10的城市
city3 = [ '武汉' , '成都' , '西安' , '长沙' , '昆明' , '长春' , '郑州' , '贵阳' , '乌鲁木齐' , '哈尔滨' ]
number3 = [ 344 , 337 , 330 , 326 , 301 , 299 , 298 , 279 , 278 , 271 ]
print ( len ( city3) , len ( number3) )
柱形图
a = np. array( city3)
b = np. array( number3)
plt. bar( a, b, width= 0.5 , align= "center" , label= "岗位个数" )
plt. title( "全国岗位数量排名前10的城市" , loc= "center" )
for ab, cd in zip ( a, b) :
plt. text( ab, cd, cd, ha= "center" , va = "bottom" , fontsize= 12 )
plt. xlabel( '城市名' )
plt. xticks( rotation= 90 )
plt. ylabel( '岗位数' )
plt. legend( )
气泡图
plt. subplot( 1 , 1 , 1 )
a = np. array( city3)
b = np. array( number3)
colors = b* 10
area = b* 4
plt. scatter( a, b, c = colors, marker = "o" , s = area, label= "岗位个数" )
plt. title( "全国岗位数量排名前10的城市" , loc= "center" )
for ab, cd in zip ( a, b) :
plt. text( ab, cd, cd, ha= "center" , va = "bottom" , fontsize= 10 , color= "white" )
plt. xlabel( '城市名' )
plt. xticks( rotation= 90 )
plt. ylabel( '岗位数' )
plt. legend( )
学历高低与岗位数量的关系
柱形图
气泡图
工作年限与岗位数量的关系
柱形图
气泡图
得出结论
本项目主要是学习并使用八象限分析法,从上面数据可视化的图中可以发现第1象限(高学历高年限高薪资),第7象限(低学历低年限低薪资)和第8象限(高学历低年限顶薪资)这三个象限岗位数都是较多的,而第3象限(低学历低年限高薪资)岗位数最少,看起来多读书还是有用处的,此外工作经验也很重要,说明我们要努力养成终身学习的良好习惯。 本来想找出全国平均年薪top10的,但是过程中发现 1.有的城市岗位数数很少,这样子误差就有可能很大 2.我采用的是统计年薪(有的每年是13,14…个月工资),这样子在求和时(我采用的是求和/岗位数)太大无法计算 3.所以最后我按岗位数排名挑选了20个城市计算了平均年薪,通过折线图可以直观的看到合肥,最低的是西安和贵阳 全国在招岗位数最多的是武汉,第二成都(奇怪北上广怎么没有,是我的爬取的数据不全面吗) 80%岗位都是专科起步,60%的岗位都是本科起步,这么看来学历真的很重要!
end
以上便是我对这份猎聘网岗位进行的一次探索分析,相信其中会有很多不足之处,欢迎有缘读到此篇文章的小朋友们批评指正,如有能启发或帮助到你的地方,我将倍感荣幸。(●’◡’●)