1.热力图及绘制方法

(1)热力图的基本概念

       热力图(Heatmap) 是一种通过颜色编码来可视化矩阵数据的图表类型。它将数据值映射到颜色空间,使读者能够直观地感知数据的分布模式、高低差异和相关性。

      核心要素:

  • 数据矩阵:通常是二维表格,行和列代表不同变量

  • 颜色映射:将数值大小转换为颜色深浅或色调变化

  • 聚类分析(可选):对行 / 列进行聚类,突出相似模式。(举个相关性分析的例子:
    假设你有 10 个特征(如收入、负债、信用评分、工作年限等),计算它们之间的相关系数后得到一个 10×10 的矩阵。如果直接画热力图,特征的顺序是随机的,可能看不出规律;但如果对行和列进行聚类,算法会自动把 “相关模式相似” 的特征放在一起。比如:特征 A、B、C 可能和 “收入类指标” 的相关性很像(都与收入正相关,与负债负相关),聚类后它们会挨在一起;特征 D、E、F 可能和 “信用类指标” 的相关性很像(都与信用评分正相关),聚类后它们会形成另一组。这样一来,热力图中会出现 “颜色块集中的区域”,你能一眼看出 “哪些特征属于同一类相关模式”,避免被混乱的顺序干扰。)

    常见应用场景:(本文主要用于相关性分析)

  • 基因表达分析:展示不同基因在不同条件下的表达水平

  • 销售数据可视化:展示不同地区、不同时间段的销售业绩

  • 相关性分析:展示多个变量之间的相关系数矩阵

  • 用户行为分析:展示网站或应用中的用户交互热点区域

(2)热力图的作用

     热力图在数据分析中有以下重要作用:

  • 快速识别模式:通过颜色直观呈现数据分布,比查看原始数字更高效。如在相关系数矩阵中,一眼看出哪些变量高度相关
  • 发现异常值:颜色的突变或极端值对应的特殊颜色可以快速定位异常数据
  • 比较多组数据:同时展示多个变量或样本之间的关系

(3)热力图的关键参数

      在使用 Seaborn 等库绘制热力图时,需要注意以下参数:

  • 颜色映射(cmap)

    • coolwarm:从蓝色到红色,适合显示正负值(如相关系数)
    • viridis:连续渐变,适合显示数值大小
    • RdBu:红蓝对比,适合突出差异
  • 数值范围(vmin, vmax)

    • 确定颜色映射的最小值和最大值
    • 例如相关系数矩阵通常设为vmin=-1, vmax=1
  • 聚类(clustering)

    • 对行 / 列进行层次聚类,将相似的变量或样本放在一起
    • 在 Seaborn 中使用clustermap函数而非heatmap
  • 标注(annot)

    • 是否在每个单元格中显示具体数值
    • 数据点较少时建议开启(annot=True

(4)代码演示:(以信贷风险预测数据为例)

         首先需要读取数据,并将字符串型特征转换为数值类型:

# 读取数据
import pandas as pd
data  = pd.read_csv('data.csv')

# 进行映射,把字符串映射为数字
# 创建嵌套字典用于映射
mappings = {
    "Years in current job": {
        "10+ years": 10,
        "2 years": 2,
        "3 years": 3,
        "< 1 year": 0,
        "5 years": 5,
        "1 year": 1,
        "4 years": 4,
        "6 years": 6,
        "7 years": 7,
        "8 years": 8,
        "9 years": 9
    },
    "Home Ownership": {
        "Home Mortgage": 0,
        "Rent": 1,
        "Own Home": 2,
        "Have Mortgage": 3
    }
}
# 使用映射字典进行转换
data["Years in current job"] = data["Years in current job"].map(mappings["Years in current job"])
data["Home Ownership"] = data["Home Ownership"].map(mappings["Home Ownership"])

      然后分析数据集中连续特征之间的相关性,并通过热力图进行可视化展示

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt


# 提取连续值特征
continuous_features = [
    'Annual Income', 'Years in current job', 'Tax Liens',
    'Number of Open Accounts', 'Years of Credit History',
    'Maximum Open Credit', 'Number of Credit Problems',
    'Months since last delinquent', 'Bankruptcies',
    'Current Loan Amount', 'Current Credit Balance', 'Monthly Debt',
    'Credit Score'
]

# 使用 Pandas 的corr()方法计算这些连续特征之间的皮尔逊相关系数矩阵
correlation_matrix = data[continuous_features].corr()

# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300

# 使用 Seaborn 的heatmap()函数将相关系数矩阵可视化:
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Correlation Heatmap of Continuous Features')
plt.show()

注:热力图本质上只能对连续值进行绘制,对于数值形的离散值其实是不合适用热力图的。

      在使用热力图时需要谨慎考虑特征类型和相关性计算方法的适用性。

      对于分类变量来讲:

  • 若是有序分类变量,标签编码能够保留顺序信息,可采用上述方法正常计算。
  • 若是无需分类变量,标签编码会引入人为的顺序关系,计算的皮尔逊相关系数可能会产生误导。应对其进行独热编码,需用其他方法计算相关性。

     可以参考下面图示:


2.子图及其绘制:

(1)子图是什么?

     子图是在同一个画布上划分出的多个独立绘图区域,每个区域可以绘制一个单独的图表(比如箱线图、折线图等)。这些子图共享同一个画布,但彼此的内容、坐标轴、标题等都是独立的

     与普通图的区别:

    子图的作用:

     子图的主要价值是方便对比多个相关数据。比如4 个特征(年收入、工作年限等)都是描述用户财务状况的指标,把它们的箱线图放在同一张画布上,能快速看出:

  • 哪个特征的数值范围更大(比如年收入可能远大于纳税留置数)
  • 哪个特征的异常值更多(比如开户数量是否有极端值)

    如果不用子图,你需要分别绘制 4 张独立的图,对比时需要频繁切换,效率很低。

(2)子图的代码实现:

     手动绘制子图:

import pandas as pd
import matplotlib.pyplot as plt

# 定义要绘制的特征
features = ['Annual Income', 'Years in current job', 'Tax Liens', 'Number of Open Accounts']

# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300

# 创建一个包含 2 行 2 列的子图布局
fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# 手动指定特征索引进行绘图,仔细观察下这个坐标
i = 0
feature = features[i]
axes[0, 0].boxplot(data[feature].dropna())          # 第一行第一列
axes[0, 0].set_title(f'Boxplot of {feature}')
axes[0, 0].set_ylabel(feature)

i = 1
feature = features[i]   
axes[0, 1].boxplot(data[feature].dropna())          # 第一行第二列
axes[0, 1].set_title(f'Boxplot of {feature}')
axes[0, 1].set_ylabel(feature)

i = 2
feature = features[i]
axes[1, 0].boxplot(data[feature].dropna())          # 第二行第一列
axes[1, 0].set_title(f'Boxplot of {feature}')
axes[1, 0].set_ylabel(feature)

i = 3
feature = features[i]
axes[1, 1].boxplot(data[feature].dropna())          # 第二行第二列
axes[1, 1].set_title(f'Boxplot of {feature}')
axes[1, 1].set_ylabel(feature)

# 调整子图之间的间距
plt.tight_layout()

# 显示图形
plt.show()

      利用循环构建子图:

# 定义要绘制的特征
features = ['Annual Income', 'Years in current job', 'Tax Liens', 'Number of Open Accounts']

# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300

# 创建一个包含 2 行 2 列的子图布局
fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# 使用 for 循环遍历特征
for i in range(len(features)):
    row = i // 2 # 计算当前特征在子图中的行索引,// 是整除,即取整 ,之所以用整除是因为我们要的是行数
    # 例如 0//2=0, 1//2=0, 2//2=1, 3//2=1
    col = i % 2 # 计算当前特征在子图中的列索引,% 是取余,即取模
    # 例如 0%2=0, 1%2=1, 2%2=0, 3%2=1
    # 绘制箱线图
    feature = features[i]
    axes[row, col].boxplot(data[feature].dropna())
    axes[row, col].set_title(f'Boxplot of {feature}')
    axes[row, col].set_ylabel(feature)

# 调整子图之间的间距
plt.tight_layout()

# 显示图形
plt.show()
    

      


3.enumerate函数的使用:

   enumerate是 Python 中一个非常实用的内置函数,它的核心作用是在遍历列表(或其他可迭代对象如元组,字典,字符串)时,同时获取元素的 “索引” 和 “值”

        

features = ['A', 'B', 'C', 'D']

# 不使用 enumerate:只能获取元素值,需要手动记录索引
i = 0
for feature in features:
    print(f"索引: {i}, 元素值: {feature}")
    i += 1

# 使用 enumerate:同时获取索引和元素值
for i, feature in enumerate(features):
    print(f"索引: {i}, 元素值: {feature}")

    使用enumerate可以省略手动维护i的过程,使得代码更简洁。、

    若希望i从1开始增长则:

for i, feature in enumerate(features, start=1):  # 索引从1开始
    print(f"序号: {i}, 特征: {feature}")

     上述(2)中循环绘制子图也可以简化为以下代码:

for i, feature in enumerate(features):
    row = i // 2
    col = i % 2
    axes[row, col].boxplot(data[feature].dropna())
    axes[row, col].set_title(f'Boxplot of {feature}')
    axes[row, col].set_ylabel(feature)
# 其他代码部分不做改变

@浙大疏锦行

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐