课程亮点
NumPy + Pandas + Matplotlib + Seaborn 一站式掌握
使用真实电商/销售数据进行清洗和分析实战
从基础图表到高级可视化,让数据说话
学习路径
适合人群
· 已掌握Python基础语法的同学
· 想系统学习数据分析工具的同学
· 需要用数据驱动业务决策的同学
· Python基础语法(变量、函数、列表等)
· 基础数学统计概念(均值、标准差等)
学完能做什么
学完本课程,你将能够:
- 使用Pandas处理Excel/CSV等格式的业务数据
- 完成数据清洗、转换、分析的全流程操作
- 制作专业的数据可视化报表和Dashboard
- 基于数据输出有价值的业务分析报告
数据分析概述
1.1 什么是数据分析
数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论,从而对数据加以详细研究和概括总结的过程。在当今数字化时代,数据分析已经成为各行各业决策的核心驱动力。
数据分析的核心目标是:发现问题、定位原因、预测趋势、辅助决策。无论是互联网公司的用户增长分析,还是传统零售企业的销售数据挖掘,数据分析都扮演着不可或缺的角色。
1.2 数据分析的完整流程
一个标准的数据分析项目通常包含以下六个阶段:
- 明确需求 —— 与业务方沟通,确定分析目标和关键问题
- 数据采集 —— 从数据库、API、日志、问卷等渠道获取原始数据
- 数据清洗 —— 处理缺失值、异常值、重复数据,保证数据质量
- 数据分析 —— 运用统计方法和工具对数据进行深入挖掘
- 数据可视化 —— 用图表直观展示分析结果
- 撰写报告 —— 输出分析结论和业务建议
1.3 数据分析的应用场景
| 行业领域 | 典型应用 | 常用分析方法 |
|---|---|---|
| 电商 | 用户画像、推荐系统、销售预测 | 关联分析、聚类分析、回归分析 |
| 金融 | 风险评估、信用评分、欺诈检测 | 分类模型、时间序列分析 |
| 医疗 | 疾病预测、药物效果评估 | 生存分析、假设检验 |
| 教育 | 学情分析、课程推荐 | 描述性统计、A/B 测试 |
| 运营 | 留存分析、转化漏斗、用户分群 | 漏斗分析、同期群分析 |
1.4 常用工具对比
选择合适的数据分析工具能大幅提升工作效率。以下是三种主流工具的对比:
# 使用 pip 安装数据分析核心库
pip install numpy pandas matplotlib seaborn
# 在 Jupyter Notebook 中验证安装
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
print("NumPy 版本:", np.__version__)
print("Pandas 版本:", pd.__version__)
print("所有库安装成功!")
| 工具 | 优势 | 适用场景 | 学习难度 |
|---|---|---|---|
| Excel | 操作直观、门槛低 | 小规模数据、快速分析 | 低 |
| Python | 生态丰富、可复现 | 大规模数据、自动化流程 | 中 |
| R | 统计功能强大 | 学术研究、高级统计建模 | 中高 |
1.5 数据分析思维
掌握工具只是基础,更重要的是培养数据分析思维。以下是几种常用的分析思维框架:
- 漏斗思维:将业务流程拆解为多个阶段,分析每个阶段的转化率,找出流失环节
- 对比思维:通过与目标值、历史值、行业均值对比,发现差异和问题
- 细分思维:从多维度(时间、地区、用户类型)拆解数据,找到关键驱动因素
- 溯源思维:发现异常指标后,逐层下钻找到根本原因
- 预测思维:基于历史数据建立模型,预测未来趋势和风险
# 一个简单的数据分析示例:分析学生成绩
scores = {
"姓名": ["张三", "李四", "王五", "赵六", "钱七"],
"数学": [85, 92, 78, 95, 88],
"英语": [90, 88, 82, 79, 93],
"Python": [95, 90, 85, 92, 97]
}
import pandas as pd
df = pd.DataFrame(scores)
df["总分"] = df["数学"] + df["英语"] + df["Python"]
df["平均分"] = df["总分"] / 3
print("=== 学生成绩表 ===")
print(df.to_string(index=False))
print(f"\n最高总分: {df['总分'].max()}")
print(f"班级平均分: {df['平均分'].mean():.1f}")
NumPy数值计算
2.1 NumPy 简介
NumPy(Numerical Python)是 Python 中最基础的科学计算库,提供了高性能的多维数组对象以及丰富的数学函数。它是 Pandas、Matplotlib、Scikit-learn 等高级库的底层依赖,是数据分析学习路径中必须掌握的第一个库。
NumPy 的核心优势在于:向量化运算避免了 Python 循环的低效问题,使得大规模数值计算的速度比纯 Python 快数十倍甚至上百倍。
2.2 数组创建与属性
NumPy 的核心数据结构是 ndarray(N 维数组)。以下展示了几种常见的数组创建方式:
import numpy as np
# 从列表创建一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print("一维数组:", arr1)
# 从嵌套列表创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print("二维数组:\n", arr2)
# 创建特殊数组
zeros = np.zeros((3, 4)) # 3行4列的全零数组
ones = np.ones((2, 3)) # 2行3列的全一数组
empty = np.empty((2, 2)) # 未初始化数组(值不确定)
full = np.full((2, 3), 7) # 2行3列,全部填充7
print("全零数组:\n", zeros)
# 创建等差数列
arange_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace_arr = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]
print("等差数列:", arange_arr)
print("等分数列:", linspace_arr)
# 创建随机数组
rand_arr = np.random.rand(3, 3) # 3x3 均匀分布随机数
randn_arr = np.random.randn(3, 3) # 3x3 标准正态分布随机数
randint_arr = np.random.randint(0, 100, (3, 3)) # 0-99随机整数
print("随机整数数组:\n", randint_arr)
每个 NumPy 数组都有以下重要属性:
| 属性 | 说明 | 示例结果 |
|---|---|---|
ndim | 数组的维度数 | 2 |
shape | 数组各维度的大小 | (3, 4) |
size | 数组元素的总数 | 12 |
dtype | 数组元素的数据类型 | float64 |
itemsize | 每个元素的字节大小 | 8 |
arr = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print("维度:", arr.ndim) # 2
print("形状:", arr.shape) # (2, 3)
print("元素总数:", arr.size) # 6
print("数据类型:", arr.dtype) # float64
print("每个元素字节:", arr.itemsize) # 8
2.3 数组运算
NumPy 支持对数组进行元素级别的运算,无需编写循环。这是 NumPy 性能优势的核心来源。
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# 算术运算(逐元素)
print("加法:", a + b) # [11 22 33 44]
print("减法:", b - a) # [ 9 18 27 36]
print("乘法:", a * b) # [ 10 40 90 160]
print("除法:", b / a) # [10. 10. 10. 10.]
print("幂运算:", a ** 2) # [ 1 4 9 16]
# 比较运算(返回布尔数组)
print("大于2:", a > 2) # [False False True True]
# 标量运算(广播机制)
print("每个元素+5:", a + 5) # [6 7 8 9]
# 常用统计函数
data = np.array([12, 5, 8, 23, 16, 9, 7])
print("均值:", np.mean(data)) # 11.43
print("中位数:", np.median(data)) # 9.0
print("标准差:", np.std(data)) # 5.87
print("最大值:", np.max(data)) # 23
print("最小值索引:", np.argmin(data)) # 1
2.4 索引与切片
NumPy 数组的索引和切片语法与 Python 列表类似,但功能更强大,支持多维索引和布尔索引。
import numpy as np
arr = np.array([10, 20, 30, 40, 50, 60, 70, 80])
# 基本索引(从0开始)
print("第1个元素:", arr[0]) # 10
print("最后一个:", arr[-1]) # 80
# 切片 [start:stop:step]
print("前3个:", arr[:3]) # [10 20 30]
print("第2到第5:", arr[1:5]) # [20 30 40 50]
print("每隔一个:", arr[::2]) # [10 30 50 70]
# 二维数组索引
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("第1行:", matrix[0]) # [1 2 3]
print("第2行第3列:", matrix[1, 2]) # 6
print("第1列:", matrix[:, 0]) # [1 4 7]
print("前两行:", matrix[:2, :]) # [[1 2 3] [4 5 6]]
# 布尔索引
scores = np.array([65, 90, 78, 55, 88, 92, 43])
passed = scores[scores >= 60]
print("及格成绩:", passed) # [65 90 78 88 92]
2.5 常用数学函数
NumPy 提供了丰富的数学函数,可以直接作用于整个数组,实现向量化计算:
import numpy as np
arr = np.array([1, 4, 9, 16, 25])
# 数学运算
print("平方根:", np.sqrt(arr)) # [1. 2. 3. 4. 5.]
print("绝对值:", np.abs(arr)) # [ 1 4 9 16 25]
print("自然对数:", np.log(arr)) # [0. 1.386 2.197 2.773 3.219]
print("以10为底对数:", np.log10(arr))
print("四舍五入:", np.round(np.sqrt(arr), 2))
# 三角函数
angles = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
print("正弦值:", np.round(np.sin(angles), 3))
print("余弦值:", np.round(np.cos(angles), 3))
# 线性代数运算
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print("矩阵乘法:\n", A @ B) # @ 运算符进行矩阵乘法
print("矩阵转置:\n", A.T)
print("行列式:", np.linalg.det(A)) # -2.0
print("逆矩阵:\n", np.linalg.inv(A))
2.6 数组形状变换
在实际数据处理中,经常需要改变数组的形状。NumPy 提供了 reshape、transpose、flatten 等方法来灵活调整数组维度。
import numpy as np
# reshape: 改变数组形状(不改变数据)
arr = np.arange(12)
print("原始:", arr) # [ 0 1 2 ... 11]
print("3x4:", arr.reshape(3, 4))
print("2x6:", arr.reshape(2, 6))
print("3x2x2:", arr.reshape(3, 2, 2))
# flatten: 展平为一维数组
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print("展平:", matrix.flatten()) # [1 2 3 4 5 6]
# transpose: 转置
data = np.array([[1, 2, 3], [4, 5, 6]])
print("转置:\n", data.T)
# [[1 4]
# [2 5]
# [3 6]]
# 拼接数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print("水平拼接:", np.concatenate([a, b])) # [1 2 3 4 5 6]
# 堆叠数组
print("垂直堆叠:\n", np.vstack([a, b]))
print("水平堆叠:\n", np.hstack([a, b]))
reshape(-1) 可以自动计算某一维度的大小。例如 arr.reshape(3, -1) 会自动将列数计算为 4(总共12个元素 / 3行 = 4列),非常方便。Pandas数据处理
3.1 Pandas 简介
Pandas 是 Python 中最强大的数据分析和处理库,提供了两种核心数据结构:Series(一维数据)和 DataFrame(二维表格数据)。Pandas 让数据的读取、清洗、转换、分析变得简单高效,是数据分析工作中使用频率最高的库。
3.2 Series 和 DataFrame
Series 是带标签的一维数组,DataFrame 是带行列标签的二维表格。它们是 Pandas 的基础,几乎所有操作都围绕这两种数据结构展开。
import pandas as pd
# 创建 Series
s = pd.Series([85, 92, 78, 95, 88],
index=["张三", "李四", "王五", "赵六", "钱七"],
name="数学成绩")
print(s)
# 张三 85
# 李四 92
# 王五 78
# 赵六 95
# 钱七 88
# Name: 数学成绩, dtype: int64
# Series 常用属性
print("值:", s.values) # [85 92 78 95 88]
print("索引:", s.index) # Index(['张三', '李四', ...])
print("数据类型:", s.dtype) # int64
# Series 统计方法
print("均值:", s.mean()) # 87.6
print("最大值:", s.max()) # 95
print("描述统计:\n", s.describe())
import pandas as pd
# 从字典创建 DataFrame
data = {
"姓名": ["张三", "李四", "王五", "赵六", "钱七"],
"年龄": [20, 21, 19, 22, 20],
"城市": ["北京", "上海", "广州", "深圳", "杭州"],
"成绩": [85, 92, 78, 95, 88]
}
df = pd.DataFrame(data)
print(df)
# 姓名 年龄 城市 成绩
# 0 张三 20 北京 85
# 1 李四 21 上海 92
# ...
# 查看基本信息
print("形状:", df.shape) # (5, 4)
print("列名:", df.columns.tolist()) # ['姓名', '年龄', '城市', '成绩']
print("数据类型:\n", df.dtypes)
print("前3行:\n", df.head(3))
print("描述统计:\n", df.describe())
3.3 数据读取
Pandas 支持读取多种格式的数据文件,最常用的是 CSV 和 Excel 文件。
import pandas as pd
# 读取 CSV 文件
df_csv = pd.read_csv("data.csv", encoding="utf-8")
df_csv = pd.read_csv("data.csv",
encoding="utf-8",
header=0, # 指定表头所在行
index_col=0, # 指定索引列
usecols=["姓名", "成绩"], # 只读取指定列
nrows=100 # 只读取前100行
)
# 读取 Excel 文件
df_excel = pd.read_excel("data.xlsx", sheet_name="Sheet1")
# 读取 JSON 文件
df_json = pd.read_json("data.json")
# 保存数据
df.to_csv("output.csv", index=False, encoding="utf-8-sig")
df.to_excel("output.xlsx", sheet_name="结果", index=False)
encoding="gbk" 或 encoding="utf-8-sig"。保存 CSV 时使用 utf-8-sig 编码可以避免在 Excel 中打开出现乱码。3.4 数据筛选与过滤
数据筛选是数据分析中最常用的操作之一。Pandas 提供了多种灵活的方式来筛选数据。
import pandas as pd
df = pd.DataFrame({
"姓名": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"部门": ["技术", "市场", "技术", "财务", "市场", "技术"],
"薪资": [15000, 12000, 18000, 14000, 13000, 16000],
"年龄": [25, 28, 30, 26, 24, 32]
})
# 选择单列
print(df["姓名"])
# 选择多列
print(df[["姓名", "薪资"]])
# 条件筛选
tech = df[df["部门"] == "技术"]
print("技术部门:\n", tech)
# 多条件筛选(& 与,| 或,~ 非)
high_salary = df[(df["薪资"] >= 15000) & (df["年龄"] < 30)]
print("高薪年轻员工:\n", high_salary)
# 使用 isin 筛选
target_dept = df[df["部门"].isin(["技术", "财务"])]
print("技术或财务:\n", target_dept)
# 使用 query 方法(更简洁的语法)
result = df.query("薪资 > 14000 and 部门 == '技术'")
print(result)
3.5 数据清洗
真实世界的数据往往是不完整的、有噪声的。数据清洗是保证分析质量的关键步骤。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"姓名": ["张三", "李四", "王五", "赵六", "钱七"],
"年龄": [25, np.nan, 30, 26, np.nan],
"薪资": [15000, 12000, np.nan, 14000, 13000],
"城市": ["北京", "上海", "广州", None, "杭州"]
})
# 检查缺失值
print("各列缺失值数量:\n", df.isnull().sum())
print("缺失值总数:", df.isnull().sum().sum())
# 删除缺失值
df_drop = df.dropna() # 删除任何含缺失值的行
df_drop_col = df.dropna(subset=["年龄"]) # 只检查指定列
# 填充缺失值
df_fill_zero = df.fillna(0) # 用0填充
df_fill_mean = df.fillna({"年龄": df["年龄"].mean(), "薪资": df["薪资"].median()})
# 用均值填充年龄,用中位数填充薪资
# 前向填充 / 后向填充
df_ffill = df.ffill() # 用前一个有效值填充
df_bfill = df.bfill() # 用后一个有效值填充
import pandas as pd
df = pd.DataFrame({
"姓名": ["张三", "李四", "张三", "王五", "李四"],
"城市": ["北京", "上海", "北京", "广州", "上海"],
"薪资": [15000, 12000, 15000, 14000, 12000]
})
# 检查重复行
print("重复行数量:", df.duplicated().sum())
# 删除重复行
df_unique = df.drop_duplicates()
print("去重后:\n", df_unique)
# 基于指定列去重
df_unique_name = df.drop_duplicates(subset=["姓名"])
print("按姓名去重:\n", df_unique_name)
# 替换值
df["城市"] = df["城市"].replace("北京", "北京市")
df.info() 可以快速查看数据概览(总行数、各列数据类型、非空值数量),配合 df.duplicated().sum() 检查重复值,这两个命令是数据清洗的第一步。3.6 数据分组与聚合
groupby 是 Pandas 中最强大的功能之一,它实现了 SQL 中的 "GROUP BY" 操作,可以按类别对数据进行分组统计。
import pandas as pd
df = pd.DataFrame({
"部门": ["技术", "技术", "市场", "市场", "市场", "财务", "财务"],
"姓名": ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九"],
"薪资": [15000, 18000, 12000, 13000, 14000, 16000, 15000],
"绩效": [85, 92, 78, 88, 82, 90, 86]
})
# 按部门分组,计算均值
print("各部门平均薪资:\n", df.groupby("部门")["薪资"].mean())
# 多种聚合函数
result = df.groupby("部门").agg({
"薪资": ["mean", "max", "min", "count"],
"绩效": ["mean", "std"]
})
print("多指标聚合:\n", result)
# 自定义聚合函数
def salary_range(x):
return x.max() - x.min()
print("薪资极差:\n", df.groupby("部门")["薪资"].agg(salary_range))
# 分组后筛选(transform)
df["部门平均薪资"] = df.groupby("部门")["薪资"].transform("mean")
df["薪资偏差"] = df["薪资"] - df["部门平均薪资"]
print(df)
agg() 方法可以同时应用多个聚合函数,返回多级列名的结果。如果觉得多级列名不方便处理,可以在聚合后使用 df.columns = ['_'.join(col).strip() for col in df.columns.values] 将多级列名展平。数据可视化
4.1 数据可视化概述
数据可视化是将数据转化为图形的过程,目的是让复杂的数据变得直观易懂。好的可视化能够揭示数据中隐藏的模式、趋势和异常,帮助决策者快速理解信息。
Python 中最常用的可视化库是 Matplotlib(基础绘图库)和 Seaborn(基于 Matplotlib 的高级统计可视化库)。Seaborn 提供了更美观的默认样式和更简洁的 API。
| 图表类型 | 适用场景 | 推荐库 |
|---|---|---|
| 折线图 | 展示数据随时间的变化趋势 | Matplotlib |
| 柱状图 | 比较不同类别的数值大小 | Matplotlib / Seaborn |
| 散点图 | 展示两个变量之间的关系 | Matplotlib / Seaborn |
| 热力图 | 展示相关系数矩阵或密度分布 | Seaborn |
| 箱线图 | 展示数据分布和异常值 | Seaborn |
| 直方图 | 展示数据的频率分布 | Matplotlib / Seaborn |
4.2 Matplotlib 基础
Matplotlib 是 Python 最经典的绘图库,几乎可以绘制任何类型的静态图表。掌握 Matplotlib 是学习其他可视化库的基础。
import matplotlib.pyplot as plt
# 设置中文字体(避免中文显示为方块)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# ===== 折线图:月度销售趋势 =====
months = ['1月', '2月', '3月', '4月', '5月', '6月']
sales_a = [120, 135, 148, 162, 155, 178]
sales_b = [95, 110, 125, 138, 142, 150]
plt.figure(figsize=(10, 5))
plt.plot(months, sales_a, marker='o', linewidth=2,
color='#2563eb', label='产品A')
plt.plot(months, sales_b, marker='s', linewidth=2,
color='#f59e0b', label='产品B')
plt.title('月度销售趋势对比', fontsize=16)
plt.xlabel('月份', fontsize=12)
plt.ylabel('销售额(万元)', fontsize=12)
plt.legend(fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('line_chart.png', dpi=150)
plt.show()
# ===== 柱状图:各部门平均薪资 =====
departments = ['技术部', '市场部', '财务部', '人事部']
avg_salary = [16500, 13000, 15500, 12000]
colors = ['#2563eb', '#06b6d4', '#8b5cf6', '#f59e0b']
plt.figure(figsize=(8, 5))
bars = plt.bar(departments, avg_salary, color=colors, width=0.6,
edgecolor='white', linewidth=1.5)
# 在柱子上方添加数值标签
for bar, val in zip(bars, avg_salary):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 200,
f'{val}', ha='center', fontsize=11, fontweight='bold')
plt.title('各部门平均薪资', fontsize=16)
plt.ylabel('平均薪资(元)', fontsize=12)
plt.tight_layout()
plt.savefig('bar_chart.png', dpi=150)
plt.show()
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 生成模拟数据:学习时间 vs 考试成绩
np.random.seed(42)
study_hours = np.random.uniform(1, 10, 50)
scores = 40 + study_hours * 5 + np.random.normal(0, 5, 50)
plt.figure(figsize=(8, 6))
plt.scatter(study_hours, scores, c=scores, cmap='coolwarm',
s=80, alpha=0.7, edgecolors='white', linewidth=0.5)
plt.colorbar(label='考试成绩')
plt.title('学习时间与考试成绩的关系', fontsize=16)
plt.xlabel('每周学习时间(小时)', fontsize=12)
plt.ylabel('考试成绩(分)', fontsize=12)
# 添加趋势线
z = np.polyfit(study_hours, scores, 1)
p = np.poly1d(z)
plt.plot(sorted(study_hours), p(sorted(study_hours)),
'--', color='#ef4444', linewidth=2, label='趋势线')
plt.legend(fontsize=12)
plt.tight_layout()
plt.savefig('scatter_chart.png', dpi=150)
plt.show()
4.3 Seaborn 高级可视化
Seaborn 基于 Matplotlib 构建,提供了更高级的统计图表接口和更美观的默认样式。特别适合绘制统计分布图和关系图。
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 创建学生成绩数据
scores_df = pd.DataFrame({
'数学': [85, 92, 78, 95, 88, 76, 90, 82, 94, 87],
'英语': [90, 88, 82, 79, 93, 85, 91, 80, 86, 89],
'物理': [78, 85, 90, 88, 76, 92, 84, 87, 91, 83],
'化学': [82, 79, 88, 91, 85, 78, 86, 93, 80, 90],
'生物': [88, 91, 75, 83, 90, 87, 79, 85, 92, 86]
}, index=['学生'+str(i) for i in range(1, 11)])
# 计算相关系数矩阵
corr = scores_df.corr()
# 绘制热力图
plt.figure(figsize=(8, 6))
sns.heatmap(corr, annot=True, fmt='.2f', cmap='RdBu_r',
center=0, square=True, linewidths=1,
cbar_kws={'shrink': 0.8})
plt.title('各科目成绩相关系数热力图', fontsize=16, pad=15)
plt.tight_layout()
plt.savefig('heatmap.png', dpi=150)
plt.show()
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 创建不同城市薪资数据
np.random.seed(42)
cities = ['北京', '上海', '广州', '深圳', '杭州']
data = []
for city in cities:
base = {'北京': 15000, '上海': 14500, '广州': 12000,
'深圳': 14000, '杭州': 13000}[city]
salaries = np.random.normal(base, 2000, 50).clip(6000, 25000)
for s in salaries:
data.append({'城市': city, '月薪': int(s)})
df = pd.DataFrame(data)
# 绘制箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(x='城市', y='月薪', data=df, palette='Set2',
width=0.5, fliersize=3)
plt.title('各城市薪资分布箱线图', fontsize=16)
plt.ylabel('月薪(元)', fontsize=12)
plt.xlabel('')
plt.tight_layout()
plt.savefig('boxplot.png', dpi=150)
plt.show()
4.4 图表美化技巧
好的可视化不仅要准确传达数据信息,还要美观专业。以下是一些常用的美化技巧:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 使用 Seaborn 主题风格
import seaborn as sns
sns.set_theme(style="whitegrid", font_scale=1.2)
# 数据准备
categories = ['Q1', 'Q2', 'Q3', 'Q4']
revenue = [280, 350, 420, 390]
cost = [180, 220, 260, 240]
profit = [r - c for r, c in zip(revenue, cost)]
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# 左图:堆叠柱状图
x = np.arange(len(categories))
width = 0.5
axes[0].bar(x, cost, width, label='成本', color='#94a3b8', edgecolor='white')
axes[0].bar(x, profit, width, bottom=cost, label='利润', color='#2563eb', edgecolor='white')
axes[0].set_title('季度收入构成', fontsize=14, fontweight='bold', pad=10)
axes[0].set_xticks(x)
axes[0].set_xticklabels(categories)
axes[0].set_ylabel('金额(万元)')
axes[0].legend(frameon=True, fancybox=True, shadow=True)
axes[0].spines['top'].set_visible(False)
axes[0].spines['right'].set_visible(False)
# 右图:利润率折线图
profit_rate = [p/r*100 for p, r in zip(profit, revenue)]
axes[1].fill_between(categories, profit_rate, alpha=0.2, color='#2563eb')
axes[1].plot(categories, profit_rate, 'o-', color='#2563eb',
linewidth=2.5, markersize=8)
for i, (cat, rate) in enumerate(zip(categories, profit_rate)):
axes[1].annotate(f'{rate:.1f}%', (cat, rate),
textcoords="offset points", xytext=(0, 12),
ha='center', fontsize=11, fontweight='bold')
axes[1].set_title('季度利润率趋势', fontsize=14, fontweight='bold', pad=10)
axes[1].set_ylabel('利润率(%)')
axes[1].set_ylim(25, 45)
axes[1].spines['top'].set_visible(False)
axes[1].spines['right'].set_visible(False)
plt.tight_layout()
plt.savefig('beautiful_charts.png', dpi=150, bbox_inches='tight')
plt.show()
spines['top'].set_visible(False) 和 spines['right'].set_visible(False) 隐藏顶部和右侧边框,可以让图表看起来更简洁专业。- 配色方案:使用统一的配色方案,推荐使用 ColorBrewer 或 Seaborn 内置调色板(如
Set2、husl) - 字体大小:标题 14-18pt,坐标轴标签 11-13pt,刻度标签 10-11pt,保持层次感
- 图例位置:避免遮挡数据,优先放在图表上方或右侧空白区域
- 保存格式:推荐保存为 PNG(
dpi=150以上)或 PDF(矢量图,适合论文和报告) - 子图布局:使用
plt.subplots()创建多子图,配合tight_layout()自动调整间距