文章目录
前置(有 9 种常见热图类型表格对比):4.玩转热图(相关矩阵、缺失值、多维相关、聚类热图、时间序列)——Python数据挖掘代码实践
4.玩转热图(续:地图热图)——Python数据挖掘代码实践
乱码必备:
import matplotlib.pyplot as plt
# 设置中文字体和解决负号显示问题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
一、 矩阵式网络关系热图
在网络或图(Graph)分析中,矩阵式网络关系热图(Adjacency Matrix Heatmap) 是将网络中的节点-节点连接关系以矩阵形式展示,通过颜色深浅反映节点间连接强度或权重。它不仅能帮助我们在大规模网络中快速定位结构模式和聚类关系,也为数据治理和异常检测提供了全局视角。
1.1 理论基础
邻接矩阵的定义
-
邻接矩阵的概念:
一个邻接矩阵是一个 n × n 的矩阵 A,其中 n 表示网络中节点的数量。矩阵中的元素 A[i, j] 表示节点 i 与节点 j 之间的连接情况。- 如果节点 i 和节点 j 之间存在一条边,则 A[i, j] 通常为该边的权重(例如,连接强度、交易量或相似度);
- 如果节点 i 和节点 j 之间没有边,则 A[i, j] = 0。
-
有向图与无向图:
- 对于无向图,邻接矩阵 A 是对称的,即对于所有 i 和 j,A[i, j] = A[j, i]。
- 对于有向图,A 可能不对称,因为 A[i, j] 表示从节点 i 指向节点 j 的连接,而 A[j, i] 则表示反向连接,二者可能不同。
-
加权图:
在加权图中,邻接矩阵的每个元素不仅表示是否存在连接(0 或 1),而是表示连接的具体数值,如边的权重。权重可以代表距离、流量、相似度等,根据业务场景确定。 -
无自环:
通常情况下,如果网络中不允许节点与自身相连,那么对于所有 i,A[i, i] = 0。
通过这种方式构造的邻接矩阵可以帮助我们在后续利用热图直观展示网络中各节点间的关系,从而为聚类、异常检测和特征筛选提供有力支持。
网络关系可视化的价值
- 宏观结构:对比力导向图(Force-directed Graph)等方法,邻接矩阵热图能在节点数量较多时,直观呈现全局结构。
- 聚类与分群:通过观察热图中颜色深浅的“块状”分布,识别相互紧密联系的节点集群。
- 异常检测:若某些行或列与其他行/列差异显著,可能表示异常节点或错误数据源。
1.2 实践操作:使用 NetworkX + Seaborn
在 Python 中,可通过 NetworkX 生成或读取图结构,然后将其转换为邻接矩阵(NumPy 或 Pandas),再用 Seaborn 或 Matplotlib 绘制热图。以下示例展示如何构造一个随机加权图并可视化其邻接矩阵。
构造随机加权网络
import networkx as nx
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 构建一个含 10 个节点的随机有向加权图
np.random.seed(42)
num_nodes = 10
G = nx.DiGraph()
# 添加节点
G.add_nodes_from(range(num_nodes))
# 随机添加若干边并赋予随机权重
for i in range(num_nodes):
for j in range(num_nodes):
if i != j and np.random.rand() < 0.3: # 30% 概率连边
weight = np.random.uniform(0, 10) # 0~10 之间随机权重
G.add_edge(i, j, weight=weight)
# 查看图的基本信息
print("图中节点数:", G.number_of_nodes())
print("图中边数:", G.number_of_edges())
获取邻接矩阵
# 获取节点列表(确保顺序一致)
nodes = sorted(G.nodes())
# 创建邻接矩阵(num_nodes x num_nodes)
adj_matrix = np.zeros((num_nodes, num_nodes))
for i, node_i in enumerate(nodes):
for j, node_j in enumerate(nodes):
if G.has_edge(node_i, node_j):
adj_matrix[i, j] = G[node_i][node_j]['weight'] # 提取权重
# 转为 Pandas DataFrame 便于可视化
adj_df = pd.DataFrame(adj_matrix, index=nodes, columns=nodes)
adj_df.head()
绘制邻接矩阵热图
plt.figure(figsize=(8, 6))
sns.heatmap(adj_df,
cmap='YlGnBu', # 颜色映射
annot=True, # 在单元格中显示数值
fmt=".2f", # 保留两位小数
linewidths=0.5, # 网格线宽度
linecolor='white')
plt.title("矩阵式网络关系热图 (邻接矩阵)", fontsize=14)
plt.xlabel("节点")
plt.ylabel("节点")
plt.show()
代码解读:
sns.heatmap(adj_df, cmap='YlGnBu', annot=True)
:绘制热图并在单元格内显示数值,颜色从淡黄到深蓝。linewidths=0.5
与linecolor='white'
:网格线更清晰,方便区分不同节点间的连接强度。- 对角线上若无自环边,则通常为 0。
绘制网络图表示
plt.figure(figsize=(8, 6))
# 使用 spring_layout 布局算法(基于欧几里得距离的力导向算法)
pos = nx.spring_layout(G, seed=42)
edges = G.edges()
# 提取每条边的权重,用于设置边的粗细
weights = [G[u][v]['weight'] for u, v in edges]
# 绘制节点
nx.draw_networkx_nodes(G, pos, node_size=500, node_color='lightblue')
# 绘制节点标签
nx.draw_networkx_labels(G, pos)
# 绘制边,边宽度按权重调节(可除以一个常数调整比例)
nx.draw_networkx_edges(G, pos, edgelist=edges, width=[w/2 for w in weights], alpha=0.7, edge_color='gray')
plt.title("网络图表示", fontsize=14)
plt.axis('off') # 关闭坐标轴
plt.show()
在数据治理和业务分析中的应用
网络宏观结构与聚类
- 宏观结构:在大规模社交网络或供应链网络中,力导向图容易混乱;而邻接矩阵热图则可帮助我们快速发现密集连接的子群。
- 聚类分析:若结合聚类算法(如层次聚类或 K-means)对行和列重新排序,可以让相似节点的行/列相邻,形成“块状”分布,便于识别社区或分群。
异常节点检测
- 异常节点:若某个节点行(或列)呈现颜色分布与其他节点差异极大,可能表示异常活动或数据质量问题。
- 数据修复:通过比较异常节点与正常节点的连接模式,分析是否存在采集或标注错误。
业务场景示例
- 社交网络:用户之间的互动权重可视化(如私信次数、点赞量),快速发现活跃群体或核心用户。
- 供应链:供应商-制造商-分销商之间的物流量或交易额,识别关键节点或薄弱环节,优化供应链管理。
- 物联网:设备-设备间的连接频度或带宽使用情况,定位网络瓶颈或异常设备。
二、Pivot Table 热图
在数据分析中,Pivot Table(数据透视表) 是一种用于重新整合数据的方法,能够将行列维度重新排列,以便更清晰地展现数据关系。在 Python 中,pandas
提供了强大的 pivot_table
方法,使得数据透视表的构建变得直观。同时,结合 seaborn
或 matplotlib
,可以将 Pivot Table 以 热图(heatmap) 形式呈现,从而更直观地观察数据分布情况。
Pivot Table 热图应用场景
Pivot Table 热图在 时间序列分析、市场销售分析、用户行为分析 等多个领域都有广泛应用。例如:
- 销售数据分析:按 “产品类别” 和 “月份” 统计销售额,观察销售趋势;
- 用户行为分析:按 “用户地区” 和 “活跃时间段” 统计访问次数,优化推荐策略;
- 财务数据可视化:按 “部门” 和 “季度” 统计财务支出,优化成本管理。
2.1 代码实现:绘制 Pivot Table 热图
生成示例数据
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 1. 生成模拟销售数据
np.random.seed(42)
data = pd.DataFrame({
'日期': pd.date_range(start='2024-01-01', periods=100, freq='D'), # 100 天的数据
'产品类别': np.random.choice(['电子产品', '家居用品', '服饰', '食品'], size=100),
'销售额': np.random.randint(100, 1000, size=100)
})
# 2. 提取月份
data['月份'] = data['日期'].dt.strftime('%Y-%m')
# 3. 创建 Pivot Table(按 “产品类别” 和 “月份” 聚合销售额)
pivot_table = data.pivot_table(values='销售额', index='产品类别', columns='月份', aggfunc='sum', fill_value=0)
# 4. 显示 Pivot Table 数据
print(pivot_table)
生成热图
# 设置绘图风格
plt.figure(figsize=(10, 6))
sns.heatmap(pivot_table, cmap='coolwarm', annot=True, fmt=".0f", linewidths=0.5)
# 设置标题和标签
plt.title("Pivot Table 热图 - 产品类别 vs 月份销售额", fontsize=14)
plt.xlabel("月份", fontsize=12)
plt.ylabel("产品类别", fontsize=12)
plt.xticks(rotation=45) # 旋转 x 轴标签,避免重叠
# 显示热图
plt.show()
2.2 代码解析
-
数据生成
- 100 天的随机销售数据,包含 “日期”、“产品类别”、“销售额”。
- 提取 “月份” 作为新的列,用于透视表的列索引。
-
构建 Pivot Table
values='销售额'
:透视表的值为销售额;index='产品类别'
:行索引为不同的产品类别;columns='月份'
:列索引为不同的月份;aggfunc='sum'
:对相同 “产品类别” 和 “月份” 进行销售额求和;fill_value=0
:对于没有数据的单元格填充0
。
-
绘制热图
sns.heatmap(pivot_table, cmap='coolwarm', annot=True, fmt=".0f", linewidths=0.5)
:cmap='coolwarm'
:使用冷暖色调;annot=True
:显示数值;fmt=".0f"
:数值格式,去除小数点;linewidths=0.5
:单元格间添加网格线。
-
优化可视化
plt.xticks(rotation=45)
:旋转 x 轴标签,避免重叠;plt.title()
/plt.xlabel()
/plt.ylabel()
:添加标题和坐标轴标签。
三、三维/交互式热图
在数据可视化领域,三维(3D)热图和交互式热图 结合了空间、时间、数值信息,使数据的变化趋势更直观地呈现。相比于二维静态热图,三维热图可以在不同维度(如时间、地理空间、数据类别) 上提供更丰富的信息,而交互式热图则允许用户通过鼠标悬停、缩放、旋转等操作动态探索数据。
在 Python 生态中,我们可以使用以下工具实现三维或交互式热图:
matplotlib
(基本 3D 绘图)plotly
(交互式可视化)ipywidgets
(Jupyter Notebook 交互控件)holoviews
+bokeh
(高级交互式可视化)
3.1 代码实现:三维热图(Matplotlib 3D)
生成数据
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 1. 生成三维数据
x = np.linspace(-5, 5, 50) # X 轴数据
y = np.linspace(-5, 5, 50) # Y 轴数据
X, Y = np.meshgrid(x, y) # 生成网格
Z = np.sin(np.sqrt(X**2 + Y**2)) # 计算 Z 轴值(基于正弦函数)
# 2. 创建 3D 图像
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')
# 3. 绘制 3D 热图
ax.plot_surface(X, Y, Z, cmap='coolwarm')
# 4. 设置标题和轴标签
ax.set_title("三维热图 - 3D Heatmap", fontsize=14)
ax.set_xlabel("X 轴", fontsize=12)
ax.set_ylabel("Y 轴", fontsize=12)
ax.set_zlabel("Z 轴值", fontsize=12)
# 5. 显示图像
plt.show()
代码解析
-
数据生成
np.meshgrid()
生成 二维网格,用于绘制 3D 图像;Z = np.sin(np.sqrt(X**2 + Y**2))
计算 Z 轴数值,模拟数据的变化。
-
绘制 3D 图像
ax = fig.add_subplot(111, projection='3d')
设置三维坐标;ax.plot_surface()
生成 3D 热图,cmap='coolwarm'
设置颜色。
3.2 代码实现:交互式热图(Plotly)
相比于 matplotlib
,plotly
提供了更强大的交互功能,可以拖拽旋转、缩放、鼠标悬停显示数据值,适用于数据分析仪表盘。
交互式热图代码
import numpy as np
import pandas as pd
import plotly.graph_objects as go
# 1. 生成数据
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
# 2. 创建交互式 3D 热图,使用有效的颜色映射 'RdBu'
fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y, colorscale='RdBu')])
# 3. 设置布局
fig.update_layout(
title="交互式 3D 热图",
scene=dict(
xaxis_title="X 轴",
yaxis_title="Y 轴",
zaxis_title="Z 轴"
)
)
# 4. 显示图像
fig.show()
3.3 代码实现:Jupyter 交互控件(ipywidgets)
在 Jupyter Notebook 中,我们可以结合 ipywidgets
动态调整热图参数,实现更加自由的交互体验。
交互式控件代码
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
from IPython.display import display
# 1. 生成数据
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
# 2. 创建交互式更新函数
def update_plot(frequency=1.0):
Z = np.sin(frequency * np.sqrt(X**2 + Y**2)) # 计算 Z 轴值
plt.figure(figsize=(6, 4))
plt.contourf(X, Y, Z, cmap='coolwarm')
plt.colorbar()
plt.title(f"交互式热图 (频率={frequency})")
plt.show()
# 3. 创建滑块控件
slider = widgets.FloatSlider(value=1.0, min=0.1, max=5.0, step=0.1, description="频率")
widgets.interactive(update_plot, frequency=slider)
代码解析
-
创建动态热图
update_plot()
动态生成热图;np.sin(frequency * np.sqrt(X**2 + Y**2))
让Z
随frequency
变化。
-
使用
ipywidgets
控制参数widgets.FloatSlider()
创建滑块控件;widgets.interactive()
绑定滑块和热图,实时更新。
总结
方法 | 适用场景 | 优势 | 主要库 |
---|---|---|---|
Matplotlib 3D | 基础三维数据可视化 | 适合静态 3D 热图 | matplotlib |
Plotly 交互式 | 需要交互式分析的场景,如 Web Dashboard | 支持拖拽、缩放、悬停显示 | plotly |
Jupyter + ipywidgets | 需要实时调整参数的场景 | 交互性更强,可控制数据动态变化 | ipywidgets |
- 三维热图适用于观察复杂的数据结构和趋势,尤其是空间数据、物理模型、流体模拟等;
- 交互式热图适用于仪表盘、探索性分析,用户可以实时调整参数,发现数据规律;
- 选择适合的工具,可以让数据可视化更加直观、易用。