用MapReduce对招聘数据处理分析+可视化

对招聘数据处理分析并可视化


前言

关于本次任务:

当我们择业,寻找工作时,需要从各大招聘平台,招聘网站以及招聘单位官网等获取招聘信息,那么对相关数据进行分析,能帮助我们更好的了解招聘市场情况,可以对我们的就业提供参考。本次任务从Boss直聘获取数据,分析热门职位,城市平均工资等信息,帮助我们更好地面对严峻的就业形势。


以下是本次任务主要内容:

一、数据源和任务目标

数据来源于Boss直聘,一共1651条记录,其中包含id,city(城市),education(学历),salary(工资)等12个属性,数据样式如下:
在这里插入图片描述
任务目标:
1.各学历平均工资;
2.各城市平均工资走势;
3.各岗位招聘数量占比分析

二、具体实现

任务1.各学历平均工资

涉及数据属性:education, salary
任务输入:data.txt
任务输出:output/01/part-r-00000
总体流程设计如图:
在这里插入图片描述
数据处理:
Map部分

public static class Map extends Mapper<LongWritable, Text, Text, Text> {

        Text k = new Text();
        Text v = new Text();

        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

            String s = value.toString();
            
            if (!s.contains("advantage") && s.trim().length() > 0 && s.split("\t").length == 12) {
                String[] strings = s.split("\t");
                k.set(strings[3]);
                v.set(strings[8]);

                context.write(k, v);
            }
        }
    }

Reduce部分

 public static class Reduce extends Reducer<Text, Text, Text, Text> {

        Text v = new Text();
       
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {

            Double sumSalary = 0D;
            int cntSalary = 0;
            
            for (Text value : values) {
                int salary = Integer.parseInt(value.toString());
                sumSalary += salary;
                cntSalary ++;
            }
          
            double avgSalary = sumSalary / cntSalary;
            v.set(avgSalary+"");
            context.write(key, v);

        }
    }

可视化:

def drawChart_1():
    root = "output/01/part-r-00000"
    date = []
    cases = []
    with open(root, 'r',encoding='utf-8') as f:
        while True:
            line = f.readline()
            if not line:   
                break
            strings = line.split('\t')
            date.append(str(strings[0]))
            cases.append(int(float(strings[1])))

    d = (
        Bar()
            .add_xaxis(date)
            .add_yaxis("平均工资", cases, stack="stack1")
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
            .set_global_opts(title_opts=opts.TitleOpts(title="各学历平均工资"))
            .render("output_html/result1.html")
    )

运行结果:
在这里插入图片描述
在这里插入图片描述
通过数据分析以及观察可视化效果,各学历层次工资金额都很可观,博士生尤为显著,除此以外,大专,本科,硕士三个学历层次工资金额随学历层次的升高而增加。而对于其他层次,例如自考,培训,自学等,其工资水平也并不低,同时在一定程度上反映技术水平的重要性。但从整体来看,正常情况下,学历层次同工资水平是呈正比关系的,同时也反映当下考研热潮的火爆。

任务2.各城市平均工资走势

涉及数据属性:city, salary
任务输入:data.txt
任务输出:output/02/part-r-00000
总体流程设计如图:
在这里插入图片描述
数据处理:
Map部分

public static class Map extends Mapper<LongWritable, Text, Text, Text> {

        Text k = new Text();
        Text v = new Text();
        
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

            String s = value.toString();
           
            if (!s.contains("advantage") && s.trim().length() > 0 && s.split("\t").length == 12) {
                String[] strings = s.split("\t");
                k.set(strings[2]);
                v.set(strings[8]);

                context.write(k, v);
            }
        }
    }

Reduce部分

public static class Reduce extends Reducer<Text, Text, Text, Text> {

        Text v = new Text();
        
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {

            Double sumSalary = 0D;
            int cntSalary = 0;
            
            for (Text value : values) {
                int salary = Integer.parseInt(value.toString());
                sumSalary += salary;
                cntSalary ++;
            }
           
            double avgSalary = sumSalary / cntSalary;
            v.set(avgSalary+"");
            context.write(key, v);
        }
    }

可视化:

def drawChart_2():
    root = "output/02/part-r-00000"
    date = []
    cases = []
    with open(root, 'r',encoding='utf-8') as f:
        while True:
            line = f.readline()
            if not line: 
                break
            strings = line.split('\t')
            date.append(str(strings[0]))
            cases.append(int(float(strings[1])))

    (
        Line(init_opts=opts.InitOpts(width="1600px", height="800px"))
            .add_xaxis(xaxis_data=date)
            .add_yaxis(
            series_name="工资",
            y_axis=cases,
            markpoint_opts=opts.MarkPointOpts(
                data=[
                    opts.MarkPointItem(type_="max", name="最大值")
                ]
            ),
            markline_opts=opts.MarkLineOpts(
                data=[opts.MarkLineItem(type_="average", name="平均值")]
            ),
        )
            .set_global_opts(
            title_opts=opts.TitleOpts(title="各城市平均工资走势", subtitle=""),
            tooltip_opts=opts.TooltipOpts(trigger="axis"),
            toolbox_opts=opts.ToolboxOpts(is_show=True),
            xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
        )
            .render("output_html/result2.html")
    )

运行结果:
在这里插入图片描述
在这里插入图片描述
通过数据分析以及观察可视化效果,在各大热门城市中,热门去向依然是北京,上海,广州,深圳(北上广深),工资水平居于第一梯队,是大家争先恐后去发展的地方。除此以外,杭州的平均工资水平也很可观,只是该城市对应届生身份卡得严,更多的是有工作经验的“社会人”在发展,所以很多应届毕业生选择去了工资水平相当的其他热门城市。近年,有很多新一线城市兴起,比如涉及到的南京,成都,武汉,重庆等,其平均工资水平虽然赶不上其他热门地域城市,但对于不少对工资水平要求不是太高,喜欢稍慢一点节奏生活的毕业生也是不错去向。总体来看,除北京,上海,广州,深圳,杭州这些热门城市工资水平在高薪标准以上,其他城市均在其之下。

任务3.各岗位招聘数量占比分析

涉及数据属性:position_name
任务输入:data.txt
任务输出:output/03/part-r-00000
总体流程设计如图:
在这里插入图片描述
数据处理:
Map部分

public static class Map extends Mapper<LongWritable, Text, Text, Text> {

        Text k = new Text();
        Text v = new Text();
        
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

            String s = value.toString();
         
            if (!s.contains("advantage") && s.trim().length() > 0 && s.split("\t").length == 12) {
                String[] strings = s.split("\t");
                k.set(strings[7]);
                v.set("1");

                context.write(k, v);
            }
        }
    }

Reduce部分

public static class Reduce extends Reducer<Text, Text, Text, Text> {

        Text v = new Text();
        
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            
            int size = Lists.newArrayList(values).size();
            
            v.set(size+"");
            context.write(key, v);
        }
    }

可视化:

def drawChart_3():
    root = "output/03/part-r-00000"
    values = []
    with open(root, 'r',encoding='utf-8') as f:
        while True:
            line = f.readline()
            if not line:                           
                break
            strings = line.split('\t')
            values.append([(strings[0]),(strings[1])])
    c = (
    Pie()
    .add("", values)
    .set_colors(["orange","red","blue","green"])
    .set_global_opts(title_opts=opts.TitleOpts(title="各岗位招聘数量占比分析"))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
    .render("output_html/result3.html")
    )

运行结果:
在这里插入图片描述
在这里插入图片描述
通过数据分析以及观察可视化效果,可以看出对于数据分析涉及到的这四个岗位:数据分析师,数据挖掘工程师,机器学习工程师,深度学习工程师,其招聘人数占比都差不太多,而其中相比较多的是机器学习工程师和数据挖掘工程师。而随着近年来,大数据,人工智能的发展,对于数据分析,机器学习方面的技术人员需求很大,但同时岗位缺口也很大。


总结

 三个任务是对部分招聘数据的分析处理,通过最终的数据分析及结果可视化观察并结合资料可知:

1.学历与工资水平呈正比;
2.北上广深依旧火热,工资水平依旧处于第一梯队;
3.随着近几年大数据、人工智能的崛起。算法类的职位缺口比较大。
以上三点即为最简洁地概括最终处理结果分析。

关于MapReduce:
MapReduce是一个分布式运算程序的编程框架,是用户开发"基于Hadoop的数据分析应用”的核心框架。

MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成-个完整的分布式运算程序,并发运行在一个Hadoop集群上。
其优缺点:
关于优点

  1. MapReduce易于编程
    它简单的实现一些接口,就可以完成一个分布式程序, 这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写-个简单的串行程序是一模一样的。 就是因为这个特点使得MapReduce编程变得非常流行。
    2.良好的扩展性
    当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
    3.高容错性
    MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。
    4.适合PB级以上海量数据的离线处理
    可以实现上千台服务器集群并发工作,提供数据处理能力。
    关于缺点
    1.不擅长实时计算
    MapReduce无法像MySQL-样,在毫秒或者秒级内返回结果。
    2.不擅长流式计算
    流式计算的输入数据是动态的,而MapReduce的输入数据集 是静态的,不能动态变化。这是因为MapReduce自身 的设计特点决定了数据源必须是静态的。
    3.不擅长DAG (有向图)计算
    多个应用程序存在依赖关系,后一个应用程序的输入为前一一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

其核心编程思想:
在这里插入图片描述

1)分布式的运算程序往往需要分成至少2个阶段。
2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。
3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
总结:分析WordCount数据流走向深入理解MapReduce核心思想。

其处理的一般步骤:
用户编写的程序分成三个部分:Mapper、Reducer和Driver
(1)map阶段
用户自定义的Mapr要迷承自己的父类;
Mapper的输入数据是KV对的形式(KV的类型可自定义);
Mapper中的业务逻 辑写在map方法中;
Mape的前出数据是KV对的形式(KV的类型可自定义);
map(方法(MapTasb进程) 对每个<K.V>调用-次。
(2)reduce阶段
用户自定义的Reducer要继承自己的父类;
Reducet的输入数据类型对应Mappe的输出数据类型,也是KV;
Reducer的业务逻辑写在reduce方法中;
ReduceTask进程对每组相同k的<k,v>组调用一 次reduce()方法。
(3)Driver阶段
相当于YARN隼群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程字相关运行参数的job对象。

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y?Ire: TO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值