从数据清洗到可视化:用Pandas把Selenium爬到的8000条招聘数据变成你的行业洞察报告
当你用Selenium爬取到8000条招聘数据后,真正的挑战才刚刚开始。这些原始数据就像未经雕琢的玉石,只有经过专业的数据处理和可视化,才能展现出它们真正的价值。本文将带你从零开始,把杂乱无章的招聘数据转化为具有商业价值的行业洞察报告。
1. 数据清洗:从混乱到规范
拿到原始数据的第一件事不是急着分析,而是要进行彻底的数据清洗。招聘数据通常存在各种问题:缺失值、异常值、格式不统一等。以下是一个典型的数据清洗流程:
import pandas as pd # 读取爬取到的数据 df = pd.read_csv('job_data.csv', encoding='utf-8') # 查看数据概况 print(df.info()) print(df.head())1.1 处理缺失值
招聘数据中最常见的缺失值出现在薪资、工作经验和学历要求等字段。处理策略需要根据具体情况而定:
- 删除法:当缺失比例小于5%时,可以直接删除
- 填充法:对于数值型数据,可以用中位数填充;对于类别型数据,可以用众数填充
# 处理薪资缺失值 - 用该职位的中位数薪资填充 df['salary'] = df.groupby('position')['salary'].apply( lambda x: x.fillna(x.median()))1.2 薪资字段标准化
爬取到的薪资通常是"15k-30k"这样的字符串,我们需要将其转换为可计算的数值:
def parse_salary(salary_str): if 'k' in salary_str: parts = salary_str.replace('k', '').split('-') return (float(parts[0]) + float(parts[1])) / 2 return None df['avg_salary'] = df['salary'].apply(parse_salary)1.3 工作经验标准化
工作经验字段通常包含"1-3年"、"3-5年"等描述,我们可以将其转换为数值范围:
| 原始描述 | 转换后下限 | 转换后上限 |
|---|---|---|
| 不限 | 0 | 0 |
| 1年以下 | 0 | 1 |
| 1-3年 | 1 | 3 |
| 3-5年 | 3 | 5 |
| 5-10年 | 5 | 10 |
| 10年以上 | 10 | 20 |
2. 数据分析:挖掘数据背后的故事
清洗后的数据已经可以进行深入分析了。我们将从多个维度挖掘数据价值。
2.1 薪资分布分析
首先看看整体薪资分布情况:
import matplotlib.pyplot as plt plt.figure(figsize=(10, 6)) df['avg_salary'].plot(kind='hist', bins=20) plt.title('薪资分布直方图') plt.xlabel('月薪(k)') plt.ylabel('职位数量') plt.show()2.2 城市薪资对比
不同城市的薪资水平差异是求职者最关心的信息之一:
city_salary = df.groupby('city')['avg_salary'].agg(['mean', 'median', 'count']) city_salary = city_salary[city_salary['count'] > 50] # 只考虑样本量足够的城市 city_salary.sort_values('mean', ascending=False).head(10)2.3 技能需求分析
从职位描述中提取热门技能关键词:
from collections import Counter # 假设职位描述存储在'description'列 all_descriptions = ' '.join(df['description'].dropna().tolist()) words = [word.lower() for word in all_descriptions.split() if len(word) > 1] word_counts = Counter(words) # 排除常见无意义词 stop_words = ['的', '和', '等', '有', '相关', '优先'] for word in stop_words: word_counts.pop(word, None) word_counts.most_common(20)3. 高级分析:多维度交叉洞察
基础分析之后,我们可以进行更深入的交叉分析,发现更有价值的洞察。
3.1 薪资与经验的关系
exp_salary = df.groupby('experience')['avg_salary'].mean() exp_salary.plot(kind='bar', figsize=(10, 6)) plt.title('不同工作经验的平均薪资') plt.ylabel('平均月薪(k)') plt.xticks(rotation=45) plt.show()3.2 行业薪资对比
industry_salary = df.groupby('industry')['avg_salary'].agg(['mean', 'count']) industry_salary = industry_salary[industry_salary['count'] > 30] industry_salary.sort_values('mean', ascending=False).head(10)3.3 公司规模与薪资的关系
# 首先将公司规模标准化 def parse_company_size(size_str): if '人以下' in size_str: return 50 elif '500' in size_str and '1000' in size_str: return 750 # 其他情况类似处理... return None df['company_size_num'] = df['company_size'].apply(parse_company_size) # 然后分析关系 size_salary = df.groupby('company_size_num')['avg_salary'].mean() size_salary.plot(kind='line', marker='o', figsize=(10, 6)) plt.title('公司规模与平均薪资关系') plt.xlabel('公司规模(人)') plt.ylabel('平均月薪(k)') plt.show()4. 数据可视化:让数据说话
数据分析的最终目的是为了呈现洞察。好的可视化能让数据自己讲故事。
4.1 热力图:城市-行业薪资矩阵
import seaborn as sns # 准备数据 heatmap_data = df.pivot_table( index='industry', columns='city', values='avg_salary', aggfunc='mean' ) plt.figure(figsize=(12, 8)) sns.heatmap(heatmap_data, cmap='YlGnBu', annot=True, fmt=".1f") plt.title('各城市不同行业的平均薪资热力图') plt.xticks(rotation=45) plt.yticks(rotation=0) plt.show()4.2 箱线图:薪资分布对比
plt.figure(figsize=(12, 6)) sns.boxplot(x='city', y='avg_salary', data=df[df['city'].isin(top_cities)]) plt.title('主要城市薪资分布对比') plt.xticks(rotation=45) plt.ylabel('月薪(k)') plt.show()4.3 词云:热门技能需求
from wordcloud import WordCloud wordcloud = WordCloud( font_path='simhei.ttf', background_color='white', width=800, height=600 ).generate_from_frequencies(word_counts) plt.figure(figsize=(12, 8)) plt.imshow(wordcloud, interpolation='bilinear') plt.axis('off') plt.title('热门技能需求词云') plt.show()5. 构建完整的分析报告
将上述分析整合成一份专业的报告,建议包含以下部分:
- 执行摘要:1-2页,总结主要发现
- 方法论:数据来源、清洗和分析方法
- 主要发现:
- 整体薪资水平和分布
- 城市间薪资差异
- 热门技能需求
- 行业趋势
- 建议:基于数据的行动建议
- 附录:详细数据表格和方法说明
提示:使用Jupyter Notebook可以很方便地将分析代码、结果和说明文字整合在一起,导出为HTML或PDF报告。
在实际项目中,我发现最耗时的部分往往是数据清洗和标准化。特别是当数据来源多样时,统一各种格式需要花费大量精力。建议在爬取阶段就尽量规范化数据格式,可以节省后续很多时间。