BOSS直聘招聘数据分析的第一步:用Python进行深度清洗
在数据分析和数据挖掘过程中,数据清洗是确保分析结果准确性的重要步骤。本文以从 BOSS直聘 爬取的"测试工程师"职位数据为例(数据爬取详见上篇文章),介绍如何使用Python对爬取的数据进行清洗,确保数据质量,以便后续分析和建模。
数据清洗的目标与方法
在数据分析前,清洗数据的主要目标是确保数据的一致性和完整性。常见的清洗任务包括:
- 处理缺失值:填充或删除缺失数据。
- 删除重复数据:去除重复行,确保数据唯一性。
- 标准化字段格式:统一字段值的格式(如薪资范围、年限要求等)。
- 检测并处理异常值:去除不合理的数据点,减少对分析结果的干扰。
- 清洗文本数据:清理职位描述等文本字段,为后续的文本分析做好准备。
数据清洗的代码实现
在数据清洗中,我们按照以下思路进行逐步实现,并为每个步骤提供代码示例和详细说明。
1. 数据读取与缺失值处理
1.1 数据读取
数据存储在 Excel 文件中,我们使用 pandas.read_excel()
读取数据。
python
import pandas as pd
# 读取Excel数据
df = pd.read_excel('your_data.xlsx') # 替换为实际文件路径
1.2 检查缺失值
通过 isnull().sum()
检查每列的缺失值数量,了解缺失数据的分布情况。
python
# 检查缺失值分布
print("缺失值情况:")
print(df.isnull().sum())
1.3 填充或删除缺失值
根据字段的重要性和缺失值的性质,选择填充或删除策略。例如:
- 薪资描述 、公司名称 等字段:填充为空字符串
""
。 - 年限要求 、学历要求 等字段:填充为"未指定"或其他默认值。
- 缺失较多的数据行可以删除。
python
# 填充缺失值
df['薪资描述'].fillna("", inplace=True)
df['公司名称'].fillna("", inplace=True)
df['年限要求'].fillna("未指定", inplace=True)
df['学历要求'].fillna("未指定", inplace=True)
# 删除超过50%字段缺失的行
df.dropna(thresh=len(df.columns)*0.5, axis=0, inplace=True)
2. 重复数据处理
通过 duplicated()
检查数据是否存在重复行,删除多余数据以保证数据唯一性。
python
# 检查重复数据
duplicates = df.duplicated().sum()
print(f"重复行数量:{duplicates}")
# 删除重复行
df.drop_duplicates(inplace=True)
3. 数据格式标准化
在招聘数据中,字段值的格式往往不一致。以下代码标准化了薪资、年限和学历字段。
3.1 薪资描述的标准化
将薪资字段(如 "10k-15k" 或 "年薪15万元")统一为数字表示,并以区间中位数表示。
python
import re
def standardize_salary(salary):
"""标准化薪资描述为数值"""
if isinstance(salary, str):
salary = salary.strip()
# 匹配薪资范围(如 "10k-15k")
match = re.match(r'(\d+)(k|万)?-(\d+)(k|万)?', salary)
if match:
min_salary = int(match.group(1))
max_salary = int(match.group(3))
unit = 1000 if match.group(2) in ['k', 'K'] else 10000
return (min_salary + max_salary) * unit / 2
# 匹配单一薪资(如 "年薪15万")
match_annual = re.search(r'年薪(\d+)万', salary)
if match_annual:
return int(match_annual.group(1)) * 10000
return None # 返回None表示无法识别的薪资格式
# 应用薪资标准化函数
df['薪资描述'] = df['薪资描述'].apply(standardize_salary)
3.2 年限要求的标准化
统一年限格式(如 "1-3年" 转为平均年限,"3年以上" 转为单一值)。
python
def standardize_experience(experience):
"""标准化年限要求为数值"""
if isinstance(experience, str):
experience = experience.strip()
# 匹配年限范围(如 "1-3年")
match = re.match(r'(\d+)-(\d+)年', experience)
if match:
return (int(match.group(1)) + int(match.group(2))) / 2
# 匹配单一年限(如 "3年以上")
elif '年以上' in experience:
return int(experience.split('年')[0])
# 无经验或不限
elif '不限' in experience or '应届生' in experience:
return 0
return None
# 应用年限标准化函数
df['年限要求'] = df['年限要求'].apply(standardize_experience)
3.3 学历要求的标准化
将学历要求字段统一为规范格式,如 "本科"、"硕士" 等。
python
def standardize_education(education):
"""标准化学历要求"""
if isinstance(education, str):
if '本科' in education:
return '本科'
elif '硕士' in education:
return '硕士'
elif '博士' in education:
return '博士'
elif '大专' in education:
return '大专'
return '不限'
# 应用学历标准化函数
df['学历要求'] = df['学历要求'].apply(standardize_education)
4. 异常值检测
对数值字段(如薪资和年限)使用箱线图进行异常值检测,并删除不合理数据。
python
import matplotlib.pyplot as plt
# 绘制箱线图
plt.figure(figsize=(10, 6))
df['薪资描述'].plot(kind='box')
plt.title("薪资分布箱线图")
plt.show()
# 删除异常值(薪资低于3000或高于30000的职位)
df = df[(df['薪资描述'] >= 3000) & (df['薪资描述'] <= 30000)]
5. 文本数据清洗
对岗位描述等文本字段,去除符号和空格,并进行分词处理。
python
import jieba
def clean_text(text):
"""清洗文本数据"""
text = re.sub(r'[^\w\s]', '', text) # 去除符号
return " ".join(jieba.cut(text)) # 分词处理
# 应用文本清洗函数
df['岗位要求'] = df['岗位要求'].apply(clean_text)
6. 结果检查与保存
清洗完成后,可以检查清洗后的数据并保存为新的 Excel 文件。
python
# 查看清洗后的数据
print("清洗后的数据:")
print(df.head())
# 保存清洗后的数据
df.to_excel('cleaned_job_data.xlsx', index=False)
完整实现代码示例
python
import pandas as pd
import re
import numpy as np
def standardize_salary(salary):
"""标准化薪资数据,转换为数值形式"""
if isinstance(salary, str):
salary = salary.strip()
# 匹配薪资范围,如"6-9K"
match = re.match(r'(\d+)-(\d+)(K|k|万)?', salary)
if match:
min_salary = int(match.group(1)) * (1000 if match.group(3).lower() == 'k' else 10000)
max_salary = int(match.group(2)) * (1000 if match.group(3).lower() == 'k' else 10000)
return (min_salary + max_salary) / 2 # 取区间的平均值
# 匹配年薪格式,如"年薪15万·14薪"
match_annual = re.match(r'(\d+)-(\d+)(K|k)?[\s·]*(\d+)薪', salary)
if match_annual:
base_salary = int(match_annual.group(1)) * (1000 if match_annual.group(3).lower() == 'k' else 10000)
extra_salary = int(match_annual.group(2)) * (1000 if match_annual.group(3).lower() == 'k' else 10000)
extra_months = int(match_annual.group(4))
return (base_salary + extra_salary) * extra_months / 12 # 按年薪计算
# 处理其他情况,如"10K"或"15万"
match_single = re.match(r'(\d+)(K|k|万)?', salary)
if match_single:
return int(match_single.group(1)) * (1000 if match_single.group(2).lower() == 'k' else 10000)
# 其他无效的薪资格式返回NaN
return np.nan
return np.nan
def standardize_experience(experience):
"""标准化年限数据,转换为数值"""
if isinstance(experience, str):
experience = experience.strip()
# 匹配年限范围,如"1-3年"
match = re.match(r'(\d+)-(\d+)年', experience)
if match:
return (int(match.group(1)) + int(match.group(2))) / 2 # 取年限区间的中位数
# 匹配"经验不限"
if '经验不限' in experience:
return 0 # 经验不限时认为是0年
# 匹配"应届生"
if '应届生' in experience:
return 0 # 应届生视为0年经验
# 匹配"大于5年"等描述
match_greater_than = re.match(r'(\d+)年.*以上', experience)
if match_greater_than:
return int(match_greater_than.group(1)) # 返回最小年限
# 无法匹配的返回NaN
return np.nan
return np.nan
def standardize_education(education):
"""标准化学历要求"""
if isinstance(education, str):
education = education.strip().lower()
# 处理本科以上,本科及其他
if '本科' in education:
return '本科'
elif '硕士' in education:
return '硕士'
elif '博士' in education:
return '博士'
elif '大专' in education:
return '大专'
else:
return '不限'
return '不限'
def standardize_company_size(size):
"""标准化公司规模,清理异常值"""
if isinstance(size, str):
size = size.strip()
# 匹配数字
match = re.match(r'(\d+)', size)
if match:
size_num = int(match.group(1))
if size_num < 10 or size_num > 100000:
return np.nan # 异常的公司规模
return size_num
return np.nan
def clean_job_data(df):
"""对招聘数据进行清洗"""
# 薪资描述清洗
df['薪资描述'] = df['薪资描述'].apply(standardize_salary)
df = df[(df['薪资描述'] >= 3000) & (df['薪资描述'] <= 30000)] # 薪资限制
# 年限要求清洗
df['年限要求'] = df['年限要求'].apply(standardize_experience)
df = df[(df['年限要求'] >= 0) & (df['年限要求'] <= 40)] # 年限限制
# 学历要求清洗
df['学历要求'] = df['学历要求'].apply(standardize_education)
# 公司规模清洗
df['公司规模'] = df['公司规模'].apply(standardize_company_size)
# 返回清洗后的数据
return df
# 使用示例
if __name__ == "__main__":
df = pd.read_excel('jobs.xlsx') # 假设你已经爬取的数据存储在此文件中
cleaned_df = clean_job_data(df)
cleaned_df.to_excel('cleaned_job_data.xlsx', index=False) # 保存清洗后的数据
清洗后的数据
总结
上述代码实现了以下功能:
- 缺失值处理:对缺失值进行了合理的填充或删除。
- 重复数据处理:删除了重复的行。
- 数据格式标准化:薪资、年限、学历等字段进行了标准化。
- 异常值检测:通过箱线图检测并删除了异常的薪资数据。
- 文本数据清洗:对岗位描述、任职要求进行了文本清洗和分词处理。
清洗后的数据更加规范和一致,为后续的数据分析和建模打下了坚实基础。完整代码已附上,欢迎试用并根据需求进行优化!