特征提取与相似度计算
特征提取与相似度计算
深入理解对象特征提取和相似度计算的完整流程,掌握加权余弦相似度、特征归一化等核心技术的原理和应用。从第一性原理出发,理解为什么需要相似度计算,以及如何选择合适的相似度度量方法。
目录
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(所有特征公平贡献)✅
归一化的重要性总结:
- 相似度计算:归一化是相似度计算准确性的基础
- 模型训练:归一化提高训练稳定性和收敛速度
- 特征公平性:归一化确保所有特征公平贡献
- 算法性能:归一化是很多算法(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
对比
| 维度 | MinMax | Z-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)作为缓存
总结
本文深入介绍了特征提取与相似度计算的完整流程。关键要点:
- 业务需求:对象比对、风险评估、推荐系统
- 特征提取:从多表数据中提取特征,构建特征矩阵
- 特征归一化:MinMax归一化,消除量纲影响
- 加权余弦相似度:根据特征重要性加权,提高准确性
- 稀疏特征处理:降低稀疏特征的权重
- 完整流程:训练阶段和查询阶段的完整流程
- 最佳实践:特征一致性、权重更新、性能优化
通过合理的特征提取和相似度计算,我们可以:
- 找到相似的对象
- 进行风险评估
- 构建推荐系统
选择合适的相似度计算技术,能够大大提高相似度计算的准确性和应用价值。
