#%% md
## 类库导入
#%%
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.array((pd, np, plt))
#%% md
## 数据加载
#%%
data = pd.read_csv(r'I:\AIoT智能物联网工程师\AIoT智能物联网\Python数据分析\综合项目实战\课程资料\数据分析综合项目实战\job.csv') # 读取数据
print(data.shape) # 数据结构 行,列
np.array(data.columns).reshape((-1, data.shape[1])) # 水平列(字段) | reshape水平显示
#%%
city_items = data.city.unique() # 城市(去重)
city_items.reshape((-1, city_items.shape[0]))
#%%
# 只取部分字段
column_items = ["positionName", "companyShortName", "city", "companySize", "education", "financeStage", "industryField", "salary", "workYear","companyLabelList", "job_detail"] # 不能元祖
data = data[column_items].drop_duplicates() # drop_duplicates 去重
print(data.shape)
data.head() # 显示前5条
#%% md
## 数据清洗
#%% md
### 提取数据分析师数据
#%%
cond = data.positionName.str.contains('数据分析') # positionName(职位名)中含有 "数据分析" 关键字 | str对每一个字段值进行判断运算 | [True/False]
data = data[cond]
print(data.shape)
data.tail()
#%%
data = data.reset_index(drop=True) # 重置索引
data.tail()
#%% md
### 薪资处理
#%%
# 当出现范围情况 需要计算平均值 不然是字符串 难以计算
salary = data.salary.str.lower() # 将值的英文字母部分全部转为小写,方便处理
salary.head()
#%%
salary = salary.str.extract(r'(\d+)k-(\d+)k') # 正则处理获取数值 | 根据正则提取
salary = salary.applymap(lambda _: int(_)) # 值转为整型(用于计算)
salary.head()
#%%
data.salary = salary.mean(axis=1) # axis=1 水平算 默认垂直 | 注意, 当前值已经不是字符串是数值, 没有 str
data.head()
#%% md
### 岗位技能
#%%
job_detail = data.job_detail
job_detail = job_detail.str.lower() # 统一变成小写
job_detail = job_detail.fillna('') # 将缺失值的赋值为空字符串
#%% md
从 job_detail 中提取出技能要求 将技能分为以下几类:
+ Python
+ SQL
+ Tableau
+ Excel
+ SPSS/SAS
#%%
job_detail_items = [
# (类型, 对应类的处理函数 | 返回1存在,0不存在) | 注意判断使用 in 匹配值需要全小写
('Python', lambda _: 1 if ('python' in _) else 0),
('SQL', lambda _: 1 if ('sql' in _) or ('hive' in _) else 0), # SQL与hive一回事, hive数据量更大
('Tableau', lambda _: 1 if ('tableau' in _) else 0),
('Excel', lambda _: 1 if ('excel' in _) else 0),
('SPSS/SAS', lambda _: 1 if ('spss' in _) or ('sas' in _) else 0),
]
for (k, m) in job_detail_items:
data[k] = job_detail.map(m) # 注意!! 这里需要使用已经处理过的 job_detail 进行 map
data.head()
#%% md
### 行业信息
#%%
# industryField/industryLables
industryField = data.industryField
def clean_industry(_):
_ = _.split(',') # 字符串切割
return _[1] if (_[0] == '移动互联网' and len(_) > 1) else _[0]
data.industryField = industryField.map(clean_industry)
data.head()
#%% md
## 综合指标分析
#%% md
### 各城市对数据分析岗位的需求量
#%%
city_items_count = data.city.value_counts() # 统计城市工作数量 | 统计技术
pd.DataFrame(dict(count=city_items_count)).T
#%%
# 查看电脑自带字体
from matplotlib.font_manager import FontManager
fm = FontManager()
np.array([font.name for font in fm.ttflist])
#%%
# 图表设置全局参数 (字体正常显示)
plt.rcParams['font.family'] = plt.rcParams['font.sans-serif'] = 'SimHei' # 设置字体 国标黑体中文字体
plt.rcParams['axes.unicode_minus'] = False ## 设置正常显示符号a
#%%
np.array(city_items_count.index).reshape(-1, city_items_count.index.shape[0]) # 索引
#%%
np.array(city_items_count.values).reshape(-1, city_items_count.values.shape[0]) # 值
#%%
# 两种常用颜色:浅蓝色: #3c7f99 ,淡黄色:#c5b783
plt.figure(figsize=(12, 9)) # 设置图标尺寸
# 条形图(水平)
plt.barh(
# y=city_items_count.index, # 数据左侧 | 数据颠倒 默认数据从从大到小 | 绘制时是从下往上(从大到小)
# width=city_items_count.values,
y=city_items_count.index[::-1], # 数据左侧 | 数据颠倒 默认数据从从小到大 | 虽然输出时是从大到小
width=city_items_count.values[::-1], # 数据宽度
color='#3c7f99'
)
plt.box(False) # 不显示边框
plt.title(
label= '各城市对数据分析岗位的需求量',
fontsize=32, weight='bold', color='white',
backgroundcolor='#c5b783', pad=30, # pad 标题与图标距离
)
plt.tick_params(labelsize=16) # 刻度设置 字体设置
plt.grid(axis='x', linewidth=0.5, color='#3c7f99') # 设置x轴坐标网格线 linewidth 水平
#%% md
### 不同领域对数据分析岗的需求量
#%%
industryField_items_count = data.industryField.value_counts()[:10] # 只需要前10
industryField_items_count
#%%
# 两种常用颜色:浅蓝色: #3c7f99 ,淡黄色:#c5b783
plt.figure(figsize=(12, 9)) # 设置图标尺寸
# 条形图(水平)
plt.barh(
y=industryField_items_count.index[::-1], # 数据左侧 | 数据颠倒 默认数据从从大到小 | 绘制时是从下往上(从大到小)
width=industryField_items_count.values[::-1], # 数据宽度
color='#3c7f99'
)
plt.box(False) # 不显示边框
plt.title(
label= '不同领域对数据分析岗的需求量(前10)',
fontsize=32, weight='bold', color='white',
backgroundcolor='#c5b783', pad=30, # pad 标题与图标距离
)
plt.tick_params(labelsize=16) # 刻度设置 字体设置
plt.grid(axis='x', lw=0.5, color='#3c7f99', ls='--') # 设置x轴坐标网格线 linewidth(lw) 水平 | ls 线样式
#%% md
### 各城市薪资状况
#%%
# 需要分组并聚合运算
city_items_salary = data.groupby('city').salary.mean().sort_values() # 根据城市分组 并且拿到薪资(上面数据清洗已计算平均数) 进行 各城市的平均数计算 排序数据(默认从小到大)
city_items_salary
#%%
plt.figure(figsize=(12, 9))
plt.bar(
x=city_items_salary.index, # 标尺
height=city_items_salary.values, # 数据
color=plt.cm.RdBu_r(np.linspace(0, 1, len(city_items_salary))) # 渐变颜色 | 多少个城市就多少份
)
plt.title(
label='各城市薪资状况',
fontsize=32, weight='bold', color='white', backgroundcolor='#3c7f99'
)
plt.tick_params(labelsize=16)
plt.grid(axis='y', lw=0.5, color='black')
plt.yticks(ticks=np.arange(0, 25, step=5,), labels=('', '5K', '10K', '15k', '20K'))
plt.box(False)
#%% md
### 工作经验与薪水关系
#%%
# 需要透视表 分组聚合
work_salary = data.pivot_table(
index='city',
columns='workYear',
values='salary'
)
work_salary.fillna('')
work_salary_coumns = ['应届毕业生', '1-3年', '3-5年', '5-10年']
work_salary[work_salary_coumns]
#%%
work_salary = work_salary[work_salary_coumns].sort_values(by='5-10年', ascending=False) # 筛选部分工作经验 | ascending 降序
work_salary
#%%
work_salary_values = work_salary.values
work_salary_values = np.repeat(work_salary_values, 4, axis=1) # 重复4次 使图标美观,图片宽度拉大 | 水平拉大
#%%
# work_salary.index # 城市名称
# work_salary.columns # 年份
#%%
plt.figure(figsize=(12, 9))
plt.imshow(work_salary_values, cmap='RdBu_r')
# 设置刻度
_ = plt.xticks(np.array([1.5, 5.5, 9.5, 13.5]), work_salary.columns)
_ = plt.yticks(np.arange(13), work_salary.index)
# 绘制文本
h, w = work_salary_values.shape # 行列
for x in range(w):
for y in range(h):
if (x % 4 == 0) and (~np.isnan(work_salary_values[y, x])): # 数据重复4次 | ~np.isnan(work_salary_values[y, x]) 数据不能空
text = plt.text(x+1.5, y, round(work_salary_values[y, x], 1), # 倾斜
ha='center', va='center',color='r', fontsize=16
)
plt.colorbar(shrink=0.85) # 颜色标 高度
plt.tick_params(labelsize=16) # 字体大小
#%% md
### 学历要求
#%%
education = data.education.value_counts(normalize=True) # 统计 normalize 规划 (0~1)
education
#%%
# education = education.value_counts() # 统计
# education
#%%
plt.figure(figsize=(9, 9))
_ = plt.pie(education, labels=education.index, autopct='%0.2f%%', # 数据 标签 显示百分比(格式)
wedgeprops=dict(lw=3,width=0.5), # width 元环的粗细
pctdistance=0.8, # 百分比位置
textprops=dict(fontsize=20)
)
_ = plt.title(label='学历要求',fontsize=32,weight='bold', color='white', backgroundcolor='#c5b893')
#%% md
#%% md
### 技能与薪资对应关系
#%%
# 数据调整
job_detail_items_key = [a for (a, b) in job_detail_items]
def get_level(_): # 每行数据
for k in job_detail_items_key:
if _[k] == 1:
_['skill'] = k # 符合就进行增加列 并且退出循环
break
else:
_['skill'] = '其他' # 当循环结束都没有进行时就 赋值
return _
# 对整个数据进行处理 | axis 对列进行处理
data = data.apply(get_level, axis=1) # 数据转换
data.head(20)
#%%
# 获取主要技能 过滤其他的
"""
job_detail_items_key = [
'Python',
'SQL',
'Tableau',
'Excel',
'SPSS/SAS',
]
"""
x = data.loc[data.skill!='其他'][['salary', 'skill']] # 薪资和技能
cond_data = []
for _ in job_detail_items_key:
cond_data.append(data.loc[data.skill!='其他']['salary'][x.skill==_])
# 箱式图
plt.figure(figsize=(12, 9))
plt.title(
label='不同技能的薪资水平对比',
fontsize=32, weight='bold', color='white',
backgroundcolor='#c5b783', pad=30
)
_ = plt.boxplot(
x=cond_data,
vert=False, labels=job_detail_items_key # vert=False 水平 =True 垂直
)
plt.tick_params(axis='both', labelsize=16) # 标签文本大小 垂直
plt.grid(axis='x', linewidth=0.75) # 网格线
_ = plt.xticks(np.arange(0, 61, 10), [str(i) + 'K' for i in range(0, 61, 10)]) # 水平标签文本设置
plt.xlabel('薪资', fontsize=18)
plt.ylabel('技能', fontsize=18)
# 盒子内的线是中位数
# 左边是下限右边是上限
# 超过上限会认为是异常值
#%% md
### 大公司对数据分析师技能要求
#%%
skill_count = data[ data.companySize == '2000人以上' ][ job_detail_items_key ].sum() # 根据字段进行统计
skill_count
#%%
plt.figure(figsize=(12, 9))
plt.bar( # 垂直条形图
np.arange(5), skill_count,
tick_label=job_detail_items_key,
width=0.5,
color=plt.cm.RdBu_r(skill_count/skill_count.max())
)
_ = plt.title(
label='大公司对技能要求',
fontsize=32, weight='bold', color='white',
backgroundcolor='#c5b783', pad=30
)
plt.tick_params(labelsize=16,)
plt.grid(axis='y')
plt.box(False)
#%% md
### 不同规模公司招聘差异
#%%
# 散点图
from matplotlib import gridspec # 子视图
workYear_map = {
'5-10年': 5,
'3-5年': 4,
'1-3年': 3,
'1年以下': 2,
'应届毕业生': 1
}
color_map = {
5: '#ff0000',
4: '#ffa500',
3: '#c5b783',
2: '#3c7f99',
1: '#0000cd'
}
cond = data.workYear.isin(workYear_map) # 只统计在这里面的范围的数据
data = data[cond] # 重写数据
data.loc[:,'workYear'] = data.workYear.map(workYear_map) # 进行数据处理字符串变成数字 方便统计和计算
data.head()
#%%
# 根据 companySize 这一列数据进行排序 从多到小 | companySize 是字符串 无法直接做数值排序
data.loc[:,'companySize'] = data.companySize.astype('category') # 修改数据类型 category 类别
companySize_items = ['2000人以上', '500-2000人', '150-500人', '50-150人', '15-50人', '少于15人'] # 手动设置排序规则
# data.companySize.unique() # 获取该列数据(去重)
data.loc[:,'companySize'] = data.companySize.cat.reorder_categories(companySize_items) # 进行排序 小到大
data.sort_values(by='companySize', inplace=True, ascending=False) # 降序排序
data.head()
#%%
# 绘图
plt.figure(figsize=(12,11))
gs = gridspec.GridSpec(10, 1) # 子视图 10行一列
plt.subplot(gs[:8]) # 第一个子视图取到8
plt.suptitle(
t='不同规模公司招聘差异',
fontsize=32,
weight='bold', color='white', backgroundcolor='#3c7f99'
)
# scatter 散点图
# 外圆 有透明度比较浅色
plt.scatter(data.salary, data.companySize,
c=data.workYear.map(color_map),
s=(data.workYear * 100), # 这个比较大
alpha=0.35
)
# 内圆
plt.scatter(data.salary, data.companySize,
c=data.workYear.map(color_map),
)
plt.grid(axis='x')
plt.xticks(np.arange(0, 61, 10), [str(i) + 'K' for i in range(0, 61, 10)])
plt.xlabel('薪资', fontsize=18)
plt.box(False) # 无边框
plt.tick_params(labelsize=18)
# 绘制底部标记
plt.subplot(gs[9:]) # 10个中取最后一个 | 和上面子视图有间隔
x = np.arange(5)[::-1] # 反转
y = np.zeros(len(x)) # 全是0
s = x * 100
plt.scatter(x,y, s=s, c=color_map.values(), alpha=0.3)
plt.scatter(x,y, c=color_map.values())
plt.box(False)
plt.xticks(ticks=x, labels=list(workYear_map.keys()), fontsize=14)
plt.yticks(np.arange(1), labels=['经验'], fontsize=18)
#%%
笔记 | 数据分析综合项目实战
最新推荐文章于 2023-04-05 20:27:52 发布