数据预处理入门学习教程,从入门到精通, 实战演练——数据分析师岗位分析知识点详解(8)

实战演练------数据分析师岗位分析知识点详解


一、数据分析的流程

1.1 知识点概述

数据分析的标准流程一般包含以下五个阶段:

阶段 说明
明确目标 确定分析的业务问题和分析方向
数据收集 通过爬虫、数据库、API、公开数据集等方式获取原始数据
数据预处理 对原始数据进行清洗、转换、整合,使其满足分析需求
数据分析与展现 运用统计方法和可视化手段探索数据规律
结论与建议 总结发现,输出分析报告

1.2 数据分析流程示意图代码(pyecharts 基础铺垫)

python 复制代码
# ============================================
# 使用 pyecharts 绘制数据分析流程图(Sankey 桑基图)
# ============================================

# 导入 pyecharts 中的图表类型和配置项模块
from pyecharts.charts import Sankey          # 导入桑基图类
from pyecharts import options as opts        # 导入全局配置项模块

# ---------- 定义节点(nodes) ----------
# 每个节点代表数据分析流程中的一个阶段
# "name" 是节点的显示名称
nodes = [
    {"name": "明确目标"},       # 第1阶段:明确分析目标
    {"name": "数据收集"},       # 第2阶段:收集原始数据
    {"name": "数据预处理"},     # 第3阶段:清洗与转换数据
    {"name": "数据分析"},       # 第4阶段:统计分析与建模
    {"name": "数据可视化"},     # 第5阶段:图表呈现结果
    {"name": "结论与建议"},     # 第6阶段:输出分析报告
]

# ---------- 定义链接(links) ----------
# 每条链接表示从一个阶段流向下一个阶段
# "source":起始节点名称
# "target":目标节点名称
# "value": 流量大小(此处表示流程的先后顺序权重)
links = [
    {"source": "明确目标",   "target": "数据收集",   "value": 10},  # 目标 -> 收集
    {"source": "数据收集",   "target": "数据预处理", "value": 10},  # 收集 -> 预处理
    {"source": "数据预处理", "target": "数据分析",   "value": 10},  # 预处理 -> 分析
    {"source": "数据分析",   "target": "数据可视化", "value": 8},   # 分析 -> 可视化
    {"source": "数据可视化", "target": "结论与建议", "value": 8},   # 可视化 -> 结论
]

# ---------- 创建桑基图 ----------
sankey = (
    Sankey()                                                    # 实例化桑基图对象
    .add(                                                       # 添加数据系列
        series_name="数据分析流程",                              # 系列名称(图例显示)
        data_opt=nodes,                                         # 传入节点数据
        link_opt=links,                                         # 传入链接数据
        linestyle_opt=opts.LineStyleOpts(                       # 设置线条样式
            opacity=0.2,                                        # 线条透明度(0-1)
            curve=0.5,                                          # 线条弯曲程度(0-1)
            color="source",                                     # 线条颜色跟随源节点颜色
        ),
        label_opts=opts.LabelOpts(                              # 设置标签样式
            position="right",                                   # 标签显示在节点右侧
            font_size=14,                                       # 字体大小14px
        ),
    )
    .set_global_opts(                                           # 设置全局配置
        title_opts=opts.TitleOpts(                              # 标题配置
            title="数据分析流程图",                              # 主标题
            title_textstyle_opts=opts.TextStyleOpts(            # 标题文字样式
                font_size=20,                                   # 标题字号
                color="#333",                                   # 标题颜色
            ),
        ),
    )
)

# ---------- 渲染输出为 HTML 文件 ----------
sankey.render("data_analysis_flow.html")                        # 生成本地HTML文件
print("数据分析流程图已生成:data_analysis_flow.html")            # 提示输出完成

二、使用 pyecharts 绘制图表

2.1 pyecharts 简介与安装

bash 复制代码
# ============================================
# pyecharts 安装命令(在终端/命令行中执行)
# ============================================

# 安装 pyecharts 库(Echarts 的 Python 版本)
pip install pyecharts

# 查看安装版本
pip show pyecharts

2.2 pyecharts 核心架构

python 复制代码
# ============================================
# pyecharts 核心架构演示
# ============================================

# pyecharts 的两个核心导入
from pyecharts.charts import Bar, Line, Pie, Map, Grid, Page   # 导入图表类型
from pyecharts import options as opts                           # 导入配置项

# pyecharts 的核心架构:
# 1. 图表类型(Charts):Bar, Line, Pie, Map, Scatter 等
# 2. 配置项(Options):全局配置 + 系列配置
# 3. 渲染(Render):输出为 HTML 或图片

# ----- 配置项分类 -----
# 全局配置项(set_global_opts):
#   - TitleOpts       标题配置
#   - ToolboxOpts     工具箱配置
#   - LegendOpts       图例配置
#   - VisualMapOpts   视觉映射配置
#   - DataZoomOpts    数据缩放配置
#   - TooltipOpts     提示框配置

# 系列配置项(.add() 中使用):
#   - LabelOpts       标签配置
#   - ItemStyleOpts   图元样式配置
#   - linestyle_opts  线样式配置
#   - areastyle_opts  区域填充样式配置

2.3 pyecharts 基本使用模式

python 复制代码
# ============================================
# pyecharts 基本使用模式------以柱状图为例
# ============================================

from pyecharts.charts import Bar                          # 导入柱状图类
from pyecharts import options as opts                     # 导入配置项

# 第一步:准备数据
# x 轴数据(类目轴):城市名称列表
x_data = ["北京", "上海", "深圳", "杭州", "广州"]
# y 轴数据(数值轴):各城市数据分析师岗位数量
y_data = [1200, 980, 850, 620, 580]

# 第二步:创建图表对象并链式调用
bar = (
    Bar()                                                 # 实例化柱状图对象
    .add_xaxis(x_data)                                    # 添加 x 轴数据
    .add_yaxis(                                           # 添加 y 轴数据系列
        series_name="岗位数量",                            # 系列名称
        y_axis=y_data,                                    # y 轴数据
        label_opts=opts.LabelOpts(                        # 标签配置
            is_show=True,                                 # 是否显示标签
            position="top",                               # 标签位置:柱体顶部
            color="#333",                                 # 标签字体颜色
        ),
    )
    .set_global_opts(                                     # 全局配置
        title_opts=opts.TitleOpts(                        # 标题
            title="数据分析师岗位数量 Top5 城市",           # 主标题
            subtitle="数据来源:某招聘平台",                # 副标题
        ),
        xaxis_opts=opts.AxisOpts(                         # x 轴配置
            name="城市",                                  # 轴名称
            axislabel_opts=opts.LabelOpts(rotate=30),     # 标签旋转30度防重叠
        ),
        yaxis_opts=opts.AxisOpts(                         # y 轴配置
            name="岗位数量",                               # 轴名称
        ),
        tooltip_opts=opts.TooltipOpts(                    # 提示框配置
            trigger="axis",                               # 触发方式:坐标轴触发
            axis_pointer_type="shadow",                   # 指示器类型:阴影
        ),
    )
)

# 第三步:渲染输出
bar.render("bar_basic_demo.html")                         # 生成HTML文件
print("柱状图已生成:bar_basic_demo.html")

2.4 常用图表类型详细案例

2.4.1 折线图(Line)
python 复制代码
# ============================================
# 折线图案例------数据分析师岗位需求趋势
# ============================================

from pyecharts.charts import Line                          # 导入折线图类
from pyecharts import options as opts                      # 导入配置项
from pyecharts.globals import ThemeType                    # 导入主题类型

# 准备数据
# x 轴:月份
months = ["2024-01", "2024-02", "2024-03", "2024-04",
          "2024-05", "2024-06", "2024-07", "2024-08",
          "2024-09", "2024-10", "2024-11", "2024-12"]

# y 轴:每月新增岗位数量
job_counts = [3200, 2800, 4100, 4500, 4800, 5200,
              5000, 4600, 5800, 6100, 5500, 6800]

# 创建折线图对象,使用 DARK 主题
line = (
    Line(init_opts=opts.InitOpts(                          # 初始化配置
        theme=ThemeType.DARK,                              # 使用暗色主题
        width="1000px",                                    # 图表宽度
        height="500px",                                    # 图表高度
    ))
    .add_xaxis(months)                                     # 添加 x 轴数据(月份)
    .add_yaxis(                                            # 添加 y 轴数据系列
        series_name="新增岗位数",                           # 系列名称
        y_axis=job_counts,                                 # y 轴数据
        is_smooth=True,                                    # 平滑曲线(默认为折线)
        symbol="circle",                                   # 数据点标记形状:圆形
        symbol_size=8,                                     # 数据点标记大小
        linestyle_opts=opts.LineStyleOpts(                 # 线条样式配置
            width=3,                                       # 线宽3px
            color="#e74c3c",                               # 线条颜色:红色
        ),
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=True,                                  # 是否显示标签
            position="top",                                # 标签位于数据点上方
            font_size=10,                                  # 标签字号
        ),
        # 添加区域填充样式(面积图效果)
        areastyle_opts=opts.AreaStyleOpts(                 # 区域填充配置
            opacity=0.3,                                   # 填充透明度
            color="#e74c3c",                               # 填充颜色
        ),
        # 标记最大值和最小值
        markpoint_opts=opts.MarkPointOpts(                 # 标记点配置
            data=[
                opts.MarkPointItem(                        # 标记最大值
                    type_="max",                           # 标记类型:最大值
                    name="最大值",                          # 标记名称
                ),
                opts.MarkPointItem(                        # 标记最小值
                    type_="min",                           # 标记类型:最小值
                    name="最小值",                          # 标记名称
                ),
            ],
            symbol_size=50,                                # 标记点大小
        ),
        # 添加平均线
        markline_opts=opts.MarkLineOpts(                   # 标记线配置
            data=[
                opts.MarkLineItem(                         # 平均线
                    type_="average",                       # 线类型:平均值
                    name="平均值",                          # 线名称
                ),
            ],
            linestyle_opts=opts.LineStyleOpts(             # 标记线样式
                type_="dashed",                            # 虚线
                color="#f39c12",                           # 颜色:橙色
            ),
        ),
    )
    .set_global_opts(                                      # 全局配置
        title_opts=opts.TitleOpts(                         # 标题配置
            title="数据分析师岗位月度需求趋势",              # 主标题
            subtitle="2024年全年数据",                      # 副标题
            pos_left="center",                             # 标题水平居中
        ),
        xaxis_opts=opts.AxisOpts(                          # x 轴配置
            name="月份",                                   # 轴名称
            axislabel_opts=opts.LabelOpts(rotate=45),      # 标签旋转45度
        ),
        yaxis_opts=opts.AxisOpts(                          # y 轴配置
            name="岗位数量",                                # 轴名称
            splitline_opts=opts.SplitLineOpts(             # 分割线配置
                is_show=True,                              # 显示分割线
            ),
        ),
        tooltip_opts=opts.TooltipOpts(                     # 提示框配置
            trigger="axis",                                # 触发方式:坐标轴
        ),
        datazoom_opts=[                                    # 数据缩放配置
            opts.DataZoomOpts(                             # 滑动条型
                type_="slider",                            # 类型:滑动条
                range_start=0,                             # 起始范围百分比
                range_end=100,                             # 结束范围百分比
            ),
        ],
    )
)

# 渲染输出
line.render("line_job_trend.html")
print("折线图已生成:line_job_trend.html")
2.4.2 饼图(Pie)
python 复制代码
# ============================================
# 饼图案例------数据分析师岗位学历要求分布
# ============================================

from pyecharts.charts import Pie                           # 导入饼图类
from pyecharts import options as opts                      # 导入配置项

# 准备数据------学历要求及对应的岗位数量
# 数据格式:[(类别1, 值1), (类别2, 值2), ...]
edu_data = [
    ("本科", 4500),      # 本科学历要求:4500个岗位
    ("硕士", 1200),      # 硕士学历要求:1200个岗位
    ("大专", 800),       # 大专学历要求:800个岗位
    ("博士", 150),       # 博士学历要求:150个岗位
    ("不限", 350),       # 学历不限:350个岗位
]

# 创建饼图对象
pie = (
    Pie()                                                  # 实例化饼图对象
    .add(                                                  # 添加数据系列
        series_name="学历要求",                             # 系列名称
        data_pair=edu_data,                                # 数据对(类别-值)
        radius=["40%", "70%"],                             # 环形图半径 [内半径, 外半径]
        center=["50%", "55%"],                             # 饼图中心位置 [水平, 垂直]
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=True,                                  # 显示标签
            formatter="{b}: {c}\n{d}%",                    # 标签格式:名称:值\n百分比
            font_size=12,                                  # 字体大小
        ),
        # 每个扇区的样式
        itemstyle_opts=opts.ItemStyleOpts(                 # 图元样式配置
            border_color="#fff",                           # 边框颜色:白色
            border_width=2,                                # 边框宽度:2px
        ),
    )
    .set_global_opts(                                      # 全局配置
        title_opts=opts.TitleOpts(                         # 标题配置
            title="数据分析师岗位学历要求分布",              # 主标题
            pos_left="center",                             # 标题居中
        ),
        legend_opts=opts.LegendOpts(                       # 图例配置
            orient="vertical",                             # 图例排列方向:垂直
            pos_left="left",                               # 图例位置:左侧
            pos_top="middle",                              # 图例垂直居中
        ),
        tooltip_opts=opts.TooltipOpts(                     # 提示框配置
            trigger="item",                                # 触发方式:数据项
            formatter="{a} <br/>{b}: {c} ({d}%)",         # 提示框格式
        ),
    )
    .set_colors(                                           # 设置自定义颜色列表
        ["#2ecc71", "#3498db", "#e67e22", "#e74c3c", "#9b59b6"]
    )
)

# 渲染输出
pie.render("pie_edu_distribution.html")
print("饼图已生成:pie_edu_distribution.html")
2.4.3 地图(Map)
python 复制代码
# ============================================
# 地图案例------全国数据分析师岗位城市分布
# ============================================

from pyecharts.charts import Map                           # 导入地图类
from pyecharts import options as opts                      # 导入配置项

# 准备数据------省份对应的岗位数量
# 注意:省份名称要与 pyecharts 内置的中国地图名称匹配
province_data = [
    ("北京", 1200),     # 北京市:1200个岗位
    ("上海", 980),      # 上海市:980个岗位
    ("广东", 1500),     # 广东省(含深圳、广州):1500个岗位
    ("浙江", 720),      # 浙江省:720个岗位
    ("江苏", 560),      # 江苏省:560个岗位
    ("四川", 380),      # 四川省:380个岗位
    ("湖北", 320),      # 湖北省:320个岗位
    ("山东", 280),      # 山东省:280个岗位
    ("福建", 250),      # 福建省:250个岗位
    ("湖南", 200),      # 湖南省:200个岗位
]

# 创建地图对象
map_chart = (
    Map()                                                  # 实例化地图对象
    .add(                                                  # 添加数据系列
        series_name="岗位数量",                             # 系列名称
        data_pair=province_data,                           # 数据对
        maptype="china",                                   # 地图类型:中国地图
        is_map_symbol_show=True,                           # 是否显示地图标记点
        symbol_size=15,                                    # 标记点大小
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=True,                                  # 显示省份名称
            font_size=10,                                  # 字体大小
        ),
    )
    .set_global_opts(                                      # 全局配置
        title_opts=opts.TitleOpts(                         # 标题配置
            title="数据分析师岗位全国分布图",                # 主标题
            pos_left="center",                             # 标题居中
        ),
        visualmap_opts=opts.VisualMapOpts(                 # 视觉映射配置(颜色渐变)
            is_show=True,                                  # 显示视觉映射组件
            min_=100,                                      # 映射最小值
            max_=1500,                                     # 映射最大值
            is_piecewise=True,                             # 分段显示(非连续)
            pieces=[                                       # 自定义分段
                {"min": 1000, "label": "1000以上", "color": "#7f1100"},   # 深红
                {"min": 500, "max": 999, "label": "500-999", "color": "#cc3311"},  # 红
                {"min": 200, "max": 499, "label": "200-499", "color": "#ee6644"},  # 橙
                {"min": 0, "max": 199, "label": "0-199", "color": "#ffaa55"},      # 浅橙
            ],
            pos_left="left",                               # 组件位置:左侧
            pos_bottom="20%",                              # 组件距底部20%
        ),
    )
)

# 渲染输出
map_chart.render("map_city_distribution.html")
print("地图已生成:map_city_distribution.html")
2.4.4 组合图表(Grid 多图组合)
python 复制代码
# ============================================
# Grid 组合图案例------柱状图 + 折线图组合
# ============================================

from pyecharts.charts import Bar, Line, Grid                # 导入柱状图、折线图、网格组合图
from pyecharts import options as opts                       # 导入配置项
from pyecharts.globals import ThemeType                     # 导入主题

# 准备数据
cities = ["北京", "上海", "深圳", "杭州", "广州", "成都"]
avg_salary = [18000, 17500, 16800, 15500, 14000, 12500]     # 平均薪资(元/月)
job_count = [1200, 980, 850, 620, 580, 380]                # 岗位数量

# ---------- 创建柱状图 ----------
bar = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))   # 使用马卡龙主题
    .add_xaxis(cities)                                       # 添加 x 轴数据
    .add_yaxis(                                              # 添加薪资系列
        "平均薪资(元/月)",                                    # 系列名称
        avg_salary,                                          # y 轴数据
        yaxis_index=0,                                       # 使用第0个 y 轴(左侧)
        label_opts=opts.LabelOpts(is_show=True, position="top"),  # 标签在顶部
    )
    .extend_axis(                                            # 扩展一个新的 y 轴(右侧)
        yaxis=opts.AxisOpts(                                 # 右侧 y 轴配置
            name="岗位数量",                                  # 轴名称
            position="right",                                # 位置:右侧
            axislabel_opts=opts.LabelOpts(formatter="{value}"),  # 标签格式
        )
    )
    .set_global_opts(                                        # 全局配置
        title_opts=opts.TitleOpts(title="薪资与岗位数量对比"),  # 标题
        tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow"),
        yaxis_opts=opts.AxisOpts(                            # 左侧 y 轴
            name="平均薪资(元)",                               # 轴名称
            position="left",                                 # 位置:左侧
        ),
    )
)

# ---------- 创建折线图 ----------
line = (
    Line()                                                   # 实例化折线图
    .add_xaxis(cities)                                       # 添加 x 轴数据
    .add_yaxis(                                              # 添加岗位数量系列
        "岗位数量",                                           # 系列名称
        job_count,                                           # y 轴数据
        yaxis_index=1,                                       # 使用第1个 y 轴(右侧)
        symbol="circle",                                     # 数据点形状
        symbol_size=10,                                      # 数据点大小
        linestyle_opts=opts.LineStyleOpts(width=3, color="#e74c3c"),  # 线条样式
    )
)

# ---------- 使用 Grid 组合两个图表 ----------
# bar + line 两个图表绘制在同一画布中
bar.overlap(line)                                            # 将折线图叠加到柱状图上

# 创建 Grid 布局
grid = (
    Grid(init_opts=opts.InitOpts(width="1000px", height="500px"))  # 创建网格
    .add(                                                    # 添加组合图表
        bar,                                                 # 叠加后的图表对象
        grid_opts=opts.GridOpts(                             # 网格配置
            pos_left="10%",                                  # 左边距10%
            pos_right="10%",                                 # 右边距10%
            pos_top="15%",                                   # 上边距15%
        ),
    )
)

# 渲染输出
grid.render("grid_bar_line_combo.html")
print("组合图已生成:grid_bar_line_combo.html")

三、数据收集

3.1 知识点概述

数据收集是数据分析的第一步,常见方式包括:

方式 说明 适用场景
爬虫 使用 requests + BeautifulSoup / Scrapy 爬取网页数据 招聘网站、电商网站
API 调用平台提供的数据接口 Twitter、微博、公开数据平台
数据库 从 MySQL、MongoDB 等读取数据 企业内部数据
文件读取 读取 CSV、Excel、JSON 等文件 已有数据文件
公开数据集 Kaggle、UCI 等平台下载 学习与研究

3.2 使用 requests 爬取招聘数据

python 复制代码
# ============================================
# 数据收集------使用 requests + BeautifulSoup 爬取招聘数据
# ============================================

import requests                                            # 导入HTTP请求库
from bs4 import BeautifulSoup                              # 导入HTML解析库
import pandas as pd                                        # 导入数据处理库
import time                                                # 导入时间模块(用于设置请求间隔)
import random                                              # 导入随机数模块

# ---------- 设置请求头(模拟浏览器访问) ----------
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",        # 浏览器标识
    "Accept": "text/html,application/xhtml+xml",           # 接受的响应类型
    "Accept-Language": "zh-CN,zh;q=0.9",                   # 接受的语言:中文
}

# ---------- 构建请求URL ----------
# 示例:某招聘网站数据分析师岗位搜索页面
# 参数说明:query=搜索关键词, city=城市, page=页码
base_url = "https://www.example.com/jobs"
params = {
    "query": "数据分析师",                                  # 搜索关键词
    "city": "全国",                                        # 城市范围
    "page": 1,                                             # 起始页码
}

# ---------- 存储爬取结果的列表 ----------
all_jobs = []                                              # 存储所有岗位信息

# ---------- 循环爬取多页数据 ----------
for page in range(1, 6):                                   # 爬取第1页到第5页
    params["page"] = page                                  # 更新页码参数
    print(f"正在爬取第 {page} 页...")                        # 打印当前页码

    try:
        # 发送 GET 请求
        response = requests.get(                           # 发送HTTP GET请求
            url=base_url,                                  # 请求URL
            params=params,                                 # URL参数
            headers=headers,                               # 请求头
            timeout=10,                                    # 超时时间:10秒
        )

        # 判断请求是否成功
        response.raise_for_status()                        # 如果状态码不是200,抛出异常

        # 解析HTML内容
        soup = BeautifulSoup(                              # 创建BeautifulSoup对象
            response.text,                                 # HTML文本内容
            "html.parser"                                  # 使用内置HTML解析器
        )

        # 查找所有岗位卡片(根据实际网页结构调整选择器)
        job_cards = soup.find_all("div", class_="job-card")  # 查找所有class为job-card的div

        # 遍历每个岗位卡片,提取信息
        for card in job_cards:
            # 提取岗位名称
            job_title = card.find("h3", class_="job-title")
            title_text = job_title.get_text().strip() if job_title else "N/A"
            # .get_text() 获取标签内文本, .strip() 去除首尾空白字符

            # 提取公司名称
            company = card.find("span", class_="company-name")
            company_text = company.get_text().strip() if company else "N/A"

            # 提取薪资
            salary = card.find("span", class_="salary")
            salary_text = salary.get_text().strip() if salary else "N/A"

            # 提取工作地点
            location = card.find("span", class_="location")
            location_text = location.get_text().strip() if location else "N/A"

            # 提取学历要求
            education = card.find("span", class_="education")
            edu_text = education.get_text().strip() if education else "N/A"

            # 提取经验要求
            experience = card.find("span", class_="experience")
            exp_text = experience.get_text().strip() if experience else "N/A"

            # 将提取的信息存入字典
            job_info = {
                "岗位名称": title_text,                     # 岗位名称
                "公司名称": company_text,                   # 公司名称
                "薪资": salary_text,                        # 薪资范围
                "工作地点": location_text,                  # 工作地点
                "学历要求": edu_text,                       # 学历要求
                "经验要求": exp_text,                       # 经验要求
            }

            all_jobs.append(job_info)                      # 添加到总列表中

        # 随机等待1-3秒,避免请求过于频繁
        time.sleep(random.uniform(1, 3))                   # 随机休眠

    except requests.exceptions.RequestException as e:       # 捕获请求异常
        print(f"第 {page} 页爬取失败:{e}")                 # 打印错误信息
        continue                                           # 跳过当前页,继续下一页

# ---------- 将数据保存为CSV文件 ----------
df = pd.DataFrame(all_jobs)                                # 将列表转换为DataFrame
df.to_csv("data_analyst_jobs.csv",                         # CSV文件名
          index=False,                                     # 不保存行索引
          encoding="utf-8-sig")                            # 编码格式(支持中文Excel打开)
print(f"共爬取 {len(all_jobs)} 条岗位数据,已保存为 data_analyst_jobs.csv")

3.3 读取本地数据文件

python 复制代码
# ============================================
# 数据收集------读取本地CSV/Excel文件
# ============================================

import pandas as pd                                        # 导入pandas库

# ---------- 读取 CSV 文件 ----------
df_csv = pd.read_csv(                                      # 读取CSV文件
    "data_analyst_jobs.csv",                               # 文件路径
    encoding="utf-8-sig",                                  # 文件编码格式
    header=0,                                              # 第0行作为列名(默认值)
    usecols=["岗位名称", "公司名称", "薪资",                 # 只读取指定列
             "工作地点", "学历要求"],
    dtype={                                                # 指定列的数据类型
        "岗位名称": str,                                    # 字符串类型
        "薪资": str,                                        # 字符串类型(后续需转换)
    },
)

# ---------- 读取 Excel 文件 ----------
df_excel = pd.read_excel(                                  # 读取Excel文件
    "data_analyst_jobs.xlsx",                              # 文件路径
    sheet_name="Sheet1",                                   # 读取的工作表名称
    header=0,                                              # 第0行作为列名
    engine="openpyxl",                                     # 使用openpyxl引擎(支持.xlsx)
)

# ---------- 查看数据基本信息 ----------
print("数据形状(行数, 列数):", df_csv.shape)              # 输出 (行数, 列数)
print("\n前5行数据预览:")                                  # 分隔提示
print(df_csv.head())                                       # 查看前5行

print("\n数据类型:")                                       # 分隔提示
print(df_csv.dtypes)                                       # 查看每列数据类型

print("\n基本统计信息:")                                   # 分隔提示
print(df_csv.describe())                                   # 查看数值列的统计摘要

print("\n缺失值统计:")                                     # 分隔提示
print(df_csv.isnull().sum())                               # 查看每列缺失值数量

四、数据预处理

4.1 知识点概述

数据预处理是将原始数据转换为可分析形式的关键步骤,主要包括:

步骤 说明
缺失值处理 删除或填充缺失数据
重复值处理 删除重复记录
数据类型转换 字符串转数值、日期格式转换等
异常值处理 检测并处理不合理的数据
数据标准化 统一格式(如薪资统一为月薪)
特征工程 从现有数据中提取新特征

4.2 缺失值处理

python 复制代码
# ============================================
# 数据预处理------缺失值处理
# ============================================

import pandas as pd                                        # 导入pandas库
import numpy as np                                         # 导入numpy库

# ---------- 创建包含缺失值的示例数据 ----------
data = {
    "岗位名称": ["数据分析师", "数据分析师", "数据分析师", "BI分析师", "数据分析师"],
    "薪资":     ["15-25K",     None,          "20-30K",     "18-28K",     None],
    "工作地点": ["北京",        "上海",         None,         "深圳",       "杭州"],
    "学历要求": ["本科",        "本科",         "硕士",       None,         "大专"],
    "经验要求": ["3-5年",       "1-3年",       None,         "3-5年",      "1-3年"],
}
df = pd.DataFrame(data)                                    # 创建DataFrame
print("原始数据:")
print(df)                                                  # 打印原始数据
print(f"\n缺失值统计:\n{df.isnull().sum()}")              # 统计缺失值

# ----- 方法1:删除缺失值 -----
# 删除包含任意缺失值的行
df_drop_rows = df.dropna(                                  # 删除缺失值
    axis=0,                                                # 按行删除(默认值)
    how="any",                                             # 只要该行有任意一个缺失值就删除
    subset=["薪资", "工作地点"],                              # 只检查指定列的缺失值
)
print("\n方法1-删除含缺失值的行:")
print(df_drop_rows)

# ----- 方法2:用固定值填充缺失值 -----
df_fill_fixed = df.copy()                                  # 创建副本,避免修改原始数据
df_fill_fixed["薪资"] = df_fill_fixed["薪资"].fillna("面议")  # 薪资缺失用"面议"填充
df_fill_fixed["工作地点"] = df_fill_fixed["工作地点"].fillna("未知")  # 地点缺失用"未知"填充
print("\n方法2-固定值填充:")
print(df_fill_fixed)

# ----- 方法3:用众数填充缺失值 -----
df_fill_mode = df.copy()                                   # 创建副本
# 获取学历要求列的众数(出现次数最多的值)
edu_mode = df_fill_mode["学历要求"].mode()[0]               # mode()返回Series,取第一个
df_fill_mode["学历要求"] = df_fill_mode["学历要求"].fillna(edu_mode)  # 用众数填充
print(f"\n方法3-众数填充(众数为'{edu_mode}'):")
print(df_fill_mode)

# ----- 方法4:用前一个有效值填充(前向填充) -----
df_ffill = df.copy()                                       # 创建副本
df_ffill["经验要求"] = df_ffill["经验要求"].ffill()          # 用前一个非缺失值填充
print("\n方法4-前向填充:")
print(df_ffill)

# ----- 方法5:插值法填充(适用于数值型数据) -----
# 示例:对数值型数据进行线性插值
numeric_data = pd.Series([10, np.nan, np.nan, 40, 50])     # 包含缺失值的数值序列
interpolated = numeric_data.interpolate(method="linear")    # 线性插值
print(f"\n方法5-线性插值:{list(interpolated)}")
# 输出:[10.0, 20.0, 30.0, 40.0, 50.0](均匀插值)

4.3 重复值处理

python 复制代码
# ============================================
# 数据预处理------重复值处理
# ============================================

import pandas as pd                                        # 导入pandas库

# ---------- 创建包含重复值的示例数据 ----------
data = {
    "岗位名称": ["数据分析师", "数据分析师", "算法工程师", "数据分析师", "BI分析师"],
    "公司名称": ["A公司",      "A公司",      "B公司",       "C公司",       "D公司"],
    "薪资":     ["15-25K",     "15-25K",     "25-40K",      "20-30K",      "18-28K"],
    "工作地点": ["北京",        "北京",        "上海",         "深圳",        "广州"],
}
df = pd.DataFrame(data)                                    # 创建DataFrame
print("原始数据:")
print(df)

# ----- 检测重复值 -----
# 查看是否有完全重复的行
duplicated_mask = df.duplicated(                           # 检测重复行
    subset=["岗位名称", "公司名称"],                          # 根据指定列判断是否重复
    keep="first",                                          # 保留第一次出现的行,标记后续重复行为True
)
print(f"\n重复行标记:\n{duplicated_mask}")                 # 打印布尔标记

# ----- 删除重复值 -----
df_deduped = df.drop_duplicates(                           # 删除重复行
    subset=["岗位名称", "公司名称"],                          # 根据指定列判断重复
    keep="first",                                          # 保留第一次出现的记录
    ignore_index=True,                                     # 重置行索引
    inplace=False,                                         # 不修改原DataFrame,返回新对象
)
print(f"\n去重后数据({len(df_deduped)}条):")
print(df_deduped)

# ----- 统计重复情况 -----
dup_count = df.duplicated(                                 # 检测重复行
    subset=["岗位名称", "公司名称"],
    keep=False,                                            # 标记所有重复行(包括首次出现的)
).sum()                                                    # 对True求和,得到重复行总数
print(f"\n重复记录总数:{dup_count} 条")

4.4 薪资数据清洗与转换(核心预处理)

python 复制代码
# ============================================
# 数据预处理------薪资字段清洗与数值转换
# (这是本章实战中最核心的预处理步骤)
# ============================================

import pandas as pd                                        # 导入pandas库
import re                                                  # 导入正则表达式模块

# ---------- 创建包含各种薪资格式的示例数据 ----------
data = {
    "岗位名称": ["数据分析师", "数据分析师", "数据分析师", "数据分析师", "数据分析师", "数据分析师"],
    "薪资": [
        "15-25K",        # 格式1:标准格式 15K-25K
        "20K-30K",       # 格式2:带大写K
        "1.5万-2.5万/月", # 格式3:万元/月格式
        "18-25K·14薪",   # 格式4:含薪数(14个月工资)
        "15000-25000",   # 格式5:纯数字格式(元/月)
        "面议",          # 格式6:面议
    ],
    "工作地点": ["北京", "上海", "深圳", "杭州", "广州", "成都"],
}

df = pd.DataFrame(data)                                    # 创建DataFrame
print("原始薪资数据:")
print(df["薪资"])                                          # 打印薪资列

# ---------- 定义薪资解析函数 ----------
def parse_salary(salary_str):
    """
    解析各种格式的薪资字符串,返回统一的最低薪资和最高薪资(单位:千元/月)
    
    参数:
        salary_str (str): 原始薪资字符串
    返回:
        tuple: (最低薪资K, 最高薪资K),无法解析返回 (None, None)
    """
    # 如果薪资为空或"面议",返回空值
    if pd.isna(salary_str) or salary_str == "面议":        # 判断空值或面议
        return (None, None)                                # 返回两个空值

    salary_str = str(salary_str).strip()                   # 转为字符串并去除空白

    # ----- 情况1:处理"XX-XXK"或"XXK-XXK"格式 -----
    # 正则表达式:匹配 "数字-数字K" 或 "数字K-数字K" 格式
    pattern_k = re.compile(r'(\d+\.?\d*)\s*[Kk]\s*[-~]\s*(\d+\.?\d*)\s*[Kk]?')
    match_k = pattern_k.search(salary_str)                 # 搜索匹配
    if match_k:                                            # 如果匹配成功
        low = float(match_k.group(1))                      # 提取最低薪资(已经是K)
        high = float(match_k.group(2))                     # 提取最高薪资
        return (low, high)                                 # 返回结果

    # ----- 情况2:处理"X.X万-X.X万/月"格式 -----
    pattern_wan = re.compile(r'(\d+\.?\d*)\s*万?\s*[-~]\s*(\d+\.?\d*)\s*万')
    match_wan = pattern_wan.search(salary_str)             # 搜索匹配
    if match_wan:                                          # 如果匹配成功
        low = float(match_wan.group(1)) * 10               # 万转K(1万 = 10K)
        high = float(match_wan.group(2)) * 10              # 万转K
        return (low, high)                                 # 返回结果

    # ----- 情况3:处理纯数字格式 "15000-25000" -----
    pattern_num = re.compile(r'(\d+)\s*[-~]\s*(\d+)')
    match_num = pattern_num.search(salary_str)             # 搜索匹配
    if match_num:                                          # 如果匹配成功
        low = float(match_num.group(1)) / 1000             # 元转K(除以1000)
        high = float(match_num.group(2)) / 1000            # 元转K
        return (low, high)                                 # 返回结果

    # ----- 无法解析的情况 -----
    return (None, None)                                    # 返回空值

# ---------- 应用薪资解析函数 ----------
# apply() 对薪资列的每个元素应用 parse_salary 函数
salary_parsed = df["薪资"].apply(parse_salary)             # 解析每条薪资数据

# 将解析结果拆分为两列
df["最低薪资(K)"] = salary_parsed.apply(lambda x: x[0])    # 提取最低薪资
df["最高薪资(K)"] = salary_parsed.apply(lambda x: x[1])    # 提取最高薪资

# 计算平均薪资
df["平均薪资(K)"] = (                                       # 计算平均值
    df["最低薪资(K)"] + df["最高薪资(K)"]                    # 最低 + 最高
) / 2                                                      # 除以2

# ---------- 处理含薪数的情况(如14薪) ----------
# 提取薪资月数
def extract_months(salary_str):
    """
    从薪资字符串中提取薪资月数(如14薪、13薪)
    默认为12薪
    """
    if pd.isna(salary_str):                                # 判断空值
        return 12                                          # 默认12个月
    pattern = re.compile(r'(\d+)\s*薪')                    # 匹配"X薪"格式
    match = pattern.search(str(salary_str))                # 搜索
    return int(match.group(1)) if match else 12            # 返回匹配结果或默认12

df["薪资月数"] = df["薪资"].apply(extract_months)           # 提取薪资月数

# 计算年总薪资(万元)
df["年薪(万)"] = df["平均薪资(K)"] * df["薪资月数"] / 10   # K * 月数 / 10 = 万元

print("\n薪资解析结果:")
print(df[["岗位名称", "薪资", "最低薪资(K)", "最高薪资(K)", "平均薪资(K)", "薪资月数", "年薪(万)"]])

4.5 城市数据清洗

python 复制代码
# ============================================
# 数据预处理------城市名称标准化清洗
# ============================================

import pandas as pd                                        # 导入pandas库

# ---------- 创建包含不规范城市名称的数据 ----------
data = {
    "工作地点": [
        "北京", "北京市", "北京朝阳区", "北京-朝阳",
        "上海", "上海市", "上海浦东新区",
        "深圳", "深圳市", "深圳南山区",
        "杭州", "杭州市",
        "广州", "广州市",
        "成都", "成都市",
    ],
    "薪资": ["15K"] * 14,                                   # 简化的薪资数据
}
df = pd.DataFrame(data)

# ---------- 方法1:使用字符串截取 ----------
# 取城市名称的前2个字符(适用于双字城市名)
df["城市_截取"] = df["工作地点"].str[:2]                    # 截取前2个字符
print("方法1-字符串截取:")
print(df[["工作地点", "城市_截取"]].head(8))

# ---------- 方法2:使用正则表达式提取 ----------
# 提取中文城市名称(2-4个中文字符)
df["城市_正则"] = df["工作地点"].str.extract(r'([\u4e00-\u9fa5]{2,4})')
# [\u4e00-\u9fa5] 是中文字符的Unicode范围
# {2,4} 匹配2到4个中文字符
print("\n方法2-正则表达式提取:")
print(df[["工作地点", "城市_正则"]].head(8))

# ---------- 方法3:使用映射字典标准化 ----------
# 定义城市名称映射字典(原始名称 -> 标准名称)
city_mapping = {
    "北京": "北京",    "北京市": "北京",    "北京朝阳区": "北京",  "北京-朝阳": "北京",
    "上海": "上海",    "上海市": "上海",    "上海浦东新区": "上海",
    "深圳": "深圳",    "深圳市": "深圳",    "深圳南山区": "深圳",
    "杭州": "杭州",    "杭州市": "杭州",
    "广州": "广州",    "广州市": "广州",
    "成都": "成都",    "成都市": "成都",
}

df["城市_映射"] = df["工作地点"].map(city_mapping)           # 使用map方法进行映射
print("\n方法3-字典映射标准化:")
print(df[["工作地点", "城市_映射"]].head(8))

# ---------- 方法4:使用 replace 方法批量替换 ----------
df["城市_replace"] = df["工作地点"].replace(                 # 使用replace方法
    to_replace=r'(市|区|新区|-.*)',                          # 正则匹配需要替换的内容
    value="",                                              # 替换为空字符串
    regex=True,                                            # 启用正则表达式模式
)
print("\n方法4-replace批量替换:")
print(df[["工作地点", "城市_replace"]].head(8))

4.6 数据类型转换

python 复制代码
# ============================================
# 数据预处理------数据类型转换
# ============================================

import pandas as pd                                        # 导入pandas库

# ---------- 创建示例数据 ----------
data = {
    "岗位名称": ["数据分析师", "数据分析师", "数据分析师"],
    "薪资":     ["15-25K",     "20-30K",     "18-28K"],
    "发布日期": ["2024-03-15", "2024-03-16", "2024-03-17"],
    "浏览量":   ["1200",        "850",         "620"],      # 字符串类型的数字
    "是否急聘": ["是",          "否",           "是"],
}
df = pd.DataFrame(data)                                    # 创建DataFrame

print("转换前的数据类型:")
print(df.dtypes)                                           # 打印原始数据类型

# ----- 1. 字符串转数值型 -----
# 使用 astype() 转换
df["浏览量_int"] = df["浏览量"].astype(int)                 # 字符串转整数
# 或使用 pd.to_numeric() 更安全(可处理异常值)
df["浏览量_numeric"] = pd.to_numeric(                      # 更安全的数值转换
    df["浏览量"],                                           # 要转换的列
    errors="coerce",                                       # 无法转换的设为NaN
)

# ----- 2. 字符串转日期型 -----
df["发布日期_dt"] = pd.to_datetime(                        # 字符串转日期
    df["发布日期"],                                         # 要转换的列
    format="%Y-%m-%d",                                     # 日期格式
)
# 从日期中提取年、月、日、星期
df["发布年"] = df["发布日期_dt"].dt.year                    # 提取年份
df["发布月"] = df["发布日期_dt"].dt.month                   # 提取月份
df["发布日"] = df["发布日期_dt"].dt.day                     # 提取日
df["星期"] = df["发布日期_dt"].dt.day_name()                # 提取星期名称

# ----- 3. 字符串转分类类型 -----
df["是否急聘_cat"] = df["是否急聘"].astype("category")      # 转为分类类型
# 分类类型的优势:占用内存更小,支持排序

# ----- 4. 使用 map 进行编码转换 -----
# 将"是/否"映射为 1/0
df["是否急聘_num"] = df["是否急聘"].map({"是": 1, "否": 0})  # 映射为数值

print("\n转换后的数据:")
print(df)
print("\n转换后的数据类型:")
print(df.dtypes)

五、数据分析与展现

5.1 分析展现数据分析师岗位的需求趋势

python 复制代码
# ============================================
# 分析目标1:数据分析师岗位的需求趋势
# 使用折线图展现月度/季度岗位数量变化趋势
# ============================================

import pandas as pd                                        # 导入pandas库
from pyecharts.charts import Line                          # 导入折线图
from pyecharts import options as opts                      # 导入配置项
from pyecharts.globals import ThemeType                    # 导入主题类型

# ---------- 加载数据(模拟已预处理的数据) ----------
# 假设数据已预处理完毕,包含"发布日期"列
# 使用示例数据
data = {
    "发布日期": pd.date_range(                              # 生成日期序列
        start="2023-01-01",                                # 起始日期
        periods=24,                                        # 生成24个数据点
        freq="M"                                           # 频率:月末
    ),
    "岗位数量": [
        2800, 2600, 3500, 3800, 4200, 4600,               # 2023年上半年
        4400, 4100, 5000, 5300, 4800, 5500,               # 2023年下半年
        3200, 2900, 4100, 4500, 4800, 5200,               # 2024年上半年
        5000, 4600, 5800, 6100, 5500, 6800,               # 2024年下半年
    ],
}
df = pd.DataFrame(data)                                    # 创建DataFrame

# ---------- 数据聚合:按月份统计岗位数量 -----
# 将日期转换为月份字符串格式
df["月份"] = df["发布日期"].dt.strftime("%Y-%m")           # 格式化为"年-月"字符串
# 如果有重复月份,使用 groupby 聚合
monthly_data = df.groupby("月份")["岗位数量"].sum().reset_index()
# groupby("月份"):按月份分组
# ["岗位数量"].sum():对每组的岗位数量求和
# reset_index():将分组索引还原为普通列

# ---------- 提取绘图数据 ----------
x_months = monthly_data["月份"].tolist()                   # 月份列表(x轴)
y_counts = monthly_data["岗位数量"].tolist()               # 岗位数量列表(y轴)

# ---------- 计算同比增长率 ----------
# pct_change() 计算相邻两个数据点的变化率
growth_rate = monthly_data["岗位数量"].pct_change() * 100   # 百分比增长率
growth_rate = growth_rate.round(1).fillna(0).tolist()      # 保留1位小数,空值填0

# ---------- 绘制折线图 ----------
line = (
    Line(init_opts=opts.InitOpts(                          # 初始化配置
        theme=ThemeType.VINTAGE,                           # 复古主题
        width="1200px",                                    # 图表宽度
        height="500px",                                    # 图表高度
        page_title="数据分析师需求趋势分析",                # 浏览器标签页标题
    ))
    .add_xaxis(x_months)                                   # 添加x轴数据(月份)
    .add_yaxis(                                            # 添加岗位数量系列
        series_name="岗位数量",                             # 系列名称
        y_axis=y_counts,                                   # y轴数据
        is_smooth=True,                                    # 平滑曲线
        symbol="circle",                                   # 数据点形状
        symbol_size=6,                                     # 数据点大小
        linestyle_opts=opts.LineStyleOpts(                 # 线条样式
            width=3,                                       # 线宽
            color="#5470c6",                               # 线条颜色
        ),
        itemstyle_opts=opts.ItemStyleOpts(                 # 数据点样式
            color="#5470c6",                               # 点颜色
            border_color="#fff",                           # 点边框颜色
            border_width=2,                                # 点边框宽度
        ),
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=False,                                 # 不显示标签(数据点多时避免拥挤)
        ),
        # 标记最大值和最小值
        markpoint_opts=opts.MarkPointOpts(                 # 标记点配置
            data=[
                opts.MarkPointItem(type_="max", name="最大值"),   # 标记最大值
                opts.MarkPointItem(type_="min", name="最小值"),   # 标记最小值
            ],
        ),
        # 添加平均线
        markline_opts=opts.MarkLineOpts(                   # 标记线配置
            data=[opts.MarkLineItem(type_="average", name="平均值")],
        ),
        # 区域填充(面积图效果)
        areastyle_opts=opts.AreaStyleOpts(                 # 区域填充配置
            opacity=0.15,                                  # 透明度
        ),
    )
    .add_yaxis(                                            # 添加增长率系列(第二条线)
        series_name="环比增长率(%)",                        # 系列名称
        y_axis=growth_rate,                                # y轴数据
        is_smooth=True,                                    # 平滑曲线
        symbol="diamond",                                  # 数据点形状:菱形
        symbol_size=8,                                     # 数据点大小
        linestyle_opts=opts.LineStyleOpts(                 # 线条样式
            width=2,                                       # 线宽
            color="#91cc75",                               # 线条颜色:绿色
            type_="dashed",                                # 虚线样式
        ),
        yaxis_index=1,                                     # 使用第二个y轴(右侧)
    )
    .extend_axis(                                          # 扩展第二个y轴
        yaxis=opts.AxisOpts(                               # 右侧y轴配置
            name="增长率(%)",                                # 轴名称
            position="right",                              # 位置:右侧
            axislabel_opts=opts.LabelOpts(                 # 轴标签配置
                formatter="{value}%"                       # 格式:数值后加%
            ),
            splitline_opts=opts.SplitLineOpts(is_show=False),  # 不显示分割线
        )
    )
    .set_global_opts(                                      # 全局配置
        title_opts=opts.TitleOpts(                         # 标题配置
            title="数据分析师岗位需求趋势分析",              # 主标题
            subtitle="2023年1月 - 2024年12月",              # 副标题
            pos_left="center",                             # 居中
        ),
        tooltip_opts=opts.TooltipOpts(                     # 提示框配置
            trigger="axis",                                # 坐标轴触发
        ),
        legend_opts=opts.LegendOpts(                       # 图例配置
            pos_top="8%",                                  # 距顶部8%
        ),
        xaxis_opts=opts.AxisOpts(                          # x轴配置
            name="月份",                                   # 轴名称
            axislabel_opts=opts.LabelOpts(rotate=45),      # 标签旋转45度
        ),
        yaxis_opts=opts.AxisOpts(                          # 左侧y轴配置
            name="岗位数量",                                # 轴名称
            splitline_opts=opts.SplitLineOpts(is_show=True),  # 显示分割线
        ),
        datazoom_opts=[                                    # 数据缩放配置
            opts.DataZoomOpts(type_="slider"),             # 滑动条型缩放
        ],
    )
)

# 渲染输出
line.render("01_job_demand_trend.html")
print("需求趋势图已生成:01_job_demand_trend.html")

5.2 分析展现数据分析师岗位的热门城市 Top10

python 复制代码
# ============================================
# 分析目标2:数据分析师岗位热门城市Top10
# 使用柱状图+标签展现排名
# ============================================

import pandas as pd                                        # 导入pandas库
from pyecharts.charts import Bar, Pie, Page                # 导入柱状图、饼图、页面组合
from pyecharts import options as opts                      # 导入配置项
from pyecharts.globals import ThemeType                    # 导入主题类型

# ---------- 模拟预处理后的数据 ----------
# 假设已对"工作地点"列进行了城市标准化处理
data = {
    "工作地点": (["北京"] * 1200 + ["上海"] * 980 +         # 北京1200条、上海980条
                 ["深圳"] * 850 + ["杭州"] * 620 +          # 深圳850条、杭州620条
                 ["广州"] * 580 + ["成都"] * 380 +          # 广州580条、成都380条
                 ["南京"] * 320 + ["武汉"] * 300 +          # 南京320条、武汉300条
                 ["西安"] * 260 + ["长沙"] * 220 +          # 西安260条、长沙220条
                 ["重庆"] * 180 + ["苏州"] * 150),          # 重庆180条、苏州150条
}
df = pd.DataFrame(data)                                    # 创建DataFrame

# ---------- 数据聚合:统计各城市岗位数量 ----------
city_counts = (                                            # 统计各城市出现次数
    df["工作地点"]                                         # 选取城市列
    .value_counts()                                        # 统计每个城市的出现次数(自动降序排列)
    .head(10)                                              # 取前10名
    .reset_index()                                         # 重置索引,将原索引变成列
)
city_counts.columns = ["城市", "岗位数量"]                  # 重命名列名

# 提取绘图数据
x_cities = city_counts["城市"].tolist()                    # 城市列表
y_job_counts = city_counts["岗位数量"].tolist()            # 岗位数量列表
# 计算占比
total = sum(y_job_counts)                                  # 总数
percentages = [round(c / total * 100, 1) for c in y_job_counts]  # 百分比列表

# ---------- 绘制柱状图 ----------
bar = (
    Bar(init_opts=opts.InitOpts(                           # 初始化配置
        theme=ThemeType.CHALK,                             # 粉笔主题
        width="1000px",
        height="500px",
    ))
    .add_xaxis(x_cities)                                   # 添加x轴数据(城市)
    .add_yaxis(                                            # 添加y轴数据系列
        series_name="岗位数量",                             # 系列名称
        y_axis=y_job_counts,                               # y轴数据
        category_gap="40%",                                # 柱体间距(百分比)
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=True,                                  # 显示标签
            position="top",                                # 标签在柱体顶部
            formatter="{c}",                               # 标签格式:只显示数值
            font_size=12,                                  # 字体大小
        ),
        # 设置每根柱体的渐变颜色
        itemstyle_opts=opts.ItemStyleOpts(                 # 图元样式配置
            color=opts.JsCode(                             # 使用JavaScript代码设置渐变色
                "new echarts.graphic.LinearGradient(0, 0, 0, 1, "  # 从上到下线性渐变
                "[{offset: 0, color: '#e74c3c'}, "                  # 顶部颜色:红色
                "{offset: 1, color: '#f39c12'}])"                    # 底部颜色:橙色
            ),
        ),
    )
    .reversal_axis()                                       # 翻转坐标轴(水平柱状图)
    .set_global_opts(                                      # 全局配置
        title_opts=opts.TitleOpts(                         # 标题
            title="数据分析师岗位热门城市 Top 10",           # 主标题
            subtitle="基于招聘平台数据分析",                 # 副标题
        ),
        xaxis_opts=opts.AxisOpts(                          # x轴(翻转后变成纵向)
            name="岗位数量",                                # 轴名称
        ),
        yaxis_opts=opts.AxisOpts(                          # y轴(翻转后变成横向)
            axislabel_opts=opts.LabelOpts(                 # 标签配置
                font_size=12,                              # 字体大小
            ),
        ),
        tooltip_opts=opts.TooltipOpts(                     # 提示框
            trigger="axis",                                # 触发方式
            axis_pointer_type="shadow",                    # 阴影指示器
        ),
        visualmap_opts=opts.VisualMapOpts(                 # 视觉映射
            is_show=False,                                 # 隐藏视觉映射组件
            min_=min(y_job_counts),                        # 映射最小值
            max_=max(y_job_counts),                        # 映射最大值
            dimension=0,                                   # 映射维度(0=第一个数据维度)
            range_color=["#f39c12", "#e74c3c"],            # 颜色范围:橙色到红色
        ),
    )
    .set_series_opts(                                      # 系列配置
        markline_opts=opts.MarkLineOpts(                   # 标记线
            data=[opts.MarkLineItem(type_="average", name="平均值")],
        ),
    )
)

# 渲染输出
bar.render("02_top10_cities_bar.html")
print("热门城市柱状图已生成:02_top10_cities_bar.html")

# ---------- 同时绘制饼图(辅助展示占比) ----------
# 构建饼图数据
pie_data = list(zip(x_cities, y_job_counts))              # 将城市和数量配对

pie = (
    Pie(init_opts=opts.InitOpts(width="800px", height="500px"))
    .add(
        series_name="岗位占比",
        data_pair=pie_data,                                # 饼图数据
        radius=["30%", "65%"],                             # 环形图
        rosetype="area",                                   # 玫瑰图模式(面积模式:半径表示数值)
        label_opts=opts.LabelOpts(
            formatter="{b}: {d}%",                         # 标签格式:城市名:百分比
        ),
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="Top10城市岗位占比",
            pos_left="center",
        ),
        legend_opts=opts.LegendOpts(
            orient="vertical",                             # 垂直排列图例
            pos_right="2%",                                # 右侧
            pos_top="15%",                                 # 顶部偏下
        ),
    )
)

pie.render("02_top10_cities_pie.html")
print("热门城市饼图已生成:02_top10_cities_pie.html")

5.3 分析展现不同城市数据分析师岗位的薪资水平

python 复制代码
# ============================================
# 分析目标3:不同城市数据分析师岗位的薪资水平
# 使用箱线图/柱状图/地图综合展现薪资分布
# ============================================

import pandas as pd                                        # 导入pandas库
import numpy as np                                         # 导入numpy库
import random                                              # 导入随机数模块
from pyecharts.charts import Bar, Map, Boxplot, Page       # 导入多种图表
from pyecharts import options as opts                      # 导入配置项
from pyecharts.globals import ThemeType                    # 导入主题类型

# ---------- 模拟各城市薪资数据 ----------
# 设置随机种子,保证结果可复现
random.seed(42)                                            # Python随机种子
np.random.seed(42)                                         # numpy随机种子

# 定义各城市的薪资参数:(城市名, 平均薪资K, 标准差, 数据条数)
city_salary_params = [
    ("北京", 20, 5, 200),     # 北京:均值20K,标准差5,200条数据
    ("上海", 19, 4.5, 180),   # 上海:均值19K,标准差4.5
    ("深圳", 18, 4, 160),     # 深圳:均值18K,标准差4
    ("杭州", 16, 4, 120),     # 杭州:均值16K,标准差4
    ("广州", 15, 3.5, 110),   # 广州:均值15K,标准差3.5
    ("成都", 13, 3, 80),      # 成都:均值13K,标准差3
    ("南京", 14, 3.5, 70),    # 南京:均值14K,标准差3.5
    ("武汉", 13, 3, 65),      # 武汉:均值13K,标准差3
    ("西安", 12, 2.5, 55),    # 西安:均值12K,标准差2.5
    ("长沙", 11, 2.5, 50),    # 长沙:均值11K,标准差2.5
]

# 生成模拟数据
all_data = []                                              # 存储所有数据
for city, mean, std, count in city_salary_params:          # 遍历每个城市
    # 使用正态分布生成薪资数据,并取整
    salaries = np.random.normal(mean, std, count)          # 正态分布生成
    salaries = np.clip(salaries, 5, 50)                    # 裁剪到5K-50K范围
    salaries = np.round(salaries, 1)                       # 保留1位小数
    for s in salaries:                                     # 遍历每个薪资值
        all_data.append({"城市": city, "薪资(K)": s})      # 添加到列表

df = pd.DataFrame(all_data)                                # 创建DataFrame

# ---------- 计算各城市薪资统计信息 ----------
salary_stats = df.groupby("城市")["薪资(K)"].agg([          # 分组聚合
    "mean",     # 平均值
    "median",   # 中位数
    "min",      # 最小值
    "max",      # 最大值
    "std",      # 标准差
    "count",    # 数据条数
]).round(1)                                                # 保留1位小数

# 按平均薪资降序排列
salary_stats = salary_stats.sort_values("mean", ascending=False)  # 降序
salary_stats.columns = ["平均薪资", "中位数薪资", "最低薪资",       # 重命名列
                        "最高薪资", "标准差", "样本量"]
print("各城市薪资统计:")
print(salary_stats)

# ---------- 绘制柱状图:各城市平均薪资对比 ----------
x_cities = salary_stats.index.tolist()                     # 城市列表
y_avg_salary = salary_stats["平均薪资"].tolist()            # 平均薪资列表
y_median_salary = salary_stats["中位数薪资"].tolist()       # 中位数薪资列表

bar = (
    Bar(init_opts=opts.InitOpts(                           # 初始化
        theme=ThemeType.WESTEROS,                          # 权游主题
        width="1000px",
        height="500px",
    ))
    .add_xaxis(x_cities)                                   # 添加x轴数据
    .add_yaxis(                                            # 平均薪资系列
        "平均薪资(K)",                                      # 系列名称
        y_avg_salary,                                      # 数据
        gap="20%",                                         # 同一类目柱体间距
        label_opts=opts.LabelOpts(position="top"),         # 标签在顶部
        itemstyle_opts=opts.ItemStyleOpts(                 # 样式
            color=opts.JsCode(                             # 渐变色
                "new echarts.graphic.LinearGradient(0, 0, 0, 1, "
                "[{offset: 0, color: '#667eea'}, "
                "{offset: 1, color: '#764ba2'}])"
            ),
        ),
    )
    .add_yaxis(                                            # 中位数薪资系列
        "中位数薪资(K)",                                    # 系列名称
        y_median_salary,                                   # 数据
        gap="20%",                                         # 间距
        label_opts=opts.LabelOpts(position="top"),         # 标签在顶部
        itemstyle_opts=opts.ItemStyleOpts(                 # 样式
            color=opts.JsCode(
                "new echarts.graphic.LinearGradient(0, 0, 0, 1, "
                "[{offset: 0, color: '#f093fb'}, "
                "{offset: 1, color: '#f5576c'}])"
            ),
        ),
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(                         # 标题
            title="不同城市数据分析师薪资对比",              # 主标题
            subtitle="平均薪资 vs 中位数薪资",               # 副标题
        ),
        tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow"),
        legend_opts=opts.LegendOpts(pos_top="8%"),
        xaxis_opts=opts.AxisOpts(
            axislabel_opts=opts.LabelOpts(rotate=30),      # 标签旋转
        ),
        yaxis_opts=opts.AxisOpts(name="薪资(K/月)"),
    )
)

bar.render("03_city_salary_bar.html")
print("\n薪资对比柱状图已生成:03_city_salary_bar.html")

# ---------- 绘制地图:全国薪资热力图 ----------
# 准备地图数据(省份-平均薪资)
map_data = [
    ("北京", 20.0), ("上海", 19.0), ("广东", 18.0),       # 一线城市
    ("浙江", 16.0), ("江苏", 14.0), ("四川", 13.0),       # 新一线/二线城市
    ("湖北", 13.0), ("陕西", 12.0), ("湖南", 11.0),
    ("山东", 12.5), ("福建", 13.5), ("重庆", 12.0),
]

map_chart = (
    Map(init_opts=opts.InitOpts(width="900px", height="500px"))
    .add(
        series_name="平均薪资(K)",
        data_pair=map_data,
        maptype="china",
        is_map_symbol_show=True,
        symbol_size=12,
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="数据分析师薪资全国热力图",
            pos_left="center",
        ),
        visualmap_opts=opts.VisualMapOpts(
            is_show=True,
            min_=10,                                       # 最小值
            max_=22,                                       # 最大值
            is_piecewise=True,                             # 分段显示
            pieces=[
                {"min": 18, "label": "18K以上(高薪)", "color": "#7f1100"},
                {"min": 15, "max": 17.9, "label": "15-18K", "color": "#cc3311"},
                {"min": 12, "max": 14.9, "label": "12-15K", "color": "#ee6644"},
                {"min": 0,  "max": 11.9, "label": "12K以下", "color": "#ffaa55"},
            ],
        ),
    )
)

map_chart.render("03_salary_map.html")
print("薪资热力地图已生成:03_salary_map.html")

5.4 分析展现数据分析师岗位的学历要求

python 复制代码
# ============================================
# 分析目标4:数据分析师岗位的学历要求分析
# 使用饼图、柱状图、环形图等多种图表展现
# ============================================

import pandas as pd                                        # 导入pandas库
from pyecharts.charts import Pie, Bar, Page, Liquid, WordCloud  # 导入多种图表
from pyecharts import options as opts                      # 导入配置项
from pyecharts.globals import ThemeType                    # 导入主题

# ---------- 模拟学历要求数据 ----------
data = {
    "学历要求": (["本科"] * 4500 + ["硕士"] * 1200 +        # 本科4500条、硕士1200条
                 ["大专"] * 800 + ["博士"] * 150 +          # 大专800条、博士150条
                 ["不限"] * 350),                           # 不限350条
    "城市": (["北京"] * 800 + ["上海"] * 700 +              # 各城市的分布
             ["深圳"] * 600 + ["杭州"] * 500 +
             ["广州"] * 400 + ["成都"] * 300 +
             ["南京"] * 250 + ["武汉"] * 250 +
             ["西安"] * 200 + ["长沙"] * 200 +
             ["北京"] * 500 + ["上海"] * 400 +
             ["深圳"] * 350 + ["杭州"] * 300 +
             ["广州"] * 250 + ["成都"] * 200 +
             ["南京"] * 150 + ["武汉"] * 150 +
             ["西安"] * 100 + ["长沙"] * 100),
    # 注意:这里的city分布与edu对应仅做演示,实际应一一对应
}
df = pd.DataFrame(data)

# ---------- 1. 学历要求总体分布(环形饼图) ----------
edu_counts = df["学历要求"].value_counts()                 # 统计各学历出现次数
edu_data = list(zip(edu_counts.index.tolist(),             # 学历名称列表
                    edu_counts.values.tolist()))            # 数量列表

# 自定义颜色
colors = ["#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de"]

pie = (
    Pie(init_opts=opts.InitOpts(                           # 初始化
        theme=ThemeType.MACARONS,                          # 马卡龙主题
        width="800px",
        height="500px",
    ))
    .add(                                                  # 添加数据
        series_name="学历要求",                             # 系列名称
        data_pair=edu_data,                                # 数据
        radius=["35%", "65%"],                             # 环形图半径(内35%,外65%)
        center=["50%", "55%"],                             # 中心位置
        # 设置标签引导线
        label_opts=opts.LabelOpts(                         # 标签配置
            is_show=True,                                  # 显示标签
            formatter="{b}\n{c}个岗位\n占比{d}%",          # 格式:名称\n数量\n百分比
            font_size=11,                                  # 字体大小
        ),
        # 引导线配置
        label_linelength=20,                               # 引导线第一段长度
        label_linelength2=30,                              # 引导线第二段长度
        itemstyle_opts=opts.ItemStyleOpts(                 # 图元样式
            border_color="#fff",                           # 边框白色
            border_width=2,                                # 边框宽度
        ),
    )
    .set_colors(colors)                                    # 设置颜色列表
    .set_global_opts(
        title_opts=opts.TitleOpts(                         # 标题
            title="数据分析师岗位学历要求分布",              # 主标题
            subtitle="占比分析",                            # 副标题
            pos_left="center",
        ),
        legend_opts=opts.LegendOpts(                       # 图例
            orient="vertical",                             # 垂直排列
            pos_left="left",
            pos_top="middle",
        ),
        tooltip_opts=opts.TooltipOpts(                     # 提示框
            trigger="item",
            formatter="{a} <br/>{b}: {c} ({d}%)",         # 格式
        ),
    )
)

pie.render("04_edu_pie.html")
print("学历要求饼图已生成:04_edu_pie.html")

# ---------- 2. 各城市学历要求交叉分析(分组柱状图) ----------
# 创建城市-学历交叉表
cross_table = pd.crosstab(                                 # 创建交叉表
    df["城市"],                                            # 行:城市
    df["学历要求"],                                         # 列:学历
)
# 按本科学历数量降序排列
cross_table = cross_table.sort_values("本科", ascending=False)

# 提取数据
cities = cross_table.index.tolist()                        # 城市列表
edu_levels = ["本科", "硕士", "大专", "博士", "不限"]       # 学历级别列表

# 创建分组柱状图
bar = (
    Bar(init_opts=opts.InitOpts(                           # 初始化
        theme=ThemeType.ROMA,                              # 罗马主题
        width="1100px",
        height="500px",
    ))
    .add_xaxis(cities)                                     # 添加x轴数据(城市)
)

# 为每个学历级别添加一个系列
for i, edu in enumerate(edu_levels):                       # 遍历每个学历
    if edu in cross_table.columns:                         # 如果该学历存在
        bar.add_yaxis(                                     # 添加系列
            series_name=edu,                               # 系列名:学历名称
            y_axis=cross_table[edu].tolist(),              # 数据
            gap="10%",                                     # 柱体间距
            label_opts=opts.LabelOpts(is_show=False),      # 不显示标签(避免拥挤)
        )

bar.set_global_opts(                                       # 全局配置
    title_opts=opts.TitleOpts(
        title="各城市数据分析师岗位学历要求分布",
        subtitle="分组对比",
    ),
    tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow"),
    legend_opts=opts.LegendOpts(pos_top="8%"),
    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=30)),
    yaxis_opts=opts.AxisOpts(name="岗位数量"),
    datazoom_opts=[opts.DataZoomOpts(type_="slider")],
)

bar.render("04_edu_city_bar.html")
print("城市学历分组柱状图已生成:04_edu_city_bar.html")

# ---------- 3. 本科占比水球图 ----------
# 计算本科学历占比
total_jobs = len(df)                                       # 总岗位数
bachelor_count = (df["学历要求"] == "本科").sum()           # 本科岗位数
bachelor_ratio = round(bachelor_count / total_jobs, 2)    # 计算占比(保留2位小数)

liquid = (
    Liquid(init_opts=opts.InitOpts(width="500px", height="400px"))
    .add(
        series_name="本科占比",                             # 系列名称
        data=[bachelor_ratio],                             # 数据(0-1之间的比例值)
        shape="circle",                                    # 水球形状:圆形
        is_outline_show=True,                              # 显示外边框
        outline_itemstyle_opts=opts.ItemStyleOpts(         # 外边框样式
            border_color="#5470c6",                        # 边框颜色
            border_width=2,                                # 边框宽度
        ),
        label_opts=opts.LabelOpts(                         # 标签配置
            font_size=30,                                  # 字体大小
            formatter=f"本科要求\n{bachelor_ratio:.0%}",   # 格式化显示百分比
            color="#333",                                  # 字体颜色
        ),
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="本科及以上学历要求占比",
            pos_left="center",
        ),
    )
)

liquid.render("04_edu_liquid.html")
print("水球图已生成:04_edu_liquid.html")

# ---------- 4. 学历要求词云图 ----------
wordcloud = (
    WordCloud(init_opts=opts.InitOpts(width="600px", height="400px"))
    .add(
        series_name="学历要求",                             # 系列名称
        data_pair=edu_data,                                # 数据:[(词, 频率), ...]
        word_size_range=[20, 100],                         # 字体大小范围
        shape="circle",                                    # 词云形状:圆形
        textstyle_opts=opts.TextStyleOpts(                 # 文字样式
            font_family="Microsoft YaHei",                 # 字体
        ),
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="学历要求词云"),
    )
)

wordcloud.render("04_edu_wordcloud.html")
print("词云图已生成:04_edu_wordcloud.html")

六、综合实战------完整数据分析报告

6.1 使用 Page 组合多图成一页报告

python 复制代码
# ============================================
# 综合实战:使用 Page 将多个图表组合为一个完整的分析报告页面
# ============================================

from pyecharts.charts import Page                           # 导入页面组合类
from pyecharts import options as opts                       # 导入配置项

# 创建 Page 对象
page = Page(                                                # 实例化页面对象
    page_title="数据分析师岗位分析报告",                     # 浏览器标签页标题
    layout=Page.SimplePageLayout,                           # 页面布局方式:简单布局
)

# ---------- 将之前创建的所有图表添加到页面中 ----------
# 注意:此处需要引用前面已创建的图表对象
# 这里用简化方式演示,实际使用时需确保图表对象已被创建

# 方式一:逐个添加(add方法)
# page.add(chart1, chart2, chart3, ...)                    # 逐个添加图表

# 方式二:使用 Tab 选项卡布局
# page = Page(layout=Page.DraggablePageLayout)             # 可拖拽布局

# 为了演示完整性,这里重新创建简化的图表对象组合
from pyecharts.charts import Bar, Line, Pie, Map
from pyecharts.globals import ThemeType

# ----- 图表1:需求趋势(简化版) -----
line_chart = (
    Line(init_opts=opts.InitOpts(theme=ThemeType.VINTAGE, width="1000px", height="400px"))
    .add_xaxis(["1月", "2月", "3月", "4月", "5月", "6月"])
    .add_yaxis("岗位数量", [3200, 2800, 4100, 4500, 4800, 5200], is_smooth=True)
    .set_global_opts(title_opts=opts.TitleOpts(title="需求趋势"))
)

# ----- 图表2:热门城市(简化版) -----
bar_chart = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.VINTAGE, width="1000px", height="400px"))
    .add_xaxis(["北京", "上海", "深圳", "杭州", "广州"])
    .add_yaxis("岗位数量", [1200, 980, 850, 620, 580])
    .reversal_axis()
    .set_global_opts(title_opts=opts.TitleOpts(title="热门城市Top5"))
)

# ----- 图表3:学历分布(简化版) -----
pie_chart = (
    Pie(init_opts=opts.InitOpts(theme=ThemeType.VINTAGE, width="1000px", height="400px"))
    .add("学历要求", [("本科", 4500), ("硕士", 1200), ("大专", 800), ("博士", 150), ("不限", 350)])
    .set_global_opts(title_opts=opts.TitleOpts(title="学历要求分布"))
)

# ----- 图表4:薪资地图(简化版) -----
map_chart = (
    Map(init_opts=opts.InitOpts(theme=ThemeType.VINTAGE, width="1000px", height="400px"))
    .add("平均薪资", [("北京", 20), ("上海", 19), ("广东", 18), ("浙江", 16)], maptype="china")
    .set_global_opts(
        title_opts=opts.TitleOpts(title="薪资分布"),
        visualmap_opts=opts.VisualMapOpts(min_=10, max_=22, is_piecewise=True),
    )
)

# ---------- 将所有图表添加到页面 ----------
page.add(                                                  # 添加图表到页面
    line_chart,                                            # 图表1:需求趋势
    bar_chart,                                             # 图表2:热门城市
    pie_chart,                                             # 图表3:学历分布
    map_chart,                                             # 图表4:薪资地图
)

# ---------- 渲染页面 ----------
page.render("05_full_report.html")                         # 生成完整报告HTML
print("完整分析报告已生成:05_full_report.html")

6.2 数据导出与保存

python 复制代码
# ============================================
# 分析结果导出------保存为Excel和CSV文件
# ============================================

import pandas as pd                                        # 导入pandas库

# ---------- 假设已有分析结果数据 ----------
# 汇总分析结果
summary_data = {
    "分析维度": ["需求趋势", "热门城市", "薪资水平", "学历要求"],
    "核心发现": [
        "岗位需求同比增长25%,Q4为招聘旺季",
        "北京、上海、深圳位居前三,占比超40%",
        "一线城市平均薪资18-20K,新一线城市13-16K",
        "本科学历要求占64%,硕士占17%",
    ],
    "数据来源": ["招聘平台"] * 4,
    "分析日期": ["2024-12"] * 4,
}
summary_df = pd.DataFrame(summary_data)                    # 创建汇总DataFrame

# ---------- 保存为CSV ----------
summary_df.to_csv(                                         # 保存为CSV
    "analysis_summary.csv",                                # 文件名
    index=False,                                           # 不保存行索引
    encoding="utf-8-sig",                                  # 编码(兼容中文Excel)
)
print("CSV文件已保存:analysis_summary.csv")

# ---------- 保存为Excel ----------
# 使用 ExcelWriter 可以保存多个工作表到同一个Excel文件
with pd.ExcelWriter(                                       # 创建Excel写入器
    "data_analyst_analysis_report.xlsx",                   # 文件名
    engine="openpyxl",                                     # 使用openpyxl引擎
    mode="w",                                              # 写入模式:覆盖写入
) as writer:
    # 工作表1:分析汇总
    summary_df.to_excel(                                   # 写入工作表
        writer,                                            # Excel写入器
        sheet_name="分析汇总",                              # 工作表名称
        index=False,                                       # 不保存行索引
    )
    # 工作表2:城市薪资统计(示例)
    salary_df = pd.DataFrame({
        "城市": ["北京", "上海", "深圳", "杭州", "广州"],
        "平均薪资(K)": [20, 19, 18, 16, 15],
        "中位数薪资(K)": [19, 18, 17, 15, 14],
        "岗位数量": [1200, 980, 850, 620, 580],
    })
    salary_df.to_excel(writer, sheet_name="城市薪资统计", index=False)

    # 工作表3:学历要求统计(示例)
    edu_df = pd.DataFrame({
        "学历": ["本科", "硕士", "大专", "博士", "不限"],
        "岗位数量": [4500, 1200, 800, 150, 350],
        "占比": ["64.3%", "17.1%", "11.4%", "2.1%", "5.0%"],
    })
    edu_df.to_excel(writer, sheet_name="学历要求统计", index=False)

print("Excel报告已保存:data_analyst_analysis_report.xlsx")
print("包含3个工作表:分析汇总、城市薪资统计、学历要求统计")

七、本章小结------知识点总结

复制代码
┌──────────────────────────────────────────────────────────────┐
│                    第8章 核心知识点总结                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 数据分析流程                                              │
│     目标 → 收集 → 预处理 → 分析展现 → 结论                    │
│                                                              │
│  2. pyecharts 核心图表                                        │
│     ├── Bar()        柱状图                                  │
│     ├── Line()       折线图                                  │
│     ├── Pie()        饼图                                    │
│     ├── Map()        地图                                    │
│     ├── Boxplot()    箱线图                                  │
│     ├── Liquid()     水球图                                  │
│     ├── WordCloud()  词云图                                  │
│     ├── Grid()       网格组合                                │
│     ├── Page()       页面组合                                │
│     └── Timeline()   时间轴                                  │
│                                                              │
│  3. pyecharts 配置体系                                        │
│     ├── 全局配置 set_global_opts()                           │
│     │   ├── TitleOpts     标题                               │
│     │   ├── LegendOpts     图例                               │
│     │   ├── TooltipOpts   提示框                              │
│     │   ├── VisualMapOpts 视觉映射                            │
│     │   ├── DataZoomOpts  数据缩放                            │
│     │   └── AxisOpts      坐标轴                             │
│     └── 系列配置                                              │
│         ├── LabelOpts     标签                               │
│         ├── ItemStyleOpts 图元样式                            │
│         ├── MarkPointOpts 标记点                              │
│         └── MarkLineOpts  标记线                              │
│                                                              │
│  4. 数据预处理要点                                            │
│     ├── 缺失值:dropna() / fillna() / interpolate()         │
│     ├── 重复值:duplicated() / drop_duplicates()             │
│     ├── 类型转换:astype() / to_datetime() / to_numeric()   │
│     ├── 字符串处理:str.extract() / str.replace() / map()    │
│     └── 薪资解析:正则表达式 + apply()自定义函数              │
│                                                              │
│  5. 数据分析展现方法                                          │
│     ├── 趋势分析:折线图(Line)                              │
│     ├── 排名分析:柱状图(Bar)+ 水平翻转                     │
│     ├── 分布分析:饼图(Pie)+ 环形图                        │
│     ├── 地域分析:地图(Map)+ 视觉映射                       │
│     ├── 对比分析:分组柱状图 + 组合图                         │
│     └── 综合报告:Page 组合多图                               │
│                                                              │
│  6. 关键 pandas 方法                                          │
│     ├── value_counts()    统计频次                           │
│     ├── groupby().agg()   分组聚合                           │
│     ├── crosstab()        交叉表                             │
│     ├── sort_values()     排序                               │
│     ├── head() / tail()   预览数据                           │
│     └── to_csv() / to_excel()  导出数据                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘
相关推荐
段一凡-华北理工大学1 小时前
工业领域的Hadoop架构学习~系列文章18:制造业Hadoop应用实践 - 从数据到智能的完整闭环
大数据·人工智能·hadoop·分布式·学习·架构·高炉炼铁
Wonderful U1 小时前
Python+Django实战:打造智能生鲜果蔬进销存管理系统(采购入库、库存预警、销售开单、毛利统计)
数据库·python·django
.千余1 小时前
【C++】深挖STL list底层:解迭代器与节点存储逻辑
开发语言·c++·笔记·学习·其他
yuhuofei20211 小时前
【Python入门】Python中的集合set
python
skywalk81631 小时前
我想基于kotti-py312 ,制作一个多中文编程语言的宣传网站,主要包括文档、playground 示例和学习 (Codearts制作)
开发语言·学习·编程
大雨淅淅1 小时前
【机器人】ROS2 机械臂控制(MoveIt2)从入门到实战
人工智能·python·神经网络·学习·算法·机器学习·机器人
星雨流星天的笔记本1 小时前
英语介词学习
学习
zhangrelay1 小时前
2000-2025 年适龄升学智能大模型整理数据
大数据·笔记·学习
RD_daoyi1 小时前
GEO优化能为企业带来哪些价值?
大数据·人工智能·学习·搜索引擎·chatgpt