数据分析岗位近况分析

项目介绍

近几年数据分析较为火热,现根据从BOSS直聘上爬取的最近数据分析岗位招聘信息,分析招聘信息,主要是清洗字段后从城市、工作年龄、学历、薪水等方面进行分析。

项目过程

  1. 数据清洗
  • 该阶段主要是对项目脏数据进行清洗,包括去重、字段拆分、划分区间等操作。
    1.1 position 字段清洗
    1.2 work_year 字段清洗
    1.3 city 字段清洗
    1.4 text 字段清洗
  1. 数据分析阶段
    2.1 数据类岗位整体需求
    2.2 城市对薪资的影响
    2.3 学历对薪资的影响
    2.4 工作经验对薪资的影响
    2.5 不同岗位对应的学历要求、薪水分布情况

0. 数据观察

从sql读取源数据,观察是否有缺失字段以及脏数据。

df=pd.read_sql_query('select * from Boss_analyst',con=engine)

字段解释:

  • position - 职位
  • salary_range - 薪水区间
  • work_year - 工作经验
  • city - 城市
  • tag1 - 技能标签1
  • tag2 - 技能标签2
  • tag3 - 技能标签3
  • tag4 - 技能标签4
  • tag5 - 技能标签5
  • company_name - 公司名称
  • text - 未知
  • company_type - 公司类型
  • company_welfare -公司福利
  • 一共有4482条数据,其中tag4、tag5有缺失(暂不考虑,可能仅仅是因为技能需求没那么多),company_welfare字段缺失;
  • 其中position、salary_range、work_year、city、text均为脏数据,需要进行清洗。

1. 数据清洗

1.1 数据去重

由于可能爬取到重复数据,先对整体数据进行去重

df.drop_duplicates(inplace = True)
df.shape[0]
[out]:4435
  • 其中有47条重复数据,删除后剩余4435条有效数据。
1.2 position 字段清洗

数据分析岗位筛选:

df.position.unique()

岗位名称中,也有许多也数据分析无关的岗位,需使用contains将与数据分析相关岗位筛选出来。

data = df[df.position.str.contains("数据|分析|挖掘|BI|算法")]

岗位格式统一:

  • 观察数据可知,频次出现最多的关键字是数据分析师、数据运营 、数据挖掘、算法工程师
  • 为了分析方便,将高级数据分析师之类的数据统一规整为数据分析
  • 将数据运营专家类数据统一规整为数据运营
  • 将数据挖掘工程师之类的数据统一规整为数据挖掘
  • 其他还有商业分析师/ETL工程师之类的关键词出现不多,统一将其规整为其他
position_list = data.position.tolist()
# 使用正则进行匹配
str1 = ".*数据分析.*"
str2 = ".*数据挖掘.*"
str3 = ".*运营.*"
str4 = ".*算法.*"
# 创建一个空列表 用于接匹配结果
list2 = []

for i,values in enumerate(position_list):
    # 使用正则对position_list中对应位置的元素进行匹配,若匹配成功则...
    if re.match(str1,position_list[i]):
        # 如果匹配str1成功,则执行以下代码
        position_list[i] = "数据分析"
    elif re.match(str2,position_list[i]):
        position_list[i] = "数据挖掘"
    elif re.match(str3,position_list[i]):
        position_list[i] = "数据运营"
    elif re.match(str4,position_list[i]):
        position_list[i] = "算法工程师"
    else:
        position_list[i] = "其他"
# 重新赋值
data["position"] = pd.Series(position_list)
  • 最后将岗位分为以上4种类。

1.2 salary_range 字段清洗

data.salary_range.unique()
  • 工资字段种类较多,大致可分为:xx-xxk ·xx 薪,xx-xx元/天,xx-xxk 三种形式
  • 现将他们进行清洗,划分为3列:最低薪资、最高薪资、平均薪资
# 创建函数,将薪资字段进行拆分
def cut_salary(word,types):
    # 寻找“K”,“元”字符,如果找到返回所在位置,没找到则返回-1
    position1 = word.find("K")
    position2 = word.find("元")
    if position1 != -1: # 如果找到“K”
        salary_range = word[:position1]
    elif position2 != -1: # 如果找到“元”
        salary_range = word[:position2]
        
    # 拆分数据,最低薪资、最高薪资
    bottom_salary = int(salary_range.split("-")[0])
    top_salary = int(salary_range.split("-")[1])
    
    # 传递types参数,用于选择接受最小值还是最大值
    if types == "min_salary":
        return bottom_salary
    elif types == "max_salary":
        return top_salary
# running
data["min_salary"] = data.salary_range.apply(cut_salary,types = "min_salary")
data["max_salary"] = data.salary_range.apply(cut_salary,types = "max_salary")
#新增平均薪水列
data["avg_salary"] = (data["min_salary"] + data["max_salary"])/2

处理结果如下:

1.3 work_year 字段清洗
data.work_year.unique()

数据内容的格式大致有:

  • 学历数据:学历不限、高中、中专/中技、大专、本科、硕士、博士
  • 经验数据:3-5年、1年以内、10年以上、经验不限、4天/周3个月
    由于4天/周类字段属于实习生,我们暂不考虑,筛选出全职工作,并将work_year字段划分为2个字段:工作年限、学历
python
# 切分学历要求
def cut_word2(word, types):
    p1 = word.find("学历")
    p2 = word.find("博")
    p3 = word.find("硕")
    p4 = word.find("本")
    p5 = word.find("大")
    p6 = word.find("高")
    p7 = word.find("本")
    p8 = word.find("中")
    
    if p1 != -1:
        work_year = word[:p1]
        Edu = word[p1:]
    elif p2 != -1:
        work_year = word[:p2]
        Edu = word[p2:]
    elif p3 != -1:
        work_year = word[:p3]
        Edu = word[p3:]
    elif p4 != -1:
        work_year = word[:p4]
        Edu = word[p4:]
    elif p5 != -1:
        work_year = word[:p5]
        Edu = word[p5:]
    elif p6 != -1:
        work_year = word[:p6]
        Edu = word[p6:]
    elif p7 != -1:
        work_year = word[:p7]
        Edu = word[p7:]
    elif p8 != -1:
        work_year = word[:p8]
        Edu = word[p8:]
    
    # 根据传递的types值,接收经验年限或学历字段
    if types == "work_year":
        return work_year
    elif types == "Edu":
        return Edu

data["Edu"] = data.work_year.apply(cut_word2,types = "Edu")
data["work_year"] = data.work_year.apply(cut_word2,types = "work_year")

# 全职
data_full_time = data[~data.work_year.str.contains("天|周|月")]
data_full_time.head()

1.4 city 字段清洗

data_full_time.city.unique()
  • 该字段中不仅划分了城市,还划分的区,暂不考虑区,统一划分为城市角度
data_full_time["city"] = data_full_time.city.apply(lambda x:x.split("·")[0])

1.5 text 字段清洗

# 观察text字段
data_full_time.text.unique()
  • 该字段中大致有三类信息:公司行业、融资情况、公司规模
  • 由于行业字段已经存在,先将他们分为融资情况和公司规模两列
    查看无融资情况
data_full_time[~data_full_time.text.str.contains("天使|A|B|C|D|已上市|未融资|不需要")].shape[0]
[out]:127
  • 有127条数据没有融资信息,因为数据量占比很小,且清洗复杂所以暂不处理
data = data_full_time[data_full_time.text.str.contains("天使|A|B|C|D|已上市|未融资|不需要")]
# 处理融资情况函数
# 对融资情况、公司规模做进行切片处理
def cut_word3(word, types):
    # 融资情况
    p1 = word.find("天")
    p2 = word.find("A")
    p3 = word.find("B")
    p4 = word.find("C")
    p5 = word.find("D")
    p6 = word.find("已上市")
    p7 = word.find("未融资")
    p8 = word.find("不需要")

    if p1 != -1:
        company_financing = word[p1:p1+3]
        company_size = word[p1+3:]
    elif p2 != -1:
        company_financing = word[p2:p2+2]
        company_size = word[p2+2:]
    elif p3 != -1:
        company_financing = word[p3:p3+2]
        company_size = word[p3+2:]
    elif p4 != -1:
        company_financing = word[p4:p4+2]
        company_size = word[p4+2:]
    elif p5 != -1:
        company_financing = word[p5:p5+5]
        company_size = word[p5+5:]
    elif p6 != -1:
        company_financing = word[p6:p6+3]
        company_size = word[p6+3:]
    elif p7 != -1:
        company_financing = word[p7:p7+3]
        company_size = word[p7+3:]
    elif p8 != -1:
        company_financing = word[p8:p8+5]
        company_size = word[p8+5:] 
        
    # 根据types 接收
    if types == "company_financing":
        return company_financing
    elif types == "company_size":
        return company_size

data["company_financing"] = data.text.apply(cut_word3,types="company_financing")
data["company_size"] = data.text.apply(cut_word3,types="company_size")

# 检查数据
# 检查数据
print(data["company_financing"].unique())
print("- "*30)
print(data["company_size"].unique())
['已上市' '不需要融资' 'C轮' 'D轮及以上' 'A轮' '未融资' 'B轮' '天使轮']
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
['500-999人' '10000人以上' '1000-9999人' '100-499人' '20-99人' '0-20人']
  • 清洗成功后

2. 数据分析

2.1 数据类型岗位整体状况

# 不同岗位占比
plt.rcParams["font.size"] = "16"
data.position.value_counts().plot(kind = "pie",figsize = (8,8),autopct='%.2f%%')
  • 数据分析类岗位占了近一半,数据挖掘类次之,算法工程师类需求最少。但只是从大的范畴来区分的,实际会存在一定偏差,岗位名称叫法很多,其他类岗位中也会存在叫算法工程师,这就属于数据挖掘这块了。单看岗位名称不具体,要看具体的岗位职能描述才能准确定义这个岗位属于哪个范畴
plt.figure(figsize=(18,10))

plt.rcParams['font.size']=12
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#学历
plt.subplot(2,3,1)
data.Edu.value_counts().plot(kind='barh',alpha=0.7)

# 工作年限
plt.subplot(2,3,2)
data.work_year.value_counts().plot(kind='barh',alpha=0.7)

# 岗位分布情况
plt.subplot(2,3,3)
data.city.value_counts().plot(kind='pie',autopct='%.1f%%')

# 公司类别
plt.subplot(2,3,4)
data.company_type.value_counts().head(6).plot(kind='barh',alpha=0.7)

# 公司融资情况
plt.subplot(2,3,5)
data.company_financing.value_counts().plot(kind='barh',alpha=0.7)

# 薪水情况
bins = [0,3,6,9,12,15,20,30,100]
level = ["0-3k","3-6k","6-9k","9-12k","12-15k","15-20k","20-30k","30k+"]
data["salary_level"] = pd.cut(data.avg_salary,bins = bins,labels=level)
plt.subplot(2,3,6)
data["salary_level"].value_counts().plot(kind = "pie", autopct='%.1f%%')

plt.show()
  • 学历要求:大专是最低要求,招高中或中专/中技的极少,最好是本科及以上
  • 工作经验需求:偏向招聘有一定经验的求职者,尤其3-5年经验的需求最旺盛。一般工作3年以上,对于整个职业的了解会比较深入,技术趋于成熟,能够帮助做一些独立的项目
  • 岗位分布情况:北上广深杭对其需求都差不多,相对来说北京机会最多,广州偏少
  • 公司融资情况:招聘数据类岗位的一般都是达到了一定规模的大型企业
  • 行业分布情况:互联网行业需求是最多的,包括电商、金融。还有一些乙方公司也有一定需求,比如数据服务类、咨询类
  • 薪资情况:受工作经验影响较大,3年工作经验薪资一般集中在20-30K,比较可观

总结:
绝大部分公司不倾向出钱出力对新人进行培养,尤其近期又遭受到疫情的冲击,会更偏爱有工作经验的求职者,能够直接上手,尤其是能帮助做一些独立项目。

但这不仅仅针对于数据类岗位,所有岗位对求职者的要求都是越来越高的。工作经验这种要求,其实对于个人而言,它可以是硬性的,也可以是软性的,它其实是一种期望值,表示公司期望求职者能够匹配相应工作经验的能力,如果你的综合能力能够超过公司预期的期望,求职是完全没问题的

所以这就更要求我们对于能力方面做更多的训练,以及如何能够向公司体现你的能力做更多的准备

2.2 城市对薪资的影响

# 按城市聚合 所有工资级别数量
grouped_city = data.groupby(["city","salary_level"]).salary_level.count().unstack().fillna(0)
# 计算占比
grouped_city_diff = grouped_city.div(grouped_city.sum(1),axis = 0)
# 绘图
plt.rcParams['font.size'] = "13"
grouped_city_diff.plot(kind = "bar", stacked=True,figsize=(9,7),alpha=0.7,width=0.2)
# stacked = 表示是否堆积
plt.show()
  • 北京愿意开出更高的价格吸引求职者,20-30K,甚至30K以上的比例都占了很大。
  • 广州高薪资的比例没那么多,尤其10K以下的工资水平对比其他城市占的比例大

2.3 学历对薪资的影响

data.boxplot(column='avg_salary',by='Edu',figsize=(9,7))
  • 学历上看,呈现出学历越高,起步价越高的态势(学历不限,可能是培训机构挂出来的岗位,也可能其他情况,这个不一概而论)

2.4 工作经验对薪资的影响

data.boxplot(column='avg_salary',by='work_year',figsize=(9,7))
  • 工作经验上看,薪资的差距拉开的很大,应届生和有工作经验的薪资对比,不在一个维度上,但这恰恰说明数据类岗位是可以通过个人能力的提高来获取更大的收益的,它是可成长的。你对技术、业务越熟悉,你的机会就越多,薪资就越高。

2.5 不同岗位对学历的要求

各岗位的薪水分布情况

data.groupby(["salary_level","position"]).agg({"salary_level":"count"}).unstack().plot(figsize = (12,6))
  • 总体分布情况上来看,数据分析、数据挖掘、数据运营岗位相对来说均在20-30k之间需求较多
  • 数据挖掘类岗位对比其他岗位在30k+上占比最高,薪资集中于20-30k之间

各岗位的学历分布情况

data.groupby(["Edu","position"]).agg({"Edu":"count"}).unstack().plot(kind = "barh", figsize = (12,6))
  • 数据挖掘类岗位对学历要求最高;
  • 整体情况上,都是本科学历要求最多,所以最好有本科学历的基础转行数据分析。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335