基于实习僧招聘数据进行数据分析与处理

  基于实习僧招聘数据进行数据分析与处理

一,选题背景

实习僧,专注实习,校招的校园招聘平台。为大学生提供国内外行业巨头在内的25万+企业实习、校园招聘岗位信息。助力大学生职业发展,帮助企业有效招聘,找实习校招就上实习僧。预取目标是找的实习公司是机器学习算法相关的工作,所以只对“数据挖掘”、“机器学习”、“算法”这三个关键字进行了爬取,以及公司相关的分析。

二,爬虫设计方案

1,爬虫名称:基于实习僧招聘数据进行数据分析与处理

2,数据特征分析

使用pandas进行数据处理和分析,结合seaborn和pyecharts包进行数据可视化

三,结构特征分析

1,页面结构与特征分析

 

 

 

 

 

 2,Htmls页面解析

 

 

 

四,程序设计

1,数据爬取与采集

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import pyecharts
plt.style.use('ggplot')
%matplotlib inline

from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']  #解决seaborn中文字体显示问题
plt.rc('figure', figsize=(10, 10))  #把plt默认的图片size调大一点

 

#把通过“数据挖掘”、“机器学习”和“算法”这3个关键词爬取到的3个csv文件数据导入为pandas DataFrame,再把他们concat起来
#把ignore_index设置成True让其可以重新索引

data_dm = pd.read_csv("datamining.csv")
data_ml = pd.read_csv("machinelearning.csv")
data_al = pd.read_csv("mlalgorithm.csv")
data = pd.concat([data_dm, data_ml, data_al], ignore_index = True)
#随机抽取3个数据样本看数据是否导入正确
#查看数据基本信息,看数据的行列数、数据类型是否正确、是否有重复数据,以及首先对重复数据进行处理
data.sample(3)

 

 

data.loc[666]

 

 

data.info()

 

 

data.drop_duplicates(subset='job_links', inplace=True)
data.shape

 

 2,数据处理

#由上可见:
#com_fullname、com_name、job_academic、job_links、tag不需要处理
#“auth_capital”(注册资本)、“day_per_week”(每周工作天数)、#“num_employee”(公司规模)、“time_span”(实习月数)、“wage”#(每天工资)等字段,都可以处理成数值型数据
#“est_date”(公司成立日期)、“job_deadline”(截止时间)、#“released_time”(发布时间)、“update_time”(更新时间)等字段,可#以处理成datetime类型数据
#“city”(城市)、“com_class”(公司类型)、“com_intro(公司简介)”、#“job_title”(职位名称)等字段可以进一步处理
#类似于“com_logo”(公司logo)、“industry”(行业)等字段,可以视情况处理
#com_id、com_links、com_location、com_website、com_welfare、#detailed_intro、job_detail在本次分析中用不上,不处理
#新建data_clean数据框
#新建data_clean数据框,数据处理在data_clean上进行
#data_clean用以保存处理好的数据,原数据data用以保存原始数据记录
#把本次分析中用不上的字段先drop掉
data_clean = data.drop(['com_id', 'com_links', 'com_location', 'com_website', 
                 'com_welfare', 'detailed_intro', 'job_detail'], axis = 1)
 #数值型数据处理
#包括“auth_capital”(注册资本)、“day_per_week”(每周工作天数)、“num_employee”(公司规模)、“time_span”(实习月数)、“wage”(每天工资)等字段
#“auth_capital”(注册资本)
#随机抽取“auth_capital”,发现该字段的格式基本为:“注册资本:(数字)万|万元(币种)”,有少许的格式为:“注册资本:(币种)(数字)万|万元”, 或者“注册资本:无”,或者该字段为缺失值
#币种有人民币、美元、欧元、港元(港币)等
#这里的处理思路是先把“注册资本:”清理掉,再把数值型数据提取出来,然后根据各币种的汇率,把注册资本转换为“万元人民币”单位
data.auth_capital.sample(20)

 

 

auth_capital = data['auth_capital'].str.split('', expand = True)
auth_capital.sample(5)

 

 

auth_capital['num'] = auth_capital[1].str.extract('([0-9.]+)', expand=False).astype('float')
auth_capital.sample(5)

 

 

auth_capital[1].str.split('', expand = True)[1].unique()

 

 

def get_ex_rate(string):
    if string == None:
        return np.nan
    if '人民币' in string:
        return 1.00
    elif '' in string:
        return 0.80
    elif '美元' in string:
        return 6.29
    elif '欧元' in string:
        return 7.73
    elif '' in string:
        return 1.00
    else:
        return np.nan
    
auth_capital['ex_rate'] = auth_capital[1].apply(get_ex_rate)
auth_capital.sample(5)

 

 

data_clean['auth_capital'] = auth_capital['num'] * auth_capital['ex_rate']
data_clean['auth_capital'].head()

 

 

#“day_per_week”(每周工作天数)
#由下可见:

#“day_per_week”字段没有缺失值,并且取值在“2-6天/周”之间
#可以采用直接赋值的方法处理该字段
data.day_per_week.unique()

 

 

data_clean.loc[data['day_per_week'] == '2天/周', 'day_per_week'] = 2
data_clean.loc[data['day_per_week'] == '3天/周', 'day_per_week'] = 3
data_clean.loc[data['day_per_week'] == '4天/周', 'day_per_week'] = 4
data_clean.loc[data['day_per_week'] == '5天/周', 'day_per_week'] = 5
data_clean.loc[data['day_per_week'] == '6天/周', 'day_per_week'] = 6
#“num_employee”(公司规模)
#同样,由于“num_employee”字段取值在['2000人以上', '500-2000人', nan, '50-150人', '15-50人', '150-500人', '少于15人', '5000人以上'],可以采用跟“day_per_week”字段一样的处理方法
#'少于15人'、'15-50人'、'50-150人'都记为'小型企业','150-500人'、'500-2000人'记为'中型企业','2000人以上'、'5000人以上'记为大型企业
data.num_employee.unique()

 

 

data_clean.loc[data['num_employee'] == '少于15人', 'num_employee'] = '小型企业'
data_clean.loc[data['num_employee'] == '15-50人', 'num_employee'] = '小型企业'
data_clean.loc[data['num_employee'] == '50-150人', 'num_employee'] = '小型企业'
data_clean.loc[data['num_employee'] == '150-500人', 'num_employee'] = '中型企业'
data_clean.loc[data['num_employee'] == '500-2000人', 'num_employee'] = '中型企业'
data_clean.loc[data['num_employee'] == '2000人以上', 'num_employee'] = '大型企业'
data_clean.loc[data['num_employee'] == '5000人以上', 'num_employee'] = '大型企业'
data_clean.loc[data['num_employee'].isna(), 'num_employee'] = np.nan
#“time_span”(实习月数)
#由下可知:

#“time_span”字段没有缺失值,由“1-18个月”组成
#当然,你也可以通过跟上面一样的处理方式来处理,但是,这种方式对于取值多的字段来说,第一比较繁琐,第二,其实这个赋值方式本身的运行速度很慢
#可以考虑构造一个字典,通过pd.Series.map() 也就是映射的方式来做,方便快捷
data.time_span.unique()

 

 

mapping = {}
for i in range(1,19):
    mapping[str(i) + '个月'] = i
print(mapping)

 

 

data_clean['time_span'] = data['time_span'].map(mapping)
data_clean.head(3)

 

 

#“wage”(每天工资)
#通过观察可知,该字段没有缺失值,并且格式全都为:xxx-xxx/天
#可以取一个最低工资,一个最高工资,再求一个平均工资
#这里,可以用之前的pd.Series.apply(function)来做,即定义一个函数提取每条记录中的工资最小和最大值
#不过,更加简便的方法肯定是正则提取啊
data['wage'].sample(5)

 

 

data_clean['average_wage'] = data['wage'].str.extract('([0-9.]+)-([0-9.]+)/天', expand=True).astype('int').mean(axis = 1)
data_clean['average_wage'].head()

 

 

 #时间数据处理
#包括“est_date”(公司成立日期)、“job_deadline”(截止时间)、“released_time”(发布时间)、“update_time”(更新时间)等字段
#“est_date”(公司成立日期)
#随机抽取发现“est_date”这个字段的格式为:成立日期:xxxx-xx-xx
#因此,直接正则提取,然后把它转换为datetime格式就可以了
data['est_date'].sample(5)

 

 

data_clean['est_date'] = pd.to_datetime(data['est_date'].str.extract('成立日期:([0-9-]+)', expand=False))
data_clean['est_date'].sample(5)

 

 

#“job_deadline”(截止时间)
#这个字段很干净,直接类型转换便可
data['job_deadline'].sample(5)

 

 

data_clean['job_deadline'] = pd.to_datetime(data['job_deadline'])
#“released_time”(发布时间)
#观察数据发现,该字段1小时内的都以分钟表示、1小时-2天内的都以小时表示、2天-1周内的都以天表示,1周-1个月内的都以周表示,1个月以上的以月表示
#可以考虑清洗成:2天以内是最新的(newest),2天-1周是新的(new),1周-1个月是可以投简历的(acceptable),1个月以上的是旧的(old)
#这个的处理方法很多,我的方法是先把每条记录中的分钟、小时、天、周、月提取出来,再定义一个映射map一下就可以了
data['released_time'].sample(5)

 

 

data_clean['released_time'] = data['released_time'].str.extract('[0-9-]+(\w+)前', expand=False).map(
    {'分钟':'newest', '小时':'newest', '':'new', '':'acceptable', '':'old'})
data_clean['released_time'].sample(5)

 

 

#“update_time”(更新时间)
#更新时间字段格式很工整,直接转换类型便可
data['update_time'].sample(5)

 

 

data_clean['update_time'] = pd.to_datetime(data['update_time'])
#字符型数据处理
#包括“city”(城市)、“com_class”(公司类型)、“com_intro(公司简介)”、“job_title”(职位名称)等字段
#“city”(城市)处理
#乍一看这个字段还挺整洁的,取唯一值看一下发现有些城市还是需要稍微处理一下
#比如说成都有“成都市”和“成都”,珠海有“珠海市”和“珠海”等
#直接赋值处理
data['city'].unique()

 

 

data_clean.loc[data_clean['city'] == '成都市', 'city'] = '成都'
data_clean.loc[data_clean['city'].isin(['珠海市', '珠海 深圳', '珠海']), 'city'] = '珠海'
data_clean.loc[data_clean['city'] == '上海漕河泾开发区', 'city'] = '上海'

 

 

data_clean['city'].value_counts().nlargest(10).plot(kind = 'bar')

 

 

 #“com_class”(公司和企业类型)处理
#类型有很多,可以按照组织形式可以分为独资企业、合伙企业、公司制企业,公司制企业又分为有限责任公司和股份有限公司等等
#这里主要把它分为‘股份有限公司(未上市)’、‘股份有限公司(上市)’、‘有限责任公司’、‘外商投资公司’、‘有限合伙企业’、‘国有企业’这6种
#处理方法跟上面币种的处理方法一致
#首先看看都有哪些公司(或企业)类型
list(data['com_class'].unique())

 

 

#定义一个函数处理这些类型,利用pd.Series.apply(function)方法
#把处理好的数据保存到data_clean中
def get_com_type(string):
    if string == None:
        return np.nan
    elif ('非上市' in string) or ('未上市' in string):
        return '股份有限公司(未上市)'
    elif '股份' in string:
        return '股份有限公司(上市)'
    elif '责任' in string:
        return '有限责任公司'
    elif '外商投资' in string:
        return '外商投资公司'
    elif '有限合伙' in string:
        return '有限合伙企业'
    elif '全民所有' in string:
        return '国有企业'
    else:
        return np.nan

com_class = data['com_class'].str.split('', expand = True)
com_class['com_class'] = com_class[1].apply(get_com_type)
com_class.sample(5)

 

 

data_clean['com_class'] = com_class['com_class']
#“com_intro”(公司简介)、“job_title”(职位名称)两个字段暂时不处理
# “com_logo”(公司logo)、“industry”(行业)也暂时不处理
#更改一下每列的顺序
#再把data_clean保存到本地
data_clean = data_clean.reindex(columns=['com_fullname', 'com_name', 'job_academic', 'job_links', 
                                         'tag','auth_capital', 'day_per_week', 'num_employee', 'time_span',
                                         'average_wage', 'est_date', 'job_deadline', 'released_time',
                                         'update_time', 'city', 'com_class', 'com_intro', 'job_title',
                                         'com_logo', 'industry'])
data_clean.to_csv('/Users/apple/Desktop/shixiseng/data_clean.csv', index = False)

 

 

数据分析

#进入数据分析的阶段。可以利用以上的城市、薪资、学历、行业、公司等相关字段,分析出目前国内公司对机器学习算法实习生的需求状况(仅基于实习僧网站),以及公司的相关情况

#首先,看看清洗完的数据的基本情况

数据基本情况

data_clean.sample(3)

 

 

data_clean.info()

 

 

#城市与职位数量
#其实由上面已经知道了,北上广深杭这五个城市毫无疑问地占据了前五的位置,其中北京遥遥领先,有471个职位,占53.89%;上海有164个,占18.76%;北上广深杭这五个城市占了所有的89.93%(将近九成),说明这个职位还是集中在一线城市
#另外值得注意的是,杭州排到了第三,在广州和深圳的前面,说明杭州在这方面的发展还挺好的
#原以为杭州的职位都被阿里系霸占了,结果抽取数据出来一看发现并没有,其中一家叫“非白三维”的公司占了10个职位,这到底是一家什么样的公司?可以去了解一下
city = data_clean['city'].value_counts()
city[:15]

 

 

bar = pyecharts.Bar('城市与职位数量')
bar.add('', city[:15].index, city[:15].values, mark_point=["max"])
bar


city_pct = (city/city.sum()).map(lambda x: '{:,.2%}'.format(x))
city_pct[:15]

 

 

(city/city.sum())[:5].sum()

 

 

data_clean.loc[data_clean['city'] == '杭州', 'com_name'].value_counts()[:5]

 

 

#再看看这15个个城市中,招聘职位数量前五的公司到底是哪些
#通过定义一个函数topN来实现
def topN(dataframe, n=5):
    counts = dataframe.value_counts()
    return counts[:n]
data_clean.groupby('city').com_name.apply(topN).loc[list(city_pct[:15].index)]

 

薪资

#平均薪资
#由于"average_wage"(薪资)一列的单位是每天,所以可以跟"day_per_week"(每周天数)结合起来算每月的工资(以一个月4周算)
#另起一列“salary”(月工资)保存数据
#发现平均实习工资是3645元人民币,应该还是OK的噶?
data_clean['salary'] = data_clean['average_wage'] * data_clean['day_per_week'] * 4
data_clean['salary'].mean()

 

 

#薪资与城市
#以城市分组,看不同城市平均实习工资怎么样,发现薪资前五名中,北上广深杭只有杭州进入了前五,不过前五中其它四个城市的样本量都太小,数据不具有代表性
#看看职位需求前10的城市,平均实习薪资怎么样,发现杭州是最高的,突破了4000(还算可以的噶?),紧接着是北京3790(弱弱地问一句,够房租不?),然后是深圳、上海、南京、广州
salary_by_city = data_clean.groupby('city')['salary'].mean()
salary_by_city.nlargest(10)

 

 

top10_city = salary_by_city[city_pct.index[:10]].sort_values(ascending=False)
top10_city

 

 

bar = pyecharts.Bar('北上广深杭等城市平均实习工资')
bar.add('', top10_city.index, np.round(top10_city.values, 0), mark_point=["max"], is_convert=True)
bar
再看看这些城市实习薪资的分布怎么样
top10_city_box = data_clean.loc[data_clean['city'].isin(top10_city.index),:]
sns.violinplot(x ='salary', y ='city', data = top10_city_box)

 

 

学历

数据挖掘、机器学习算法的学历要求
  • 先看看总体来说,需要什么学历的最多,发现需求的本科生数量是最多的,约占50%,紧接着是硕士,约占30%,博士是最少的
job_academic = data_clean['job_academic'].value_counts()
job_academic

 

 

pie = pyecharts.Pie("学历要求")
pie.add('', job_academic.index, job_academic.values)
pie
#学历与薪资
#再看看实习薪资和学历有什么关系。发现基本上是正相关的关系,博士最高,接着是硕士、本科、大专
#但是,本科和硕士的实习工资差别不大
#总体看起来实习工资都偏低一些(不知道大家的实习工资是多少呢?),就算是博士也不太高
data_clean.groupby(['job_academic'])['salary'].mean().sort_values()

 

 

sns.boxplot(x="job_academic", y="salary", data=data_clean)

 

 

行业

  • 有一个好奇是,在现在的各行各业中,哪些行业对数据挖掘、机器学习算法的实习生需求更多,还有哪些行业现在也正在应用机器学习算法
  • “industry”字段是前面还未处理的,先看看数据长什么样子,发现同一条记录可能对应着一个或者多个行业,格式为xxx/xxx或者xxx,xxx,或者xxx,xxx等
  • 字段存在一定的缺失值
  • 考虑把字段按照/,,分割,行业名称每出现一次,做一次记录,比如“计算机/互联网,金融”,既属于“计算机”行业、又属于“互联网”行业,也属于“金融行业”,因此这3个行业的记录加1
data_clean['industry'].sample(5)

 

 

industry = data_clean.industry.str.split('/|,|,', expand = True)

 

 

industry_top15 = industry.apply(pd.value_counts).sum(axis = 1).nlargest(15)
bar = pyecharts.Bar('行业与职位数量')
bar.add('', industry_top15.index, industry_top15.values, 
        mark_point=["max","min","average"], xaxis_rotate=45)
bar

公司

有很多跟公司相关的字段,很好奇哪些公司现在招的实习生职位数量最多、公司规模如何、这些公司都是什么时候成立的、是不是最近几年新成立的公司占的比例比较大、哪些公司给的实习薪资高一些、哪些公司比较看重学历

公司与职位数量、平均实习月薪
  • 看看招聘职位数量前15名的公司都有哪些。发现了很多耳熟能详的大公司,比如说百度、滴滴、爱奇艺、头条、京东等
  • 还有一些比较陌生的,比如中科龙智、华院数据、非白三维、恒润科技、驭势科技、Rokid A-Lab等,这些公司都值得去了解一下
  • 这些公司中,今日头条的平均实习月薪最高,6400.5元,非白三维这家公司的实习月薪也不错,5150元,比某度好多了
data_clean.groupby('com_name').salary.agg(['count', 'mean']).sort_values(by='count', ascending = False)[:15]

 

 

 

公司规模与职位数量
  • 数据挖掘、机器学习的实习生的需求,是否是以大型企业为主导呢?
  • 发现并不是的,这方面的需求是以小中大型企业向下递减的,也间接说明了这个行业迅速发展的同时催生了很多中小企业吧

 

data_clean['num_employee'].value_counts()

 

 

公司规模与实习月薪
  • 我猜应该是大公司实习月薪高,小公司实习月薪低吧
  • 发现:我还是太天真了,结果刚好相反,小公司给的高,大公司给的低
  • 仔细想想好像也不无道理,大公司靠自己的名气吸引实习生,小公司没有名气,只能靠给更多的钱来吸引实习生了
data_clean.groupby('num_employee')['salary'].mean()

 

 

公司实习期长度
  • 发现大多数公司要求的是实习3个月和6个月,基本上都是实习三个月起
  • 平均实习期长度是五个半月
data_clean['time_span'].value_counts()

 

 

data_clean['time_span'].mean()

 

 

企业成立时间

刚好可以用企业成立时间验证一下猜想,也就是最近这个行业是否得到了迅速的成长,迅速成长的过程中,是否又催生了一大批的中小企业

  • 首先,因为计算的是企业的数量而不是职位的数量,所以要先drop掉重复的企业
  • 接着,把之前清理好的成立时间数据,再清理一下,以年做单位
  • 然后,以年分组计算数量,便得到每年新成立的公司数量
  • 发现:从2013年开始,公司呈现爆发式增长
est_date = data_clean.drop_duplicates(subset='com_name')
import warnings
warnings.filterwarnings('ignore')
est_date['est_year'] = pd.DatetimeIndex(est_date['est_date']).year
num_com_by_year = est_date.groupby('est_year')['com_name'].count()
line = pyecharts.Line("每年新成立的公司数量变化")
line.add("", num_com_by_year.index, num_com_by_year.values, mark_line=["max", "average"])
line

那新成立的企业中,企业规模怎么样?

  • 把数据以企业规模和成立年份分组计数
  • 发现2013年之后的爆发式增长中,主要以中小型企业为主
scale_VS_year = est_date.groupby(['num_employee', 'est_year'])['com_name'].count()
scale_VS_year_s = scale_VS_year['小型企业'].reindex(num_com_by_year.index, fill_value=0)
scale_VS_year_m = scale_VS_year['中型企业'].reindex(num_com_by_year.index, fill_value=0)
scale_VS_year_l = scale_VS_year['大型企业'].reindex(num_com_by_year.index, fill_value=0)

line = pyecharts.Line("新成立的企业与规模")
line.add("小型企业", scale_VS_year_s.index, scale_VS_year_s.values, is_label_show=True)
line.add("中型企业", scale_VS_year_m.index, scale_VS_year_m.values, is_label_show=True)
line.add("大型企业", scale_VS_year_l.index, scale_VS_year_l.values, is_label_show=True)
line

挑选实习公司

从以上的数据分析我们可以知道:

  1. 数据挖掘、机器学习算法岗位实习生的招聘,主要集中在“北上广深杭”这5个大城市
  2. 实习生的平均薪资为3644元人民币,“北上广深杭”这五个城市中,杭州的薪资最高,再者是北京、深圳
  3. 实习生学习以本科和硕士居多,并且这两者在实习薪资待遇上并没有太大的差别
  4. 互联网和计算机行业对于数据挖掘、机器学习算法岗位实习生需求是最多的,再者是金融、通信、电子行业
  5. 百度、滴滴、爱奇艺、头条、京东等大公司对该岗位的需求很多,另外还有中科龙智、华院数据、非白三维、恒润科技、驭势科技、Rokid A-Lab这些比较陌生的公司,对于该岗位的需求很多(应该是公司这方面的业务出于快速发展阶段)
  6. 大公司的实习薪资较少,小公司的薪资较多,不过差别不大
  7. 实习期以3个月或者6个月为主
  8. 从2013年开始,该行业的迅速发展催生了很多新的公司,主要以中小企业为主

这便是实习僧网站上,国内“机器学习算法实习生”岗位的一些基本情况。下面还有一个任务就是,挑选一些符合的公司,供投简历。 相关信息:

  • 深圳人
  • 硕士在读
  • 只能实习3个月
  • 薪资高于深圳平均实习薪资
  • 要求是最新发布的职位

最后剩下......鹅厂...... 那就鹅厂吧,把鹅厂的这3条记录提取出来

E_data = data_clean.loc[(data_clean['city'] == '深圳') & 
               (data_clean['job_academic'] != '博士') & 
               (data_clean['time_span'].isin([1,2,3])) & 
               (data_clean['salary'] > 3784) & 
               (data_clean['released_time'] == 'newest'), :]
E_data['com_name'].unique()

 

 

data.loc[E_data.index, ['job_title', 'job_links']]

 

 完整代码:

 

  1 import numpy as np
  2 import pandas as pd
  3 import matplotlib.pyplot as plt
  4 import seaborn as sns
  5 import pyecharts
  6 plt.style.use('ggplot')
  7 %matplotlib inline
  8 
  9 from pylab import mpl
 10 mpl.rcParams['font.sans-serif'] = ['SimHei']  #解决seaborn中文字体显示问题
 11 plt.rc('figure', figsize=(10, 10))  #把plt默认的图片size调大一点
 12 
 13 data_dm = pd.read_csv("datamining.csv")
 14 data_ml = pd.read_csv("machinelearning.csv")
 15 data_al = pd.read_csv("mlalgorithm.csv")
 16 data = pd.concat([data_dm, data_ml, data_al], ignore_index = True)
 17 
 18 data.sample(3)
 19 
 20 data.loc[666]
 21 
 22 data.info()
 23 
 24 data.drop_duplicates(subset='job_links', inplace=True)
 25 data.shape
 26 
 27 data_clean = data.drop(['com_id', 'com_links', 'com_location', 'com_website', 
 28                  'com_welfare', 'detailed_intro', 'job_detail'], axis = 1)
 29 
 30 data.auth_capital.sample(20)
 31 
 32 auth_capital = data['auth_capital'].str.split('', expand = True)
 33 auth_capital.sample(5)
 34 
 35 auth_capital['num'] = auth_capital[1].str.extract('([0-9.]+)', expand=False).astype('float')
 36 auth_capital.sample(5)
 37 
 38 auth_capital[1].str.split('', expand = True)[1].unique()
 39 
 40 def get_ex_rate(string):
 41     if string == None:
 42         return np.nan
 43     if '人民币' in string:
 44         return 1.00
 45     elif '' in string:
 46         return 0.80
 47     elif '美元' in string:
 48         return 6.29
 49     elif '欧元' in string:
 50         return 7.73
 51     elif '' in string:
 52         return 1.00
 53     else:
 54         return np.nan
 55     
 56 auth_capital['ex_rate'] = auth_capital[1].apply(get_ex_rate)
 57 auth_capital.sample(5)
 58 
 59 data_clean['auth_capital'] = auth_capital['num'] * auth_capital['ex_rate']
 60 data_clean['auth_capital'].head()
 61 
 62 data.day_per_week.unique()
 63 
 64 data_clean.loc[data['day_per_week'] == '2天/周', 'day_per_week'] = 2
 65 data_clean.loc[data['day_per_week'] == '3天/周', 'day_per_week'] = 3
 66 data_clean.loc[data['day_per_week'] == '4天/周', 'day_per_week'] = 4
 67 data_clean.loc[data['day_per_week'] == '5天/周', 'day_per_week'] = 5
 68 data_clean.loc[data['day_per_week'] == '6天/周', 'day_per_week'] = 6
 69 
 70 data.num_employee.unique()
 71 
 72 data_clean.loc[data['num_employee'] == '少于15人', 'num_employee'] = '小型企业'
 73 data_clean.loc[data['num_employee'] == '15-50人', 'num_employee'] = '小型企业'
 74 data_clean.loc[data['num_employee'] == '50-150人', 'num_employee'] = '小型企业'
 75 data_clean.loc[data['num_employee'] == '150-500人', 'num_employee'] = '中型企业'
 76 data_clean.loc[data['num_employee'] == '500-2000人', 'num_employee'] = '中型企业'
 77 data_clean.loc[data['num_employee'] == '2000人以上', 'num_employee'] = '大型企业'
 78 data_clean.loc[data['num_employee'] == '5000人以上', 'num_employee'] = '大型企业'
 79 data_clean.loc[data['num_employee'].isna(), 'num_employee'] = np.nan
 80 
 81 data.time_span.unique()
 82 
 83 mapping = {}
 84 for i in range(1,19):
 85     mapping[str(i) + '个月'] = i
 86 print(mapping)
 87 
 88 data_clean['time_span'] = data['time_span'].map(mapping)
 89 data_clean.head(3)
 90 
 91 data['wage'].sample(5)
 92 
 93 
 94 data_clean['average_wage'] = data['wage'].str.extract('([0-9.]+)-([0-9.]+)/天', expand=True).astype('int').mean(axis = 1)
 95 data_clean['average_wage'].head()
 96 
 97 data['est_date'].sample(5)
 98 
 99 
100 data_clean['est_date'] = pd.to_datetime(data['est_date'].str.extract('成立日期:([0-9-]+)', expand=False))
101 data_clean['est_date'].sample(5)
102 
103 
104 data['job_deadline'].sample(5)
105 
106 data_clean['job_deadline'] = pd.to_datetime(data['job_deadline'])
107 
108 data['released_time'].sample(5)
109 
110 data_clean['released_time'] = data['released_time'].str.extract('[0-9-]+(\w+)前', expand=False).map(
111     {'分钟':'newest', '小时':'newest', '':'new', '':'acceptable', '':'old'})
112 data_clean['released_time'].sample(5)
113 
114 data['update_time'].sample(5)
115 
116 data_clean['update_time'] = pd.to_datetime(data['update_time'])
117 
118 
119 data['city'].unique()
120 
121 data_clean.loc[data_clean['city'] == '成都市', 'city'] = '成都'
122 data_clean.loc[data_clean['city'].isin(['珠海市', '珠海 深圳', '珠海']), 'city'] = '珠海'
123 data_clean.loc[data_clean['city'] == '上海漕河泾开发区', 'city'] = '上海'
124 
125 data_clean['city'].value_counts().nlargest(10).plot(kind = 'bar')
126 
127 list(data['com_class'].unique())
128 
129 def get_com_type(string):
130     if string == None:
131         return np.nan
132     elif ('非上市' in string) or ('未上市' in string):
133         return '股份有限公司(未上市)'
134     elif '股份' in string:
135         return '股份有限公司(上市)'
136     elif '责任' in string:
137         return '有限责任公司'
138     elif '外商投资' in string:
139         return '外商投资公司'
140     elif '有限合伙' in string:
141         return '有限合伙企业'
142     elif '全民所有' in string:
143         return '国有企业'
144     else:
145         return np.nan
146 
147 com_class = data['com_class'].str.split('', expand = True)
148 com_class['com_class'] = com_class[1].apply(get_com_type)
149 com_class.sample(5)
150 
151 data_clean['com_class'] = com_class['com_class']
152 
153 data_clean = data_clean.reindex(columns=['com_fullname', 'com_name', 'job_academic', 'job_links', 
154                                          'tag','auth_capital', 'day_per_week', 'num_employee', 'time_span',
155                                          'average_wage', 'est_date', 'job_deadline', 'released_time',
156                                          'update_time', 'city', 'com_class', 'com_intro', 'job_title',
157                                          'com_logo', 'industry'])
158 data_clean.to_csv('/Users/apple/Desktop/shixiseng/data_clean.csv', index = False)
159 
160 data_clean.sample(3)
161 
162 data_clean.info()
163 
164 city = data_clean['city'].value_counts()
165 city[:15]
166 
167 bar = pyecharts.Bar('城市与职位数量')
168 bar.add('', city[:15].index, city[:15].values, mark_point=["max"])
169 bar
170 
171 city_pct = (city/city.sum()).map(lambda x: '{:,.2%}'.format(x))
172 city_pct[:15]
173 
174 (city/city.sum())[:5].sum()
175 
176 data_clean.loc[data_clean['city'] == '杭州', 'com_name'].value_counts()[:5]
177 
178 def topN(dataframe, n=5):
179     counts = dataframe.value_counts()
180     return counts[:n]
181 
182 data_clean.groupby('city').com_name.apply(topN).loc[list(city_pct[:15].index)]
183 
184 data_clean['salary'] = data_clean['average_wage'] * data_clean['day_per_week'] * 4
185 data_clean['salary'].mean()
186 
187 salary_by_city = data_clean.groupby('city')['salary'].mean()
188 salary_by_city.nlargest(10)
189 
190 top10_city = salary_by_city[city_pct.index[:10]].sort_values(ascending=False)
191 top10_city
192 
193 bar = pyecharts.Bar('北上广深杭等城市平均实习工资')
194 bar.add('', top10_city.index, np.round(top10_city.values, 0), mark_point=["max"], is_convert=True)
195 bar
196 
197 top10_city_box = data_clean.loc[data_clean['city'].isin(top10_city.index),:]
198 sns.violinplot(x ='salary', y ='city', data = top10_city_box)
199 
200 job_academic = data_clean['job_academic'].value_counts()
201 job_academic
202 
203 pie = pyecharts.Pie("学历要求")
204 pie.add('', job_academic.index, job_academic.values)
205 pie
206 
207 data_clean.groupby(['job_academic'])['salary'].mean().sort_values()
208 
209 sns.boxplot(x="job_academic", y="salary", data=data_clean)
210 
211 data_clean['industry'].sample(5)
212 
213 industry = data_clean.industry.str.split('/|,|,', expand = True)
214 
215 industry_top15 = industry.apply(pd.value_counts).sum(axis = 1).nlargest(15)
216 
217 bar = pyecharts.Bar('行业与职位数量')
218 bar.add('', industry_top15.index, industry_top15.values, 
219         mark_point=["max","min","average"], xaxis_rotate=45)
220 bar
221 
222 data_clean.groupby('com_name').salary.agg(['count', 'mean']).sort_values(by='count', ascending = False)[:15]
223 
224 data_clean['num_employee'].value_counts()
225 
226 data_clean.groupby('num_employee')['salary'].mean()
227 
228 data_clean['time_span'].value_counts()
229 
230 data_clean['time_span'].mean()
231 
232 est_date = data_clean.drop_duplicates(subset='com_name')
233 import warnings
234 warnings.filterwarnings('ignore')
235 est_date['est_year'] = pd.DatetimeIndex(est_date['est_date']).year
236 num_com_by_year = est_date.groupby('est_year')['com_name'].count()
237 line = pyecharts.Line("每年新成立的公司数量变化")
238 line.add("", num_com_by_year.index, num_com_by_year.values, mark_line=["max", "average"])
239 line
240 
241 scale_VS_year = est_date.groupby(['num_employee', 'est_year'])['com_name'].count()
242 scale_VS_year_s = scale_VS_year['小型企业'].reindex(num_com_by_year.index, fill_value=0)
243 scale_VS_year_m = scale_VS_year['中型企业'].reindex(num_com_by_year.index, fill_value=0)
244 scale_VS_year_l = scale_VS_year['大型企业'].reindex(num_com_by_year.index, fill_value=0)
245 
246 line = pyecharts.Line("新成立的企业与规模")
247 line.add("小型企业", scale_VS_year_s.index, scale_VS_year_s.values, is_label_show=True)
248 line.add("中型企业", scale_VS_year_m.index, scale_VS_year_m.values, is_label_show=True)
249 line.add("大型企业", scale_VS_year_l.index, scale_VS_year_l.values, is_label_show=True)
250 line
251 
252 E_data = data_clean.loc[(data_clean['city'] == '深圳') & 
253                (data_clean['job_academic'] != '博士') & 
254                (data_clean['time_span'].isin([1,2,3])) & 
255                (data_clean['salary'] > 3784) & 
256                (data_clean['released_time'] == 'newest'), :]
257 E_data['com_name'].unique()
258 
259 data.loc[E_data.index, ['job_title', 'job_links']]

 

 

 

 

五,总结

1,经过对数据的分析与可视化,可以得到以下结论

  • 首先,由于这篇文章的目的是给小E分析数据挖掘、机器学习算法实习生的需求情况,并且只爬了“实习僧”这一个网站,所以数据量比较小
  • 不过,数据的清洗和分析的套路还是差不多的
  • 由于前段时间了解到pyecharts这个画图神器,所以想在这里用一下。pyecharts画出来的图确实漂亮,不过总体感觉现在它跟pandas还是结合地不够好,用起来稍微有点繁琐,希望后面会越来越好越来越方便吧

 

posted @ 2021-06-26 16:23  無島  阅读(525)  评论(0编辑  收藏  举报