Day 5:KNN算法与相似K线匹配
📋 目录
- KNN算法基础原理
- 距离度量方法详解
- K值选择策略
- 维度灾难与解决方案
- KNN的优缺点与变体
- KNN在量化交易中的应用
第一部分:KNN算法基础原理(1.5小时理论)
1.1 什么是KNN?
K-近邻(K-Nearest Neighbors) 是一种基于实例的监督学习算法,不需要显式训练过程。
核心思想:
如果一个样本在特征空间中的K个最相似的样本中的大多数属于某个类别,则该样本也属于这个类别。
KNN的三个基本要素:
- K值:选择多少个近邻
- 距离度量:如何计算样本间的相似度
- 决策规则:如何根据近邻做预测(分类用投票,回归用平均)
1.2 KNN算法流程
python
# 伪代码
def knn_predict(new_sample, training_data, labels, K):
# 1. 计算新样本与所有训练样本的距离
distances = []
for i, train_sample in enumerate(training_data):
dist = calculate_distance(new_sample, train_sample)
distances.append((dist, labels[i]))
# 2. 按距离排序,取前K个
distances.sort(key=lambda x: x[0])
k_nearest = distances[:K]
# 3. 投票/平均得到预测结果
if classification:
return majority_vote([label for _, label in k_nearest])
else:
return mean([label for _, label in k_nearest])
1.3 分类 vs 回归
| 任务类型 | 决策规则 | 示例 |
|---|---|---|
| 分类 | 多数投票 | 预测涨/跌 |
| 回归 | 加权平均 | 预测收益率数值 |
加权KNN:距离越近的样本权重越大
python
weight = 1 / (distance + epsilon)
第二部分:距离度量方法详解
2.1 常用距离公式
| 距离名称 | 公式 | 特点 | 适用场景 |
|---|---|---|---|
| 欧氏距离 | ∑i=1n(xi−yi)2\sqrt{\sum_{i=1}^{n}(x_i - y_i)^2}∑i=1n(xi−yi)2 | 最常用,直观 | 特征尺度一致 |
| 曼哈顿距离 | ∑i=1n∣xi−yi∣\sum_{i=1}^{n}|x_i - y_i|∑i=1n∣xi−yi∣ | 对异常值鲁棒 | 高维特征 |
| 切比雪夫距离 | maxi∣xi−yi∣\max_i|x_i - y_i|maxi∣xi−yi∣ | 强调最大差异 | 棋盘距离 |
| 闵可夫斯基距离 | (∑∣xi−yi∣p)1/p(\sum|x_i - y_i|^{p})^{1/p}(∑∣xi−yi∣p)1/p | 欧氏距离的推广 | p=1曼哈顿,p=2欧氏 |
| 余弦相似度 | x⋅y∣x∣∣y∣\cfrac{x·y}{|x||y|}∣x∣∣y∣x⋅y | 关注方向而非大小 | 文本/时间序列模式 |
| 马氏距离 | (x−y)TΣ−1(x−y)\sqrt{(\boldsymbol{x} - \boldsymbol{y})^T\Sigma^{-1}(\boldsymbol{x} - \boldsymbol{y})}(x−y)TΣ−1(x−y) | 考虑特征相关性,尺度无关 | 特征相关的多元数据 |
| 汉明距离 | ∑i=1nI(xi≠yi)\sum_{i=1}^n \mathbb{I}(x_i \ne y_i)∑i=1nI(xi=yi) | 衡量等长序列的位差异 | 分类/二进制数据 |
| 动态时间规整(DTW) | minπ∑(i,j)∈πd(xi,yj)2\min_{\pi} \sqrt{\sum_{(i,j) \in \pi} d(x_i, y_j)^2}minπ∑(i,j)∈πd(xi,yj)2 | 处理不等长、时间偏移序列 | 语音、手势、金融时间序列 |
2.2 欧氏距离详解
二维空间 :
d=(x1−y1)2+(x2−y2)2 d = \sqrt{(x_1 − y_1)^2 + (x_2 − y_2)^2} d=(x1−y1)2+(x2−y2)2
n维空间 :
d=∑i=1n(xi−yi)2 d = \sqrt{\sum_{i=1}^{n}(x_i − y_i)^2} d=i=1∑n(xi−yi)2
特点:
- 对特征缩放敏感
- 需要所有特征在同一量纲
2.3 曼哈顿距离详解
d=∑i=1n∣xi−yi∣ d = \sum_{i=1}^n |x_i - y_i| d=i=1∑n∣xi−yi∣
特点:
- 计算更快(无平方根)
- 对异常值更鲁棒
- 适合高维数据
2.4 马氏距离 (Mahalanobis Distance)详解
(x−y)TΣ−1(x−y) \sqrt{(\boldsymbol{x} - \boldsymbol{y})^T\Sigma^{-1}(\boldsymbol{x} - \boldsymbol{y})} (x−y)TΣ−1(x−y)
公式中的 Σ\SigmaΣ 是数据的协方差矩阵。它通过 Σ−1\Sigma^{-1}Σ−1 对数据进行"白化"处理,消除了量纲和相关性的影响。
特点:
- 尺度无关
- 衡量一个点与一个数据分布之间的距离,而不仅仅是点与点之间的距离
- 协方差矩阵为单位矩阵时,退化为欧氏距离
2.5 汉明距离 (Hamming Distance)详解
∑i=1nI(xi≠yi) \sum_{i=1}^n \mathbb{I}(x_i \ne y_i) i=1∑nI(xi=yi)
公式中 I(⋅)\mathbb{I}(\cdot)I(⋅) 是指示函数,当括号内条件为真时值为1,否则为0。它计算的是两个等长序列在对应位置上不同元素的总数。
特点:
- 专门用于衡量离散序列的差异
- 计算简单高效
2.6 动态时间规整 (Dynamic Time Warping, DTW)
minπ∑(i,j)∈πd(xi,yj)2 \min_{\pi} \sqrt{\sum_{(i,j) \in \pi} d(x_i, y_j)^2} πmin(i,j)∈π∑d(xi,yj)2
这是一个优化问题。它寻找两个时间序列 XXX 和 YYY 之间的一个最优对齐路径 π\piπ,使得沿该路径的累积距离(通常用欧氏距离 d(xi,yj)d(x_i,y_j)d(xi,yj)最小。
特点:
- 通过非线性地对齐时间轴,DTW能够有效处理序列长度不同、速度不一或存在相位偏移的问题,这是传统欧氏距离无法做到的。
2.7 距离度量选择指南
| 数据特征 | 推荐距离 | 原因 |
|---|---|---|
| 连续值,尺度一致 | 欧氏距离 | 几何直观 |
| 连续值,尺度不同 | 马氏距离 | 考虑协方差 |
| 二值特征 | 汉明距离 | 匹配位数 |
| 时间序列 | 动态时间规整(DTW) | 处理时间偏移 |
| 文本/模式 | 余弦相似度 | 忽略幅度 |
第三部分:K值选择策略
3.1 K值的影响
| K值 | 特点 | 风险 |
|---|---|---|
| K太小 (如K=1) | 对噪声敏感,过拟合 | 决策边界复杂 |
| K太大 | 决策边界平滑,欠拟合 | 忽略局部模式 |
| K适中 | 平衡偏差和方差 | 需要调参 |
3.2 选择K值的方法
1. 经验法则 :K≈NK\approx \sqrt NK≈N ,其中 NNN 是样本数
2. 交叉验证:
python
from sklearn.model_selection import cross_val_score
for k in range(1, 31):
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, X, y, cv=5)
print(f"K={k}, Accuracy={scores.mean():.4f}")
3. 肘部法则 :
选择使误差下降趋缓的K值
3.3 奇偶性考虑
避免平局:通常选择奇数K值(二分类时)
python
# 示例:K=2时可能出现1:1平局
# 解决方案:使用加权投票或选择奇数K
第四部分:维度灾难
4.1 什么是维度灾难?
随着特征维度增加,数据变得稀疏,距离计算失去意义。
表现:
- 所有点之间的距离趋近相等
- 需要指数级增长的样本量
4.2 维度灾难的数学解释
高维球体体积:
- 单位球体积随维度增加趋近0
- 大部分体积集中在表面
距离分布 :
在高维空间中,最近邻和最远邻的距离比趋近1
python
# 可视化:高维空间中的距离分布
import numpy as np
import matplotlib.pyplot as plt
def high_dim_distance_ratio(dimensions, n_points=1000):
ratios = []
for d in dimensions:
points = np.random.randn(n_points, d)
distances = []
for i in range(min(100, n_points)):
dist = np.linalg.norm(points[i] - points, axis=1)
min_dist = np.min(dist[dist > 0])
max_dist = np.max(dist)
ratios.append(min_dist / max_dist)
ratios.append(np.mean(ratios))
return ratios
4.3 缓解维度灾难的方法
| 方法 | 原理 | 实现 |
|---|---|---|
| 特征选择 | 只保留重要特征 | 方差阈值、互信息 |
| 特征降维 | 投影到低维空间 | PCA、t-SNE |
| 距离加权 | 使用更适合高维的距离 | 余弦相似度 |
| 增加样本 | 需要指数级增长 | 数据增强 |
| 近似方法 | 使用ANN(近似最近邻) | KD-Tree、LSH |
4.4 有效维度 vs 名义维度
名义维度 :原始特征数量
有效维度:数据实际占据的维度(常小于名义维度)
python
# 使用PCA分析有效维度
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(X)
cumsum_variance = np.cumsum(pca.explained_variance_ratio_)
effective_dim = np.argmax(cumsum_variance >= 0.95) + 1
print(f"有效维度(保留95%方差): {effective_dim}")
第五部分:KNN的优缺点与变体
5.1 优点
| 优点 | 说明 |
|---|---|
| 简单直观 | 无需训练,易于理解 |
| 无假设 | 不对数据分布做假设 |
| 多用途 | 分类、回归、异常检测 |
| 增量学习 | 新数据直接加入 |
5.2 缺点
| 缺点 | 说明 | 解决方案 |
|---|---|---|
| 计算量大 | 预测时需计算所有距离 | KD-Tree、Ball Tree |
| 内存消耗 | 需要存储所有训练数据 | 原型选择 |
| 维度灾难 | 高维性能下降 | 降维、特征选择 |
| 对噪声敏感 | 异常值影响大 | 加权KNN |
5.3 KNN变体
1. 加权KNN:
python
# 距离越近,权重越大
weights = 1 / (distances + 1e-5)
prediction = weighted_vote(labels, weights)
2. Radius Neighbors:
python
# 固定半径内的所有点
from sklearn.neighbors import RadiusNeighborsClassifier
rnn = RadiusNeighborsClassifier(radius=1.0)
3. 编辑KNN (ENN) :
移除错误分类的样本,减少噪声
4. 压缩KNN (CNN) :
选择"原型"样本,减少存储
第六部分:KNN在量化交易中的应用
6.1 典型应用场景
| 应用 | 描述 | 特征 |
|---|---|---|
| 相似K线匹配 | 找历史相似形态 | 收益率序列 |
| 市场状态识别 | 分类当前市场环境 | 技术指标组合 |
| 配对交易 | 找相似股票 | 基本面因子 |
| 异常检测 | 识别异常波动 | 量价特征 |
6.2 相似K线匹配原理
核心思想:
历史会重演。找到与当前K线形态最相似的过去时间段,观察其后续走势作为参考。
特征构造:
- N日收益率序列
- N日价格归一化序列
- 技术指标序列
应用方式:
- 找到K个最相似的日期
- 统计这些日期的后续走势
- 作为交易决策的参考
6.3 注意事项
过拟合风险:
- 相似不等于因果
- 市场环境变化可能导致模式失效
参数敏感性:
- N(观察窗口)
- K(近邻数量)
- 距离度量方式
验证方法:
- 滚动回测
- 样本外测试