笔记 | 数据分析综合项目实战

#%% 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)
#%%

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CY3761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值