文章

特征提取与相似度计算

特征提取与相似度计算

特征提取与相似度计算

深入理解对象特征提取和相似度计算的完整流程,掌握加权余弦相似度、特征归一化等核心技术的原理和应用。从第一性原理出发,理解为什么需要相似度计算,以及如何选择合适的相似度度量方法。

目录

  1. 为什么需要特征提取与相似度计算?
  2. 对象特征提取
  3. 特征归一化(从第一性原理理解)
  4. 加权余弦相似度(从第一性原理理解)
  5. 稀疏特征处理
  6. 完整流程示例
  7. 最佳实践

1. 为什么需要特征提取与相似度计算?

1.1 业务需求

对象比对

场景:找到相似的对象(样本、商品、文档等)。

例子

1
2
3
4
5
6
场景:样本相似度查询
    输入:查询样本的特征
    ↓
    目标:找到数据库中与查询样本最相似的样本
    ↓
    应用:风险评估、异常检测、推荐系统

为什么需要?

  • 风险评估:找到相似的高风险样本
  • 异常检测:发现与已知模式不同的对象
  • 推荐系统:基于相似度推荐相似对象

风险评估

场景:基于相似度进行风险判断。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
已知高风险样本的特征:
    特征1:高
    特征2:中
    特征3:高
    
查询样本的特征:
    特征1:高
    特征2:中
    特征3:高
    ↓
    相似度:0.95(非常相似)
    ↓
    结论:查询样本也很可能是高风险 ⚠️

推荐系统

场景:基于相似度进行推荐。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
用户A喜欢的商品特征:
    特征1:高
    特征2:中
    特征3:高
    
商品B的特征:
    特征1:高
    特征2:中
    特征3:高
    ↓
    相似度:0.92(非常相似)
    ↓
    推荐:向用户A推荐商品B ✅

1.2 技术本质

特征提取

定义:将对象信息转化为数值向量。

本质:从”对象”到”数值向量”的映射。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
对象(样本):
    编号:ID_001
    年龄:30岁
    活动次数:5次
    平均间隔:29天
    ...
    ↓
    特征提取
    ↓
    特征向量:
    [30, 5, 29, ...]
    ↓
    数值向量(计算机可处理)

相似度计算

定义:度量两个向量的接近程度。

本质:从”两个向量”到”相似度分数”的映射。

例子

1
2
3
4
5
6
7
8
向量1:[30, 5, 29, ...]
向量2:[28, 6, 27, ...]
    ↓
    相似度计算
    ↓
    相似度分数:0.85
    ↓
    数值(表示相似程度)

2. 对象特征提取

2.1 基于 Featuretools 的特征提取

从多表数据中提取特征

流程

1
2
3
4
5
6
7
8
9
10
11
步骤1:构建实体集(EntitySet)
    定义实体和关系
    ↓
步骤2:深度特征合成(DFS)
    自动生成特征
    ↓
步骤3:特征过滤
    根据字段配置过滤不需要的特征
    ↓
步骤4:特征矩阵
    得到最终的特征矩阵

特征矩阵的构建

特征矩阵结构

1
2
3
4
5
6
7
8
9
10
行:每个对象(样本、商品等)
列:每个特征(COUNT、MEAN、MODE等)
值:特征值(数值)

例子:
        特征1  特征2  特征3  ...
对象1   30     5      29     ...
对象2   28     6      27     ...
对象3   32     4      31     ...
...

特征值计算示例

例子

1
2
3
4
5
6
7
8
9
10
11
12
样本一的数据:
    活动记录:5条
    平均间隔:29天
    最常见类型:A类
    
特征提取:
    特征1 = COUNT(活动记录) = 5
    特征2 = MEAN(间隔天数) = 29
    特征3 = MODE(类型) = "A类"
    ...
    ↓
    特征向量:[5, 29, ...]

2.2 特征的存储与管理

特征数据库

作用:存储所有对象的特征向量。

内容

  • 特征矩阵(DataFrame)
  • 对象ID(标识号等)
  • 标签信息(如果有)
  • 统计信息

存储方式

  • 文件:feature_database.pkl(Pickle格式)
  • 或数据库:SQLite、MySQL等

特征定义文件

作用:记录特征的计算方式。

内容

  • 特征名称列表
  • 特征计算方式
  • 特征数据类型
  • 特征来源(实体、字段、函数)

存储方式

  • 文件:feature_definitions.pkl(Pickle格式)

特征版本管理

目的:追踪特征定义的版本历史。

方法

1
2
3
4
5
6
特征版本号:v1.0, v1.1, v2.0, ...
    ↓
记录每个版本:
    - 特征定义
    - 特征数量
    - 变更说明

好处

  • 可以回退到历史版本
  • 可以对比不同版本的特征
  • 便于问题追溯

3. 特征归一化(从第一性原理理解)

3.1 为什么需要归一化?

问题:特征量纲不同

例子

1
2
3
4
5
6
7
8
9
10
特征1:年龄(20-80岁)
特征2:收入(1000-50000元)
特征3:次数(1-100次)
    ↓
    量纲完全不同:
    - 年龄:几十
    - 收入:几千到几万
    - 次数:个位数到百位数
    ↓
    问题:量级大的特征会主导相似度计算 ❌

问题示例

1
2
3
4
5
6
7
8
9
10
11
向量1:[30, 5000, 5]
向量2:[28, 6000, 5]
    ↓
    如果不归一化:
    - 年龄差异:2
    - 收入差异:1000(很大)
    - 次数差异:0
    ↓
    收入差异会主导相似度计算
    ↓
    但实际上,年龄和次数也很重要 ⚠️

归一化的本质

目的

  • 消除量纲影响:让所有特征在同一尺度
  • 公平贡献:让所有特征在相似度计算中公平贡献
  • 提高准确性:提高相似度计算的准确性

本质:将所有特征映射到同一尺度。

归一化的重要性

为什么归一化如此重要?

问题1:量纲不同导致计算偏差

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
特征1:年龄(范围:20-80,差异:60)
特征2:收入(范围:1000-50000,差异:49000)
特征3:次数(范围:1-100,差异:99)

如果不归一化:
- 收入差异(49000)会主导相似度计算
- 年龄差异(60)和次数差异(99)的影响被忽略
- 结果:相似度计算不准确 ❌

归一化后:
- 所有特征都在[0, 1]范围
- 所有特征的差异都在同一尺度
- 结果:相似度计算准确 ✅

问题2:梯度下降算法需要归一化

为什么?

原理

  • 梯度大小不一致:不同特征的梯度大小可能差异很大
  • 学习率难以设置:如果特征量纲不同,很难设置统一的学习率
  • 训练不稳定:量纲大的特征会导致训练过程不稳定

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
特征1:年龄(范围:20-80)
特征2:收入(范围:1000-50000)

梯度计算:
- 年龄的梯度:0.01(小)
- 收入的梯度:100(大)
    ↓
    如果不归一化:
    - 收入梯度太大,训练不稳定
    - 年龄梯度太小,学习缓慢
    ↓
    归一化后:
    - 所有特征梯度在同一尺度
    - 训练稳定、收敛快 ✅

问题3:距离度量需要归一化

为什么?

原理

  • 欧氏距离受量纲影响:量纲大的特征会主导距离计算
  • 相似度计算不准确:未归一化的特征会导致相似度计算偏差

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
向量1:[30, 5000, 5]
向量2:[28, 6000, 5]

欧氏距离(未归一化):
    √((30-28)² + (5000-6000)² + (5-5)²)
    = √(4 + 1000000 + 0)
    ≈ 1000(主要由收入差异主导)❌

归一化后:
    向量1:[0.167, 0.286, 0.05]
    向量2:[0.133, 0.327, 0.05]
    
欧氏距离(归一化后):
    √((0.167-0.133)² + (0.286-0.327)² + (0.05-0.05)²)
    = √(0.0012 + 0.0017 + 0)
    ≈ 0.054(所有特征公平贡献)✅

归一化的重要性总结

  1. 相似度计算:归一化是相似度计算准确性的基础
  2. 模型训练:归一化提高训练稳定性和收敛速度
  3. 特征公平性:归一化确保所有特征公平贡献
  4. 算法性能:归一化是很多算法(KNN、神经网络等)的前提条件

关键理解:归一化不是可选的优化,而是很多机器学习算法的必要条件

3.2 MinMax 归一化

定义与公式

定义:将特征值映射到 [0, 1] 范围。

公式

1
归一化值 = (原始值 - 最小值) / (最大值 - 最小值)

步骤

1
2
3
4
5
6
7
8
步骤1:训练阶段
    计算每个特征的 min 和 max
    ↓
步骤2:保存统计信息
    保存 min 和 max 到 feature_stats
    ↓
步骤3:查询阶段
    使用训练时的 min 和 max 归一化新数据

例子

训练阶段

1
2
3
4
5
6
7
8
9
特征1(年龄):
    所有样本:20, 25, 30, 35, 80
    min = 20
    max = 80
    
特征2(收入):
    所有样本:1000, 5000, 10000, 20000, 50000
    min = 1000
    max = 50000

查询阶段

1
2
3
4
5
6
7
8
9
10
11
新样本:
    特征1(年龄):30
    特征2(收入):15000
    ↓
    归一化:
    特征1 = (30 - 20) / (80 - 20) = 10/60 = 0.167
    特征2 = (15000 - 1000) / (50000 - 1000) = 14000/49000 = 0.286
    ↓
    归一化后:[0.167, 0.286]
    ↓
    所有特征都在 [0, 1] 范围内 ✅

特点

优点

  • 范围固定:映射到 [0, 1] 范围,易于理解
  • 保留分布:保留原始分布形状
  • 适合相似度:适合相似度计算(范围明确)

缺点

  • 对异常值敏感:异常值会影响 min 和 max
  • 需要统计信息:需要保存训练时的 min 和 max

3.3 Z-score 标准化(补充)

定义与公式

定义:将特征值标准化为均值0、标准差1的分布。

公式

1
标准化值 = (原始值 - 均值) / 标准差

步骤

1
2
3
4
5
6
7
8
步骤1:训练阶段
    计算每个特征的均值 μ 和标准差 σ
    ↓
步骤2:保存统计信息
    保存 μ 和 σ
    ↓
步骤3:查询阶段
    使用训练时的 μ 和 σ 标准化新数据

特点

优点

  • 适合正态分布:适合正态分布数据
  • 对异常值相对稳健:中位数和IQR可以抵抗异常值

缺点

  • 范围不固定:可能超出 [0, 1] 范围
  • 不适合相似度:不适合相似度计算(范围不明确)
  • 需要统计信息:需要保存训练时的 μ 和 σ

3.4 MinMax vs Z-score

对比

维度MinMaxZ-score
范围[0, 1]不固定(可能超出 [0, 1])
分布形状保留标准化为正态分布
异常值影响敏感相对稳健
适用场景相似度计算梯度下降算法
相似度计算适合 ⭐不适合

选择原则

相似度计算 → 使用 MinMax(推荐)⭐

  • 范围固定,适合相似度计算
  • 取值明确(0-1之间)

梯度下降算法 → 使用 Z-score

  • 适合正态分布
  • 适合优化算法

选择建议

1
2
3
4
5
如果用于相似度计算:
    → 使用 MinMax 归一化
    
如果用于模型训练(梯度下降):
    → 使用 Z-score 标准化

3.5 哪些模型需要归一化?

模型归一化需求总结

关键理解:不是所有模型都需要归一化,取决于模型的工作原理。

模型类型是否必须归一化原因
梯度下降类模型必须加速收敛,避免梯度震荡
- 神经网络必须梯度大小不一致会导致训练不稳定
- 线性回归必须梯度下降优化需要归一化
- 逻辑回归必须梯度下降优化需要归一化
距离计算类模型必须距离度量依赖特征尺度
- KNN(K近邻)必须欧氏距离受量纲影响
- SVM(支持向量机)必须距离计算依赖特征尺度
- K-Means聚类必须聚类基于距离度量
树模型不需要基于特征排序分裂,不受尺度影响
- 决策树不需要通过遍历特征所有取值选择划分点
- 随机森林不需要基于决策树,不需要归一化
- XGBoost(决策树弱学习器)不需要树模型通过排序选择分裂点
概率模型不需要依赖概率分布,与尺度无关
- 朴素贝叶斯不需要基于概率计算,不受尺度影响

为什么树模型不需要归一化?

原理

  • 树模型的分裂方式:通过遍历特征的所有取值来选择划分点
  • 排序而非距离:树模型关注的是特征值的排序关系,而不是绝对数值大小
  • 归一化不影响排序:归一化不会改变特征值的相对大小关系

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
原始数据:
    特征1(年龄):[20, 25, 30, 35, 40]
    特征2(收入):[1000, 5000, 10000, 20000, 50000]

归一化后:
    特征1:[0, 0.25, 0.5, 0.75, 1.0]
    特征2:[0, 0.1, 0.2, 0.4, 1.0]

树模型分裂:
    原始数据:按"年龄 < 30"分裂 → 左子树:[20, 25],右子树:[30, 35, 40]
    归一化后:按"年龄 < 0.5"分裂 → 左子树:[0, 0.25],右子树:[0.5, 0.75, 1.0]
    
结果:分裂效果相同 ✅
    归一化不影响排序关系
    树模型的分裂结果不变

非线性模型的特殊情况

注意:即使树模型不强制要求归一化,但归一化可能提升计算效率。

例子

  • 直方图加速:某些树模型实现(如LightGBM)使用直方图加速,归一化可能提升效率
  • 数值稳定性:归一化可以提高数值计算的稳定性

建议

  • 树模型:归一化不是必需的,但可以尝试(可能提升效率)
  • 梯度下降类模型:归一化是必需的
  • 距离计算类模型:归一化是必需的

4. 加权余弦相似度(从第一性原理理解)

4.1 什么是余弦相似度?

定义

余弦相似度:衡量两个向量的夹角。

公式

1
2
3
4
5
6
余弦相似度 = (A · B) / (||A|| × ||B||)

其中:
    A · B = Σ(aᵢ × bᵢ)(点积)
    ||A|| = √(Σaᵢ²)(向量A的欧氏长度)
    ||B|| = √(Σbᵢ²)(向量B的欧氏长度)

几何意义

角度关系

1
2
3
4
5
6
7
8
θ = 0°(同向):
    cos(θ) = 1 → 完全相似 ✅

θ = 90°(垂直):
    cos(θ) = 0 → 不相似

θ = 180°(反向):
    cos(θ) = -1 → 完全相反 ❌

为什么适合相似度计算?

优势1:不受向量长度影响

问题:两个对象的特征数量可能不同。

解决:余弦相似度只关注方向,不关注长度。

例子

1
2
3
4
5
6
7
向量1:[1, 2, 3](长度:√14 ≈ 3.74)
向量2:[2, 4, 6](长度:√56 ≈ 7.48)
    ↓
    向量2是向量1的2倍
    但方向相同
    ↓
    余弦相似度 = 1(完全相似)✅

优势2:适合稀疏特征

问题:特征值大部分为0(稀疏特征)。

解决:余弦相似度对稀疏特征效果好。

优势3:取值范围明确

范围:[-1, 1]

解释

  • 1:完全相似
  • 0:不相似
  • -1:完全相反

4.2 为什么需要加权?

问题:所有特征权重相同

问题:重要特征和次要特征被同等对待。

例子

1
2
3
4
5
6
7
8
9
特征1:年龄(重要)
特征2:性别(重要)
特征3:职业(次要)
特征4:爱好(次要)
    ↓
    如果不加权:
    - 所有特征权重相同
    - 次要特征会干扰相似度计算 ⚠️
    - 重要特征的作用被稀释

加权的作用

目的

  • 突出重要特征:重要特征权重高
  • 降低次要特征影响:次要特征权重低
  • 提高准确性:提高相似度计算的准确性

本质:根据特征重要性分配权重。

4.3 加权余弦相似度计算

计算步骤

完整流程

1
2
3
4
5
6
7
8
9
10
11
步骤1:特征对齐
    确保两个向量的特征顺序一致
    ↓
步骤2:特征归一化(MinMax)
    将所有特征映射到 [0, 1] 范围
    ↓
步骤3:特征加权
    每个特征值乘以对应的权重
    ↓
步骤4:计算余弦相似度
    使用加权后的向量计算余弦相似度

公式

加权向量

1
2
加权向量1 = 特征向量1 × 权重
加权向量2 = 特征向量2 × 权重

余弦相似度

1
相似度 = (加权向量1 · 加权向量2) / (||加权向量1|| × ||加权向量2||)

例子

原始数据

1
2
3
向量1:[30, 5, 29]
向量2:[28, 6, 27]
权重:[0.4, 0.3, 0.3]

计算过程

1
2
3
4
5
6
7
8
9
10
11
12
13
步骤1:特征归一化(假设已归一化)
    向量1:[0.5, 0.8, 0.6]
    向量2:[0.47, 0.9, 0.55]

步骤2:特征加权
    加权向量1:[0.5×0.4, 0.8×0.3, 0.6×0.3] = [0.2, 0.24, 0.18]
    加权向量2:[0.47×0.4, 0.9×0.3, 0.55×0.3] = [0.188, 0.27, 0.165]

步骤3:计算余弦相似度
    点积 = 0.2×0.188 + 0.24×0.27 + 0.18×0.165 = 0.0376 + 0.0648 + 0.0297 = 0.1321
    范数1 = √(0.2² + 0.24² + 0.18²) = √(0.04 + 0.0576 + 0.0324) = √0.13 = 0.36
    范数2 = √(0.188² + 0.27² + 0.165²) = √(0.0353 + 0.0729 + 0.0272) = √0.1354 = 0.368
    相似度 = 0.1321 / (0.36 × 0.368) = 0.1321 / 0.1325 = 0.997

4.4 权重来源

特征重要性权重

来源:从训练好的模型中提取。

方法

  • 使用Permutation Importance计算特征重要性
  • 使用SHAP值计算特征重要性
  • 使用模型内置的特征重要性(如XGBoost的gain)

特点

  • 反映特征对分类的重要性
  • 基于模型训练结果
  • 有理论基础

特征统计权重

来源:基于特征方差计算。

方法

1
权重 = 特征方差 / 所有特征方差总和

特点

  • 反映特征的区分能力
  • 方差大的特征区分能力强
  • 方差小的特征区分能力弱

权重融合

方法

1
2
3
4
5
6
融合权重 = α × 重要性权重 + (1-α) × 统计权重

其中:
    α 是融合系数(0-1之间)
    α = 0.7 表示更重视重要性权重
    α = 0.3 表示更重视统计权重

归一化

1
归一化权重 = 融合权重 / 所有融合权重总和

目的:确保所有权重之和为1。


5. 稀疏特征处理

5.1 什么是稀疏特征?

定义

稀疏特征:特征值大部分为0或缺失。

特点

  • 大部分值为0
  • 只有少量非零值
  • 常见于计数型特征

例子

1
2
3
4
5
6
特征1(活动次数):
    对象1:5次
    对象2:0次(没有活动记录)
    对象3:3次
    ↓
    很多对象值为0(稀疏)

5.2 稀疏特征的影响

问题:相似度计算可能不准确

原因

  • 稀疏特征的0值很多
  • 两个向量在很多维度上都是0
  • 余弦相似度可能会受到稀疏特征的影响

例子

1
2
3
4
5
6
向量1:[5, 0, 0, 0, 0, ...](只有特征1有值)
向量2:[0, 3, 0, 0, 0, ...](只有特征2有值)
    ↓
    相似度:0(完全不相似)
    ↓
    但实际上,两个对象可能在其他方面相似 ⚠️

5.3 稀疏特征衰减机制

机制

目的:降低稀疏特征的权重,提高密集特征的权重。

方法

1
2
3
稀疏特征衰减:
    如果特征值大部分为0 → 降低权重
    如果特征值大部分非0 → 保持或提高权重

实现

1
2
3
4
5
衰减后的权重 = 原始权重 × (1 - 稀疏度)

其中:
    稀疏度 = 零值数量 / 总数量
    稀疏度越大 → 权重衰减越多

6. 完整流程示例

6.1 训练阶段

流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
步骤1:特征提取
    使用 Featuretools 从多表数据中提取特征
    ↓
步骤2:计算特征统计信息
    计算每个特征的 min 和 max
    ↓
步骤3:计算特征权重
    从训练好的模型中提取特征重要性
    或基于特征方差计算权重
    ↓
步骤4:保存
    保存特征定义、统计信息、权重到文件
    - feature_definitions.pkl
    - feature_stats(保存在模型文件中)
    - feature_weights(保存在模型文件中)

6.2 查询阶段

流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
步骤1:提取查询对象特征
    使用相同的特征定义提取查询对象的特征
    ↓
步骤2:特征归一化
    使用训练时的 min 和 max 归一化特征
    ↓
步骤3:与数据库对象特征计算相似度
    对每个数据库对象:
        - 特征对齐
        - 特征归一化(使用训练时的统计信息)
        - 特征加权
        - 计算加权余弦相似度
    ↓
步骤4:返回相似度排序结果
    按相似度从高到低排序
    返回TopN最相似的对象

7. 最佳实践

7.1 特征一致性保证

训练和查询使用相同的特征定义

问题:特征定义不一致会导致预测错误。

解决

  • 训练时保存特征定义(feature_definitions.pkl)
  • 查询时加载相同的特征定义
  • 使用相同的特征工程流程

使用相同的归一化方法

问题:归一化方法不一致会导致预测错误。

解决

  • 训练时保存归一化统计信息(min, max)
  • 查询时使用训练时的统计信息归一化

7.2 权重更新机制

模型更新后重新计算权重

时机:模型更新后。

方法

  • 从新模型中提取特征重要性
  • 重新计算特征权重
  • 更新权重文件

保持权重与模型的一致性

问题:权重和模型不匹配会导致相似度计算不准确。

解决

  • 每次模型更新后同步更新权重
  • 确保权重来源与模型一致

7.3 性能优化

批量计算相似度

问题:逐个计算相似度速度慢。

解决

  • 使用矩阵运算批量计算
  • 使用NumPy的向量化操作
  • 考虑使用GPU加速

特征向量缓存

问题:重复计算特征向量浪费时间。

解决

  • 缓存已计算的特征向量
  • 特征数据库(feature_database.pkl)作为缓存

总结

本文深入介绍了特征提取与相似度计算的完整流程。关键要点:

  1. 业务需求:对象比对、风险评估、推荐系统
  2. 特征提取:从多表数据中提取特征,构建特征矩阵
  3. 特征归一化:MinMax归一化,消除量纲影响
  4. 加权余弦相似度:根据特征重要性加权,提高准确性
  5. 稀疏特征处理:降低稀疏特征的权重
  6. 完整流程:训练阶段和查询阶段的完整流程
  7. 最佳实践:特征一致性、权重更新、性能优化

通过合理的特征提取和相似度计算,我们可以:

  • 找到相似的对象
  • 进行风险评估
  • 构建推荐系统

选择合适的相似度计算技术,能够大大提高相似度计算的准确性和应用价值。

本文由作者按照 CC BY 4.0 进行授权