5.5 数据分析和可视化
概述
🎯 小白理解:什么是"数据分析"和"可视化"?
想象你是一个奶茶店老板:
- 原始数据:每天的销售记录(日期、产品、数量、金额)
- 数据分析:从记录中发现规律(周末卖得多、珍珠奶茶最火)
- 可视化:画成图表,一眼就能看懂趋势
原始数据 (Excel/数据库) ↓ 数据分析 (找规律) 洞察 (珍珠奶茶销量增长 30%) ↓ 可视化 (画图) 📊 图表 (老板一看就懂)为什么 Python 适合做数据分析?
- 库丰富:NumPy、Pandas、Matplotlib 等
- 代码可复用:同样的分析逻辑,换数据就能用
- 和 AI 结合:分析结果可以喂给机器学习模型
数据分析和可视化是 Python 最强大的应用领域之一。本节介绍五个核心库:
- NumPy:高效数值计算
- Pandas:数据分析和处理
- Matplotlib:基础绑图库
- Seaborn:统计可视化
- Plotly:交互式图表
提示:请在本地 Python 环境中运行代码。建议使用 Jupyter Notebook 以便直接查看图表输出。
NumPy:数值计算基础
🎯 小白理解:为什么需要 NumPy?
Python 自带的列表
list处理数字很慢,NumPy 的数组快 100 倍!类比:
list:一个一个手动算(for循环)numpy:一次性批量算(向量化运算)python# 普通 Python 列表(慢) result = [] for x in [1, 2, 3, 4]: result.append(x * 2) # NumPy 数组(快 100 倍) import numpy as np result = np.array([1, 2, 3, 4]) * 2 # 一行搞定!核心概念:
概念 解释 类比 ndarrayNumPy 的数组类型 高效版的 list shape数组的形状 (几行几列) 矩阵的尺寸 向量化运算 不用循环,直接对整个数组操作 批处理 vs 单个处理
NumPy 是科学计算的基石,提供高性能的多维数组运算。
数组创建和基本操作
import numpy as np
# 创建数组
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print("一维数组:", arr1)
print("二维数组:")
print(arr2)
print(f"形状: {arr2.shape}, 维度: {arr2.ndim}")
# 特殊数组
zeros = np.zeros((3, 3))
ones = np.ones((2, 4))
eye = np.eye(3) # 单位矩阵
print("\n零矩阵:")
print(zeros)
print("\n单位矩阵:")
print(eye)
# 数值范围
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace_arr = np.linspace(0, 1, 5) # 等间距 5 个点
print(f"\narange: {range_arr}")
print(f"linspace: {linspace_arr}")输出:
一维数组: [1 2 3 4 5]
二维数组:
[[1 2 3]
[4 5 6]]
形状: (2, 3), 维度: 2
零矩阵:
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
单位矩阵:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
arange: [0 2 4 6 8]
linspace: [0. 0.25 0.5 0.75 1. ]数组运算
import numpy as np
# 向量化运算(比 Python 循环快 100 倍)
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
print("加法:", a + b)
print("乘法:", a * b)
print("平方:", a ** 2)
print("求和:", np.sum(a))
print("均值:", np.mean(a))
print("标准差:", np.std(a))
# 矩阵运算
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
print("\n矩阵乘法:")
print(np.dot(matrix_a, matrix_b)) # 或 matrix_a @ matrix_b
# 统计函数
data = np.random.randn(1000) # 1000 个标准正态分布随机数
print(f"\n随机数统计:")
print(f"均值: {np.mean(data):.4f}")
print(f"标准差: {np.std(data):.4f}")
print(f"最小值: {np.min(data):.4f}")
print(f"最大值: {np.max(data):.4f}")输出:
加法: [11 22 33 44]
乘法: [ 10 40 90 160]
平方: [ 1 4 9 16]
求和: 10
均值: 2.5
标准差: 1.118033988749895
矩阵乘法:
[[19 22]
[43 50]]
随机数统计:
均值: 0.0156
标准差: 1.0023
最小值: -3.2145
最大值: 3.1876Pandas:数据分析利器
🎯 小白理解:Pandas 是什么?
Pandas = Python 版的 Excel,但更强大!
Excel Pandas 优势 手动操作 写代码自动化 可重复执行 百万行就卡 处理更大数据 性能更好 复杂公式难维护 代码清晰可读 易于调试 核心概念:
- DataFrame:二维表格(像 Excel 的工作表)
- Series:一列数据(像 Excel 的一列)
DataFrame 结构: 姓名 年龄 城市 薪资 0 张三 25 北京 15000 ← 行 (row) 1 李四 30 上海 20000 2 王五 35 广州 18000 ↑ 列 (column)常用操作:
df.head()→ 看前几行df['列名']→ 选择一列df[df['年龄'] > 28]→ 条件筛选df.groupby('部门').mean()→ 分组统计
Pandas 提供 DataFrame 数据结构,是数据分析的标准工具。
创建和查看数据
import pandas as pd
import numpy as np
# 从字典创建 DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六', '钱七'],
'年龄': [25, 30, 35, 28, 32],
'城市': ['北京', '上海', '广州', '深圳', '杭州'],
'薪资': [15000, 20000, 18000, 22000, 25000]
}
df = pd.DataFrame(data)
print("DataFrame 内容:")
print(df)
print(f"\n数据形状: {df.shape}")
print(f"\n数据类型:\n{df.dtypes}")
print(f"\n统计摘要:\n{df.describe()}")输出:
DataFrame 内容:
姓名 年龄 城市 薪资
0 张三 25 北京 15000
1 李四 30 上海 20000
2 王五 35 广州 18000
3 赵六 28 深圳 22000
4 钱七 32 杭州 25000
数据形状: (5, 4)
数据类型:
姓名 object
年龄 int64
城市 object
薪资 int64
dtype: object
统计摘要:
年龄 薪资
count 5.000000 5.000000
mean 30.000000 20000.000000
std 3.807887 3807.886553
min 25.000000 15000.000000
25% 28.000000 18000.000000
50% 30.000000 20000.000000
75% 32.000000 22000.000000
max 35.000000 25000.000000数据筛选和操作
import pandas as pd
# 创建示例数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '钱七'],
'年龄': [25, 30, 35, 28, 32],
'部门': ['技术', '销售', '技术', '销售', '技术'],
'薪资': [15000, 20000, 18000, 22000, 25000]
}
df = pd.DataFrame(data)
# 选择列
print("选择单列:")
print(df['姓名'])
print("\n选择多列:")
print(df[['姓名', '薪资']])
# 条件筛选
print("\n年龄大于 28 的员工:")
print(df[df['年龄'] > 28])
print("\n技术部门的员工:")
print(df[df['部门'] == '技术'])
# 多条件筛选
print("\n技术部门且薪资大于 17000:")
print(df[(df['部门'] == '技术') & (df['薪资'] > 17000)])
# 添加新列
df['年薪'] = df['薪资'] * 12
print("\n添加年薪列:")
print(df)
# 分组统计
print("\n按部门统计平均薪资:")
print(df.groupby('部门')['薪资'].mean())读写文件
import pandas as pd
# 创建示例数据并保存
data = {
'产品': ['手机', '电脑', '平板', '耳机'],
'销量': [1000, 500, 800, 1500],
'单价': [5000, 8000, 3000, 500]
}
df = pd.DataFrame(data)
# 保存为 CSV
df.to_csv('sales_data.csv', index=False, encoding='utf-8')
print("已保存为 sales_data.csv")
# 读取 CSV
df_loaded = pd.read_csv('sales_data.csv', encoding='utf-8')
print("\n读取的数据:")
print(df_loaded)
# 保存为 JSON
df.to_json('sales_data.json', orient='records', force_ascii=False, indent=2)
print("\n已保存为 sales_data.json")Matplotlib:基础绑图
🎯 小白理解:Matplotlib 是什么?
Matplotlib = Python 的画图工具,可以画各种统计图表。
常见图表类型:
图表 用途 适合场景 折线图 展示趋势变化 股票走势、销售趋势 柱状图 对比大小 各部门业绩对比 饼图 展示占比 市场份额分布 散点图 看变量关系 身高 vs 体重 基本套路(记住这个模式):
pythonimport matplotlib.pyplot as plt # 1. 创建画布 plt.figure(figsize=(10, 6)) # 2. 画图 plt.plot(x, y) # 折线图 # plt.bar(x, y) # 柱状图 # plt.pie(sizes) # 饼图 # 3. 添加标题和标签 plt.title('标题') plt.xlabel('X轴') plt.ylabel('Y轴') # 4. 保存/显示 plt.savefig('图片.png') plt.show()
Matplotlib 是 Python 最基础的绑图库,功能强大且灵活。
折线图
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
# 数据
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
sales_a = [120, 135, 150, 145, 160, 180]
sales_b = [100, 115, 125, 140, 135, 155]
# 创建图形
plt.figure(figsize=(10, 6))
plt.plot(months, sales_a, marker='o', linewidth=2, label='Product A')
plt.plot(months, sales_b, marker='s', linewidth=2, label='Product B')
plt.title('2024 H1 Sales Trend', fontsize=16)
plt.xlabel('Month', fontsize=12)
plt.ylabel('Sales (10K CNY)', fontsize=12)
plt.legend()
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.savefig('line_chart.png', dpi=150)
plt.show()输出图表:显示两条折线分别代表产品A和产品B的销售趋势。
柱状图
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
# 数据
categories = ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Hangzhou']
values_2023 = [85, 92, 78, 88, 70]
values_2024 = [95, 98, 85, 95, 82]
x = np.arange(len(categories))
width = 0.35
# 创建图形
fig, ax = plt.subplots(figsize=(10, 6))
bars1 = ax.bar(x - width/2, values_2023, width, label='2023', color='steelblue')
bars2 = ax.bar(x + width/2, values_2024, width, label='2024', color='coral')
ax.set_title('City Sales Comparison', fontsize=16)
ax.set_xlabel('City', fontsize=12)
ax.set_ylabel('Sales (100M CNY)', fontsize=12)
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.legend()
# 添加数值标签
for bar in bars1:
height = bar.get_height()
ax.annotate(f'{height}',
xy=(bar.get_x() + bar.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha='center', va='bottom', fontsize=9)
for bar in bars2:
height = bar.get_height()
ax.annotate(f'{height}',
xy=(bar.get_x() + bar.get_width() / 2, height),
xytext=(0, 3),
textcoords="offset points",
ha='center', va='bottom', fontsize=9)
plt.tight_layout()
plt.savefig('bar_chart.png', dpi=150)
plt.show()饼图
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
# 数据
labels = ['Tech', 'Sales', 'Marketing', 'HR', 'Finance']
sizes = [35, 25, 20, 12, 8]
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
explode = (0.05, 0, 0, 0, 0) # Highlight first slice
# 创建图形
fig, ax = plt.subplots(figsize=(8, 8))
wedges, texts, autotexts = ax.pie(
sizes,
explode=explode,
labels=labels,
colors=colors,
autopct='%1.1f%%',
shadow=True,
startangle=90
)
ax.set_title('Department Staff Distribution', fontsize=16)
plt.setp(autotexts, size=11, weight='bold')
plt.tight_layout()
plt.savefig('pie_chart.png', dpi=150)
plt.show()散点图
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
# 生成模拟数据
np.random.seed(42)
n = 100
x = np.random.randn(n) * 10 + 50 # Work experience (months)
y = x * 200 + np.random.randn(n) * 2000 + 5000 # Salary
# 创建图形
plt.figure(figsize=(10, 6))
scatter = plt.scatter(x, y, c=y, cmap='viridis', alpha=0.7, s=60)
plt.colorbar(scatter, label='Salary Level')
# 添加趋势线
z = np.polyfit(x, y, 1)
p = np.poly1d(z)
plt.plot(x, p(x), "r--", linewidth=2, label=f'Trend: y={z[0]:.1f}x+{z[1]:.1f}')
plt.title('Work Experience vs Salary', fontsize=16)
plt.xlabel('Experience (months)', fontsize=12)
plt.ylabel('Monthly Salary (CNY)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('scatter_chart.png', dpi=150)
plt.show()子图布局
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
# 准备数据
np.random.seed(42)
x = np.linspace(0, 10, 100)
# 创建 2x2 子图
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 子图1: 正弦波
axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)
axes[0, 0].set_title('Sine Function')
axes[0, 0].set_xlabel('x')
axes[0, 0].set_ylabel('sin(x)')
axes[0, 0].grid(True, alpha=0.3)
# 子图2: 直方图
data = np.random.randn(1000)
axes[0, 1].hist(data, bins=30, color='green', alpha=0.7, edgecolor='black')
axes[0, 1].set_title('Normal Distribution Histogram')
axes[0, 1].set_xlabel('Value')
axes[0, 1].set_ylabel('Frequency')
# 子图3: 柱状图
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 32]
axes[1, 0].bar(categories, values, color='coral')
axes[1, 0].set_title('Category Data')
axes[1, 0].set_xlabel('Category')
axes[1, 0].set_ylabel('Value')
# 子图4: 箱线图
data_box = [np.random.randn(100) + i for i in range(4)]
axes[1, 1].boxplot(data_box, labels=['Group1', 'Group2', 'Group3', 'Group4'])
axes[1, 1].set_title('Box Plot Comparison')
axes[1, 1].set_ylabel('Value')
plt.suptitle('Matplotlib Subplots Example', fontsize=16, y=1.02)
plt.tight_layout()
plt.savefig('subplot_chart.png', dpi=150)
plt.show()Seaborn:统计可视化
🎯 小白理解:Seaborn 和 Matplotlib 有什么区别?
Matplotlib 是"基础款",Seaborn 是"高级款":
特性 Matplotlib Seaborn 美观度 需要手动调整 默认就好看 代码量 较多 较少 统计功能 需要自己算 内置统计 适合场景 精细控制 快速探索 例子对比:
python# Matplotlib(10+ 行代码) plt.figure() plt.scatter(x, y) plt.xlabel('X') plt.ylabel('Y') # ... 还要加趋势线、颜色等 # Seaborn(1 行代码) sns.regplot(x='X', y='Y', data=df) # 自带趋势线!常用 Seaborn 图表:
histplot→ 直方图(看分布)boxplot→ 箱线图(看离群值)heatmap→ 热力图(看相关性)pairplot→ 变量关系矩阵
Seaborn 基于 Matplotlib,提供更美观的统计图表和更简洁的 API。
分布图
import seaborn as sns
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
sns.set_style("whitegrid")
# 生成模拟数据
np.random.seed(42)
data = pd.DataFrame({
'Age': np.random.normal(35, 10, 500).astype(int),
'Income': np.random.normal(50000, 15000, 500),
'Gender': np.random.choice(['Male', 'Female'], 500)
})
# 创建 1x2 子图
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 直方图 + 核密度估计
sns.histplot(data=data, x='Age', kde=True, ax=axes[0], color='steelblue')
axes[0].set_title('Age Distribution', fontsize=14)
# 分组直方图
sns.histplot(data=data, x='Income', hue='Gender', kde=True, ax=axes[1])
axes[1].set_title('Income Distribution by Gender', fontsize=14)
plt.tight_layout()
plt.savefig('seaborn_dist.png', dpi=150)
plt.show()关系图
import seaborn as sns
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
sns.set_style("whitegrid")
# 生成模拟数据
np.random.seed(42)
n = 200
data = pd.DataFrame({
'AdSpend': np.random.uniform(10, 100, n),
'Revenue': None,
'Region': np.random.choice(['East', 'South', 'North', 'West'], n)
})
data['Revenue'] = data['AdSpend'] * 2.5 + np.random.normal(0, 20, n) + 50
# 创建关系图
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 散点图 + 回归线
sns.regplot(data=data, x='AdSpend', y='Revenue', ax=axes[0],
scatter_kws={'alpha': 0.5}, line_kws={'color': 'red'})
axes[0].set_title('Ad Spend vs Revenue (with Regression)', fontsize=14)
# 按类别着色的散点图
sns.scatterplot(data=data, x='AdSpend', y='Revenue', hue='Region',
style='Region', s=80, ax=axes[1])
axes[1].set_title('Ad Spend vs Revenue by Region', fontsize=14)
plt.tight_layout()
plt.savefig('seaborn_relation.png', dpi=150)
plt.show()分类图
import seaborn as sns
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
sns.set_style("whitegrid")
# 生成模拟员工数据
np.random.seed(42)
data = pd.DataFrame({
'Dept': np.repeat(['Tech', 'Sales', 'Marketing', 'HR'], 50),
'Salary': np.concatenate([
np.random.normal(18000, 3000, 50),
np.random.normal(15000, 4000, 50),
np.random.normal(14000, 2500, 50),
np.random.normal(12000, 2000, 50)
]),
'YearsExp': np.random.randint(1, 10, 200)
})
# 创建 2x2 子图
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 箱线图
sns.boxplot(data=data, x='Dept', y='Salary', ax=axes[0, 0], palette='Set2')
axes[0, 0].set_title('Salary by Department (Box Plot)', fontsize=14)
# 小提琴图
sns.violinplot(data=data, x='Dept', y='Salary', ax=axes[0, 1], palette='Set3')
axes[0, 1].set_title('Salary by Department (Violin Plot)', fontsize=14)
# 带散点的箱线图
sns.boxplot(data=data, x='Dept', y='Salary', ax=axes[1, 0], palette='pastel')
sns.stripplot(data=data, x='Dept', y='Salary', ax=axes[1, 0],
color='black', alpha=0.3, size=3)
axes[1, 0].set_title('Salary Distribution (with Points)', fontsize=14)
# 条形图(显示均值和置信区间)
sns.barplot(data=data, x='Dept', y='Salary', ax=axes[1, 1],
palette='coolwarm', errorbar='ci')
axes[1, 1].set_title('Average Salary by Department', fontsize=14)
plt.tight_layout()
plt.savefig('seaborn_category.png', dpi=150)
plt.show()热力图
import seaborn as sns
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 创建相关矩阵数据
np.random.seed(42)
n = 200
data = pd.DataFrame({
'Age': np.random.randint(22, 60, n),
'YearsExp': np.random.randint(0, 30, n),
'EduLevel': np.random.randint(1, 5, n),
'PerfScore': np.random.uniform(60, 100, n),
'Salary': np.random.normal(15000, 5000, n)
})
# 计算相关系数
correlation = data.corr()
# 创建热力图
plt.figure(figsize=(10, 8))
sns.heatmap(correlation,
annot=True, # 显示数值
fmt='.2f', # 保留两位小数
cmap='coolwarm', # 颜色方案
center=0, # 颜色中心点
square=True, # 正方形单元格
linewidths=0.5)
plt.title('Variable Correlation Heatmap', fontsize=16)
plt.tight_layout()
plt.savefig('seaborn_heatmap.png', dpi=150)
plt.show()成对关系图
import seaborn as sns
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 创建数据
np.random.seed(42)
n = 150
species = np.repeat(['TypeA', 'TypeB', 'TypeC'], 50)
data = pd.DataFrame({
'Feature1': np.concatenate([
np.random.normal(5, 1, 50),
np.random.normal(7, 1.2, 50),
np.random.normal(6, 0.8, 50)
]),
'Feature2': np.concatenate([
np.random.normal(3, 0.5, 50),
np.random.normal(4, 0.8, 50),
np.random.normal(5, 0.6, 50)
]),
'Feature3': np.concatenate([
np.random.normal(1.5, 0.3, 50),
np.random.normal(4, 0.5, 50),
np.random.normal(5.5, 0.4, 50)
]),
'Category': species
})
# 创建成对关系图
pairplot = sns.pairplot(data, hue='Category', palette='husl',
diag_kind='kde', plot_kws={'alpha': 0.6})
pairplot.fig.suptitle('Multi-variable Pair Plot', y=1.02, fontsize=16)
plt.savefig('seaborn_pairplot.png', dpi=150)
plt.show()Plotly:交互式可视化
🎯 小白理解:什么是"交互式"图表?
普通图表 vs 交互式图表:
普通图表 (Matplotlib) 交互式图表 (Plotly) 静态图片,不能动 可以缩放、拖动 只能看固定视角 鼠标悬停显示详情 保存为 PNG/PDF 保存为 HTML(网页) 适合打印报告 适合网页展示 交互式图表能做什么?
- 缩放:看细节时放大,看全局时缩小
- 悬停:鼠标放上去,显示具体数值
- 筛选:点击图例,隐藏/显示某类数据
- 3D 旋转:换角度观察立体图表
什么时候用 Plotly?
- 做 Dashboard(数据看板)
- 需要让用户自己探索数据
- 在网页中展示图表
Plotly 创建可交互的动态图表,支持缩放、悬停提示等功能。
基础折线图
import plotly.express as px
import pandas as pd
import numpy as np
# 准备数据
np.random.seed(42)
months = pd.date_range('2024-01-01', periods=12, freq='M')
data = pd.DataFrame({
'Date': months,
'Sales': np.cumsum(np.random.randint(80, 150, 12)) + 1000,
'Profit': np.cumsum(np.random.randint(20, 50, 12)) + 200
})
# 创建折线图
fig = px.line(data, x='Date', y=['Sales', 'Profit'],
title='2024 Monthly Sales Trend',
labels={'value': 'Amount (10K CNY)', 'variable': 'Metric'})
fig.update_layout(
hovermode='x unified',
legend=dict(orientation='h', yanchor='bottom', y=1.02)
)
# 保存为 HTML(可交互)
fig.write_html('plotly_line.html')
# 也可以保存为静态图片
# fig.write_image('plotly_line.png')
fig.show()交互式散点图
import plotly.express as px
import pandas as pd
import numpy as np
# 生成数据
np.random.seed(42)
n = 100
data = pd.DataFrame({
'AdSpend': np.random.uniform(10, 100, n),
'Revenue': None,
'Category': np.random.choice(['Electronics', 'Clothing', 'Food', 'Home'], n),
'Customers': np.random.randint(100, 1000, n)
})
data['Revenue'] = data['AdSpend'] * 3 + np.random.normal(0, 15, n) + 50
# 创建散点图
fig = px.scatter(
data,
x='AdSpend',
y='Revenue',
color='Category',
size='Customers',
hover_data=['Customers'],
title='Ad Spend vs Revenue',
labels={'AdSpend': 'Ad Spend (10K CNY)', 'Revenue': 'Revenue (10K CNY)'}
)
fig.update_layout(
legend=dict(orientation='h', yanchor='bottom', y=1.02)
)
fig.write_html('plotly_scatter.html')
fig.show()交互式柱状图
import plotly.express as px
import pandas as pd
import numpy as np
# 准备数据
data = pd.DataFrame({
'Quarter': ['Q1', 'Q2', 'Q3', 'Q4'] * 3,
'Region': ['East'] * 4 + ['South'] * 4 + ['North'] * 4,
'Sales': [120, 135, 128, 145, 98, 112, 105, 125, 85, 95, 92, 108]
})
# 创建分组柱状图
fig = px.bar(
data,
x='Quarter',
y='Sales',
color='Region',
barmode='group',
title='Regional Quarterly Sales Comparison',
labels={'Sales': 'Sales (10K CNY)'},
text='Sales'
)
fig.update_traces(textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
fig.write_html('plotly_bar.html')
fig.show()饼图和环形图
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# 准备数据
data = pd.DataFrame({
'Dept': ['Tech', 'Sales', 'Marketing', 'Operations', 'HR'],
'Ratio': [35, 25, 18, 15, 7]
})
# 创建子图:饼图和环形图
fig = make_subplots(rows=1, cols=2,
specs=[[{'type': 'pie'}, {'type': 'pie'}]],
subplot_titles=['Pie Chart', 'Donut Chart'])
# 饼图
fig.add_trace(
go.Pie(labels=data['Dept'], values=data['Ratio'], name='Pie'),
row=1, col=1
)
# 环形图
fig.add_trace(
go.Pie(labels=data['Dept'], values=data['Ratio'], hole=0.4, name='Donut'),
row=1, col=2
)
fig.update_layout(title_text='Staff Distribution by Department', showlegend=True)
fig.write_html('plotly_pie.html')
fig.show()热力图
import plotly.express as px
import pandas as pd
import numpy as np
# 生成销售数据矩阵
np.random.seed(42)
products = ['Product A', 'Product B', 'Product C', 'Product D', 'Product E']
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
sales_matrix = np.random.randint(50, 200, (len(products), len(months)))
# 创建 DataFrame
data = pd.DataFrame(sales_matrix, index=products, columns=months)
# 创建热力图
fig = px.imshow(
data,
labels=dict(x='Month', y='Product', color='Sales'),
title='Product Monthly Sales Heatmap',
color_continuous_scale='RdYlGn',
text_auto=True
)
fig.update_layout(
xaxis_title='Month',
yaxis_title='Product'
)
fig.write_html('plotly_heatmap.html')
fig.show()3D 散点图
import plotly.express as px
import pandas as pd
import numpy as np
# 生成 3D 数据
np.random.seed(42)
n = 200
data = pd.DataFrame({
'X': np.random.randn(n),
'Y': np.random.randn(n),
'Z': np.random.randn(n),
'Category': np.random.choice(['A', 'B', 'C'], n)
})
# 创建 3D 散点图
fig = px.scatter_3d(
data,
x='X', y='Y', z='Z',
color='Category',
title='3D Data Distribution',
opacity=0.7
)
fig.update_layout(
scene=dict(
xaxis_title='X Axis',
yaxis_title='Y Axis',
zaxis_title='Z Axis'
)
)
fig.write_html('plotly_3d.html')
fig.show()综合案例:销售数据分析报告
以下是一个完整的数据分析和可视化案例:
import numpy as np
import pandas as pd
import matplotlib
# matplotlib.use('Agg') # 如果在无图形界面的环境运行,请取消注释
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
# 1. 生成模拟销售数据
np.random.seed(42)
n = 500
data = pd.DataFrame({
'OrderID': range(1, n + 1),
'Date': pd.date_range('2024-01-01', periods=n, freq='D')[:n],
'Category': np.random.choice(['Electronics', 'Clothing', 'Food', 'Home'], n),
'Channel': np.random.choice(['Online', 'Offline'], n, p=[0.6, 0.4]),
'Revenue': np.random.exponential(500, n) + 100,
'Quantity': np.random.randint(1, 10, n),
'Rating': np.random.uniform(3.0, 5.0, n)
})
# 添加月份列
data['Month'] = data['Date'].dt.to_period('M').astype(str)
print("Data Preview:")
print(data.head(10))
print(f"\nDataset Size: {data.shape}")
# 2. 数据统计分析
print("\n" + "=" * 50)
print("Statistical Analysis")
print("=" * 50)
print("\nBasic Statistics:")
print(data.describe())
print("\nBy Category:")
category_stats = data.groupby('Category').agg({
'Revenue': ['sum', 'mean', 'count'],
'Rating': 'mean'
}).round(2)
print(category_stats)
print("\nBy Channel:")
channel_stats = data.groupby('Channel').agg({
'Revenue': ['sum', 'mean'],
'Quantity': 'sum'
}).round(2)
print(channel_stats)
# 3. 可视化分析
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
# 图1: 月度销售趋势
monthly_sales = data.groupby('Month')['Revenue'].sum().reset_index()
axes[0, 0].plot(monthly_sales['Month'], monthly_sales['Revenue'],
marker='o', linewidth=2, color='steelblue')
axes[0, 0].set_title('Monthly Sales Trend', fontsize=14)
axes[0, 0].set_xlabel('Month')
axes[0, 0].set_ylabel('Revenue (CNY)')
axes[0, 0].tick_params(axis='x', rotation=45)
# 图2: 产品类别销售占比
category_sales = data.groupby('Category')['Revenue'].sum()
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
axes[0, 1].pie(category_sales, labels=category_sales.index, autopct='%1.1f%%',
colors=colors, startangle=90)
axes[0, 1].set_title('Revenue by Category', fontsize=14)
# 图3: 销售渠道对比
channel_sales = data.groupby('Channel')['Revenue'].sum()
axes[0, 2].bar(channel_sales.index, channel_sales.values,
color=['coral', 'steelblue'])
axes[0, 2].set_title('Revenue by Channel', fontsize=14)
axes[0, 2].set_ylabel('Revenue (CNY)')
for i, v in enumerate(channel_sales.values):
axes[0, 2].text(i, v + 1000, f'{v:,.0f}', ha='center')
# 图4: 销售额分布
sns.histplot(data=data, x='Revenue', kde=True, ax=axes[1, 0], color='steelblue')
axes[1, 0].set_title('Revenue Distribution', fontsize=14)
axes[1, 0].set_xlabel('Revenue (CNY)')
# 图5: 各类别客户评分箱线图
sns.boxplot(data=data, x='Category', y='Rating', ax=axes[1, 1], palette='Set2')
axes[1, 1].set_title('Rating by Category', fontsize=14)
axes[1, 1].tick_params(axis='x', rotation=15)
# 图6: 销售额与数量关系
sns.scatterplot(data=data, x='Quantity', y='Revenue', hue='Channel',
ax=axes[1, 2], alpha=0.6)
axes[1, 2].set_title('Revenue vs Quantity', fontsize=14)
axes[1, 2].set_xlabel('Quantity')
axes[1, 2].set_ylabel('Revenue (CNY)')
plt.suptitle('Sales Data Analysis Report', fontsize=18, y=1.02)
plt.tight_layout()
plt.savefig('sales_analysis_report.png', dpi=150, bbox_inches='tight')
plt.show()安装指南
# 使用 pip 安装
pip install numpy pandas matplotlib seaborn plotly
# 使用 conda 安装
conda install numpy pandas matplotlib seaborn plotly
# Jupyter Notebook 中显示 Plotly 图表
pip install nbformat小结
本节介绍了 Python 数据分析和可视化的五大核心库:
| 库 | 用途 | 特点 |
|---|---|---|
| NumPy | 数值计算 | 高效数组运算,科学计算基础 |
| Pandas | 数据分析 | DataFrame 结构,数据处理利器 |
| Matplotlib | 基础绑图 | 功能全面,高度可定制 |
| Seaborn | 统计可视化 | 美观简洁,统计图表 |
| Plotly | 交互式图表 | 动态交互,支持 Web |
最佳实践:
- 数据处理首选 Pandas + NumPy
- 快速探索用 Seaborn
- 精细控制用 Matplotlib
- 交互式展示用 Plotly
下一节:5.6 小结和复习