ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

全国岗位招聘数据分析与可视化:Python大作业高分指南

全国岗位招聘数据分析与可视化:Python大作业高分指南 简介面向高校数据相关专业学生与初学者的全国岗位招聘数据分析与可视化毕业设计/期末大作业项目97分高分设计覆盖数据采集、清洗、分析与可视化全流程解决课程设计选题难、代码注释少、无法运行等问题。zip压缩包共56个文件13个Python脚本负责爬虫采集与可视化逻辑10个HTML页面用于结果展示多张PNG/JPG图片直观呈现图表效果另含配置文件、说明文档与依赖安装脚本包体8.55MB目录结构清晰便于按模块学习与二次开发。代码注释详细小白也可读懂下载即可运行同时配有完整源码与文档可帮助理解岗位招聘数据的分布规律与热门行业趋势也可作为答辩汇报和课程展示的参考素材。目前已有544人学习浏览适合课程设计、期末大作业参考帮助快速完成完整项目交付。1. 为什么把“全国岗位招聘数据分析与可视化”做成Python大作业最容易拿高分全国岗位招聘数据用在Python数据分析与可视化大作业里不是新瓶装旧酒而是因为它同时踩中了“业务真实、数据脏、字段多、结果直观”四个点。相比鸢尾花、房价这类练手数据招聘数据需要你处理薪资区间、城市别名、岗位名称不规范等问题清洗过程本身就占评分权重。再加上题目里明确写了“源码 文档”意味着评卷老师要看你从数据到结论的完整链路爬虫或数据下载、pandas清洗、统计分析、pyecharts出图每一步都要有对应代码和输出。这篇博客按“数据准备 → 分析 → 可视化 → 文档生成”的顺序把这条链路里最常用、也最容易拿分的技术方案讲清楚你可以直接对照着改数据、改字段名做成自己的高分项目。2. 数据准备全国岗位招聘数据的采集与清洗方案2.1 原始数据获取先定合规路径再选择爬虫脚本大作业最常见的问题是拿到数据后不知道字段含义。先不要急着写爬虫建议去公开数据集平台找“全国招聘数据”或“岗位薪资数据”常见格式是CSV或JSON字段通常包括岗位名称、公司、城市、薪资、学历要求、工作经验、发布时间。这类数据结构清晰拿到手就能接上pandas。如果一定要自己爬只爬招聘网站的公开搜索接口遵守对方robots协议控制请求频率并只在课程学习场景下使用。下面是一个针对JSON接口的通用爬虫框架重点是先拿到原始数据并落盘而不是边爬边清洗。import requests import pandas as pd import time def fetch_jobs(keyword, city, page_start, page_end): rows [] for page in range(page_start, page_end): url https://example.com/api/search params { keyword: keyword, city: city, page: page, page_size: 50 } headers {User-Agent: Mozilla/5.0 (study project)} resp requests.get(url, paramsparams, headersheaders, timeout10) if resp.status_code ! 200: print(fpage {page} failed: {resp.status_code}) continue data resp.json() for item in data.get(items, []): rows.append(item) time.sleep(1) return pd.DataFrame(rows) df fetch_jobs(数据分析, 全国, 1, 5) df.to_csv(raw_jobs.csv, indexFalse, encodingutf-8-sig)代码逻辑说明每次请求以页码和搜索词作为参数返回的JSON里items是岗位列表。把每页的items累加到rows中最后转成DataFrame。time.sleep(1)做限速避免高频请求被拒绝。参数city传“全国”时部分平台会返回所有城市数据如果拿不到可以改为遍历几个主要城市再纵向拼接。参数说明keyword是搜索关键词city是城市page_start和page_end控制页码范围page_size按接口允许最大值设置建议50或100。headers里的User-Agent要写真实一点很多接口会拦截默认Python请求头。如果接口返回的是HTML而不是JSON可以先用pandas.read_html()解析表格型页面省去写正则的时间。2.2 字段设计与薪资区间清洗把文本变成可计算数字拿到原始数据后先做字段探查。以一个典型招聘数据集为例原始字段与清洗后字段的对应关系如下。原始字段清洗后字段清洗规则positionNamejob_title去除首尾空格workYearexperience归一化为“1-3年”“3-5年”等salarysalary_min / salary_max / salary_avg解析“12k-18k”“20k以上”citycity_name统一“北京”“北京市”为“北京”educationeducation归一化为“硕士”“本科”“专科”companySizecompany_size映射为“少于50人”“50-200人”等job_detailskill_list后接技能词典匹配薪资清洗是很多项目失败的重灾区。salary字段通常是字符串比如“12k-18k”“20k以上”“面议”“6-8千”。必须先把它们拆成统一格式否则后续求均值、画图都会报错或失真。import re def parse_salary(s): if not isinstance(s, str): return None, None, None s s.lower().replace(k, ).replace(,, ).strip() if 面议 in s: return None, None, None if 以上 in s: low float(re.sub(r[^0-9.], , s.split(以上)[0])) return low, None, low nums re.findall(r\d\.?\d*, s) if len(nums) 2: low, high float(nums[0]), float(nums[1]) return low, high, (low high) / 2 if len(nums) 1: return float(nums[0]), None, float(nums[0]) return None, None, None df[salary_min], df[salary_max], df[salary_avg] zip(*df[salary].apply(parse_salary)) df_salary df.dropna(subset[salary_avg])代码逻辑说明parse_salary接收原始薪资字符串先统一小写并去掉千分位逗号。“20k以上”会被拆成low20high为空平均取20“12k-18k”取出两个数字平均15面议返回三个None最终用dropna过滤。得到的salary_avg单位是k后续所有统计和可视化都基于这个字段。参数说明s.split(以上)[0]用于提取“以上”前的数字re.sub(r[^0-9.], , ...)把“15k”中的k等字符去掉。如果薪资写成“6-8千”单位不是k计算前需要先判断单位并换算。实际作业里可以加一个单位判断代码会更完整。2.3 清洗结果验证用describe和空值分布确认数据可用数据清洗完不能直接做分析。先跑两条检查命令print(df_salary[[salary_avg, salary_min, salary_max]].describe()) print(df_salary.isnull().sum())第一条输出count、mean、min、max。如果salary_avg的mean偏离正常人认知说明单位没统一如果count比原始数据少很多说明面议占比高。第二条查看每列缺失值city不能有大量空值否则后续地图没法画。检查通过后再做一次简单的分布确认用pandas内置直方图import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False df_salary[salary_avg].hist(bins30) plt.xlabel(薪资区间(k)) plt.ylabel(岗位数量) plt.show()这里的SimHei字体设置是为了解决中文乱码axes.unicode_minus解决负号显示为方块的问题。直方图如果呈右偏分布即高薪岗位少、低薪岗位多属于正常。如果出现多个孤立尖峰要考虑是不是某些城市的高薪数据混入后面分析时需要按城市分组观察。这一步的截图建议放进取证文档评阅老师能一眼看到你做了数据体检。很多人直接从原始数据跳到饼图中间缺失清洗验证评分会低一档。3. 数据分析从技能需求到薪资分布的建模分析3.1 用Pandas做城市、岗位、学历的聚合统计拿到干净数据后先回答最宏观的问题哪些城市岗位最多哪些城市平均薪资最高用groupby加agg一次完成。city_stats ( df_salary.groupby(city_name) .agg( job_count(job_title, count), avg_salary(salary_avg, mean), median_salary(salary_avg, median) ) .reset_index() ) print(city_stats.sort_values(job_count, ascendingFalse).head(10))代码逻辑说明groupby按city_name分组agg里用count计算岗位数量mean和median计算平均薪资与中位数薪资。中位数比平均值更抗极端值部分城市少数高薪岗位会拉高均值中位数更能代表普遍水平。reset_index让分组键变回普通列方便后续合并或绘图。参数说明agg可以同时计算多个统计量每个统计量是二元组列名加聚合函数。job_count是新增列名。如果觉得groupby写起来长可以换成df_salary.pivot_table(indexcity_name, valuessalary_avg, aggfunc[count, mean])但列名会变成多层后续操作更麻烦所以这里优先用agg。接下来做学历与经验的交叉分析。用pd.crosstab查看两个分类变量的频次表。df_salary[exp_group] df_salary[experience].replace({ 经验1-3年: 1-3年, 经验3-5年: 3-5年, 经验5-10年: 5-10年, 经验10年以上: 10年, 经验不限: 不限, 无经验: 1年以内 }) cross pd.crosstab(df_salary[exp_group], df_salary[education]) print(cross)不同平台对经验字段的写法不同这里用replace字典统一为几个区间。crosstab输出的行、列分别是经验分组和学历要求单元格值为岗位数量。如果数据量大可以直接用style.background_gradient变成热力图样式的表格截图放进文档。把聚合结果整理成下面这样的表格是报告里最直观的展示方式。城市岗位数量平均薪资(k)北京234118.6上海198717.9深圳168817.2杭州120415.8这份表格来自city_stats的前几行后续分析章节的小标题就可以围绕“岗位量Top5城市”“平均薪资Top5城市”展开。3.2 岗位技能关键词的提取与词频统计技能分析是招聘数据分析里最能体现区分度的模块。很多人直接对JD做jieba分词统计词频后全是“负责”“工作”“团队”这类无关词。更好的做法是维护一份技能词典然后用str.contains匹配。skill_dict [python, sql, excel, spark, hadoop, flink, 机器学习, 深度学习, 数据分析, 数据挖掘, tableau, powerbi] def count_skills(text): if not isinstance(text, str): return text text text.lower() return [skill for skill in skill_dict if skill in text] df_salary[skill_list] df_salary[job_detail].apply(count_skills) all_skills [] for skills in df_salary[skill_list]: all_skills.extend(skills) skill_series pd.Series(all_skills).value_counts() print(skill_series.head(10))代码逻辑说明count_skills遍历skill_dict如果技能关键词出现在job_detail字符串中就把它加入列表。最后把所有岗位的技能列表打平用value_counts统计频次。这样得到的skill_list是Python列表列后续还能做“同时会Python和SQL的岗位占比”这类筛选。参数说明text.lower()让匹配不区分大小写所以“SQL”和“sql”都能命中。如果想更精确可以把skill_dict里的词写成正则例如rpython、r\bsql\b但简单in匹配在招聘场景下已经够用因为技能名大多是完整单词。如果只统计单词频老师会觉得深度不够可以加一个共现分析。from itertools import combinations def count_cooccur(skills): return list(combinations(sorted(skills), 2)) co_list [] for sk in df_salary[skill_list]: if len(sk) 2: co_list.extend(count_cooccur(sk)) co_series pd.Series(co_list).value_counts().head(10) print(co_series)这段代码统计“pythonsql”“excelsql”这类组合出现的次数。企业招聘要求的通常不是单点技能而是一组能力把这个结果用横向柱状图画出来比词云更有说服力。假如出现了“pythonspark”排在前面就能顺理成章得出“数据分析岗位开始要求大数据工具”的结论。3.3 薪资影响因素用交叉表和相关系数做初步筛选薪资受学历、经验、城市、公司规模共同影响。先做单因素预判找出影响最大的字段。edu_salary df_salary.groupby(education)[salary_avg].agg([mean, median, count]) print(edu_salary) exp_salary df_salary.groupby(exp_group)[salary_avg].agg([mean, median, count]) print(exp_salary)如果edu_salary显示“不限”学历的薪资均值高于“本科”很可能是该组数据量太少要去查count列。count低于30的分组一般不具备统计意义后续分析时可以直接过滤掉。对于数值型变量可以算相关系数矩阵。学历、城市这类分类变量不能直接corr需要先做数值映射。df_salary[edu_year] df_salary[education].map({硕士: 3, 本科: 2, 专科: 1, 不限: 0}) df_salary[city_tier] df_salary[city_name].apply( lambda x: 3 if x in [北京, 上海, 广州, 深圳] else (2 if x in [杭州, 成都, 南京, 武汉, 西安] else 1) ) corr_data df_salary[[salary_avg, edu_year, city_tier]].corr() print(corr_data)map把教育文字转为年限apply把城市按一线、新一线、其他分级。pandas的corr默认计算皮尔逊相关系数。若salary_avg与edu_year的相关系数在0.15以上说明学历与薪资存在正相关报告里可以写“学历每提升一档平均薪资增长约为xx”具体数值再去分组mean里看。city_tier跟薪资的相关系数通常不会太高因为一线城市岗位多但基层岗位也多需要看分组平均薪资而不是相关系数。注意这里是探索性分析不是因果模型。文档里写“存在相关性”而不是“影响”避免答辩时被追问逻辑漏洞。4. 数据可视化用Pyecharts做出能放上答辩屏的大屏4.1 全国地图岗位数量与平均薪资的双重展示用pyecharts出图前先安装依赖。pip install pyecharts地图组件需要省份名补齐pyecharts新版内置了中国地图文件。先做一个全国岗位数量地图。from pyecharts.charts import Map from pyecharts import options as opts province_map {北京: 北京, 上海: 上海, 广州: 广东, 深圳: 广东} df_salary[province] df_salary[city_name].map(lambda x: province_map.get(x, x)) province_data df_salary.groupby(province)[salary_avg].agg([count, mean]).reset_index() data_pair list(zip(province_data[province], province_data[count])) map_chart ( Map() .add(岗位数量, data_pair, maptypechina) .set_global_opts( title_optsopts.TitleOpts(title全国岗位招聘数量分布), visualmap_optsopts.VisualMapOpts( min_0, max_int(province_data[count].max()) ) ) ) map_chart.render(output/岗位数量地图.html)代码逻辑说明Map.add接收一个二元组列表第一项是省份名第二项是数值。visualmap_opts设置颜色映射范围min和max按数据分布手动设置否则颜色衰减会很奇怪。render输出独立html文件浏览器打开即可不需要Jupyter环境。参数说明maptypechina表示中国地图如果省份名写错地图上会有一块空白。岗位数量地图展示绝对量适合看就业机会集中度。把data_pair第二项换成mean就能做平均薪资地图但salary_avg量纲是k数值小visualmap的max要相应调小。表格配色可以用地图自带的visualmap但更常见的是配合主题一起调整。下面这些主题是作业里高频使用的。主题名色调适用场景ThemeType.WHITE白底黑字文档截图ThemeType.INFERNO深色渐变会议室大屏ThemeType.MACARONS浅粉/浅蓝校园答辩PPTThemeType.ROMANTIC粉紫渐变女性向行业数据4.2 从静态图到数据可视化大屏Bar、Line和Tab的组合大作业加分项是做数据可视化大屏。Pyecharts本身不叫大屏但可以用Tab、Grid、Bar、Line、Pie组合成多图HTML页面答辩演示完全够用。下面是一个城市平均薪资Top10的柱线组合图左边柱状图显示平均薪资右边折线图显示岗位数量。from pyecharts.charts import Bar, Line, Grid from pyecharts import options as opts top10 city_stats.sort_values(avg_salary, ascendingFalse).head(10) top10 top10.sort_values(avg_salary) bar ( Bar() .add_xaxis(top10[city_name].tolist()) .add_yaxis(平均薪资(k), top10[avg_salary].round(2).tolist(), category_gap40%) .set_global_opts( title_optsopts.TitleOpts(title城市平均薪资Top10), yaxis_optsopts.AxisOpts(namek), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate30)) ) ) line ( Line() .add_xaxis(top10[city_name].tolist()) .add_yaxis(岗位数量, top10[job_count].tolist(), yaxis_index1) ) grid ( Grid(init_optsopts.InitOpts(width900px, height500px)) .add(bar, grid_optsopts.GridOpts(pos_left10%, pos_right35%)) .add(line, grid_optsopts.GridOpts(pos_left10%, pos_right35%)) ) grid.render(output/城市薪资与岗位数量组合图.html)代码逻辑说明先按平均薪资倒序排序取Top10再升序排列让柱状图从低到高显示。Bar是主图Line挂到第二个y轴上yaxis_index1表示使用右侧坐标轴。Grid把两个图叠加到同一坐标系适合展示量纲不同的两个指标。参数说明category_gap40%控制柱子间距太窄会显得拥挤rotate30让城市名倾斜避免横轴文字重叠。右侧y轴需要额外加yaxis_opts否则Line的刻度会沿用左侧“k”单位导致数值显示异常。如果要把多个图放进一个页面用Page更简单。from pyecharts.charts import Page page Page(layoutPage.SimplePageLayout) page.add(map_chart, grid) page.render(output/招聘数据看板.html)Page.SimplePageLayout会把组件按顺序排列比Grid逐像素调位置快很多。整页作为数据可视化大屏汇报时配合深色背景会更完整。4.3 配色与交互参数评阅老师会在意的高频设置pyecharts默认图不丑但全局参数不调会显得不专业。最少要调整以下四项。init_opts里的width和height地图建议宽900柱状图宽1000避免坐标轴文字被截断。theme切换主题可以快速改变整体风格。datazoom分类多时加缩放滑块让图表在小屏幕上也能查看。tooltip的trigger柱状图和折线图用axis地图和饼图用item。带theme和datazoom的完整示例from pyecharts.globals import ThemeType city_rank city_stats.sort_values(job_count, ascendingFalse).head(20) bar2 ( Bar(init_optsopts.InitOpts(themeThemeType.INFERNO, width1000px, height500px)) .add_xaxis(city_rank[city_name].tolist()) .add_yaxis(岗位数量, city_rank[job_count].tolist()) .set_global_opts( title_optsopts.TitleOpts(title城市岗位数量Top20), datazoom_opts[opts.DataZoomOpts(range_start0, range_end100)] ) ) bar2.render(output/岗位数量Top20.html)ThemeType.INFERNO是深色主题适合放在大屏背景里。datazoom开启后图下方会出现缩放滑块数据超过20个城市时滑块自动生效范围默认0到100即全部展示。如果地图中某个省份因名称不对显示空白检查省份名是否用了全称。比如“广西壮族自治区”在pyecharts中可能识别不出来统一使用“广西”这类标准简称。这个排查过程也可以写进文档的疑难部分展示排错能力。5. 一键把分析结果变成答辩文档源码 文档的打包技巧5.1 用nbconvert把Notebook转成Markdown和HTML在Jupyter Notebook里把代码、分析结论、图表串联成一个故事线然后统一导出。jupyter nbconvert --to markdown --output-dir docs 全国招聘数据分析.ipynb jupyter nbconvert --to html --output-dir docs 全国招聘数据分析.ipynbmarkdown文件方便后续在Typora调整格式html可以直接作为答辩演示。导出前需要确保所有cell按顺序执行过最好重启kernel全部重新跑一遍避免图表为空。5.2 补全README和requirements.txt提交源码文档时评阅老师第一个打开的是README。内容至少包括项目简介、数据来源、运行环境、目录结构、功能说明五部分。环境准备部分可以链接到python安装教程明确建议Python 3.9以上并写清依赖包版本。pip freeze requirements.txt之后手动精简requirements只保留核心依赖。pandas1.4.0 matplotlib3.5.0 jieba0.42.1 pyecharts1.9.0pyecharts 1.x和2.x的接口有一些差异文档里一定要写清自己用的是哪个版本。加上版本号的好处是老师只要按requirements装环境就能复现你的全部结果。5.3 一键执行脚本从数据清洗到报告生成全链路把清洗、分析、可视化、文档导出串成一个脚本能有效避免“数据改了一版但报告没更新”的问题。python 01_data_clean.py python 02_analysis.py python 03_visualization.py jupyter nbconvert --execute --to html 全国招聘数据分析.ipynb最后的nbconvert加上--execute参数让Notebook在导出前重新执行所有代码块。这能保证提交的html是“所见即所得”而不是手动漏跑后的残缺版本。同时把每次运行生成的csv和html都放到output目录文档里用相对路径引用图片。整个项目压缩后换到其他电脑解压路径仍然有效这也是高分项目里容易被忽略但分值很实在的小细节。本文还有配套的精品资源点击获取
返回列表