大家好~
在之前学习过SVM后,咱们来聊聊SVR,即:支持向量回归。
支持向量回归是一种用来做预测的数学方法,属于「机器学习」的一种。它的目标是找到一条「最合适的线」,能够大致描述数据点的趋势,并允许数据点离这条线有一定的误差(不要求所有点都完全落在这条线上)。
你可以把它想象成:我们想找到一条「宽带」或「隧道」,大部分数据点都能在隧道里行走,而不是一定要贴着隧道的中心线。
下面,咱们从通俗案例、原理、再到完整案例的内容,详细和大家说说~
SVR 核心思路
支持向量回归主要做了两件事:
找到一条「平滑的线」,尽可能靠近所有数据点。 允许有一点点误差,只要误差不超过某个范围(叫「epsilon」),我们就认为是可以接受的。
这条线就是我们用来预测的线,它能帮助我们估算未来的数据。
一个非常简单的案例
例子:预测房租
假设我们有一个表,记录了不同房子的面积和租金:
如果我们想用支持向量回归来预测,比如一个80平方米的房子租金是多少?
第一步:找到一个「隧道」
SVR会尝试找到一条直线,并在这条线的两边划出一个「宽带」(隧道),比如租金的误差范围是 ±200元:
宽带的上边界可能是: 预测值 + 200宽带的下边界可能是: 预测值 - 200
第二步:容忍少量例外
如果有个数据点,比如一套40平方米的房子,它的租金是2600元,这个点可能跑出了隧道,但SVR不介意少量这样的点,只要总体情况不错就行。
4. SVR和普通回归的区别
普通回归(比如线性回归):
只找到一条线,试图让误差最小化。 它对所有数据点很严格,偏差太大的点可能会让线跑偏。
支持向量回归(SVR):
它允许有一定的误差,只要误差在隧道里就不算问题。 它更注重「整体趋势」,不被个别点干扰。
5. 为什么叫「支持向量」?
因为有些点对这条线的确定很重要,尤其是刚好落在「隧道边界」上的点,这些点就叫「支持向量」。可以理解成:它们是隧道的「撑梁柱」,决定了隧道的宽度和位置。
下面,咱们从详细的原理和完整的案例出发进行解释~
核心原理和案例
1. SVR公式推导
支持向量回归的目标是找到一条函数 ,使得大部分数据点落在一个宽度为 的带状区域内,并最小化模型的复杂度。其优化目标为:
优化问题:
其中:
是正则化项,控制模型的平滑性; 是惩罚参数,控制宽容程度; 是松弛变量,表示超出 的偏差。
约束条件:
通过拉格朗日方法可转为对偶问题,最终可得:
其中 是拉格朗日乘子。
2. 代码实现
以下是用虚拟数据实现支持向量回归的完整案例,咱们这里手动实现SVR计算,大家可以参考原理看看~
import numpy as np
import matplotlib.pyplot as plt
from cvxopt import matrix, solvers
# 生成虚拟数据
np.random.seed(42)
X = np.linspace(0, 10, 50).reshape(-1, 1) # 特征
true_y = 2 * np.sin(X).ravel() + 0.5 * X.ravel() # 真正的目标函数
noise = np.random.normal(0, 0.5, X.shape[0]) # 添加噪声
y = true_y + noise # 带噪声的目标值
# 核函数(RBF核)
def rbf_kernel(x1, x2, gamma=0.5):
diff = x1[:, None, :] - x2[None, :, :]
return np.exp(-gamma * np.sum(diff**2, axis=2))
# 构建SVR优化问题
class SVR:
def __init__(self, C=1, epsilon=0.1, kernel=rbf_kernel):
self.C = C
self.epsilon = epsilon
self.kernel = kernel
def fit(self, X, y):
n = len(y)
K = self.kernel(X, X)
# 构造QP问题的参数
P = matrix(np.block([[K, -K], [-K, K]]))
q = matrix(np.hstack([self.epsilon - y, self.epsilon + y]))
G = matrix(np.vstack([np.eye(2 * n), -np.eye(2 * n)]))
h = matrix(np.hstack([self.C * np.ones(2 * n), np.zeros(2 * n)]))
# 求解QP问题
solvers.options['show_progress'] = False
solution = solvers.qp(P + matrix(np.eye(2 * n) * 1e-5), q, G, h)
alpha = np.ravel(solution['x'])
# 提取支持向量的系数
self.alpha = alpha[:n] - alpha[n:]
self.X = X
self.y = y
# 计算偏差项
support_indices = (self.alpha > 1e-4)
self.b = np.mean(y[support_indices] - np.dot(K[support_indices], self.alpha))
def predict(self, X):
K = self.kernel(self.X, X)
return np.dot(K.T, self.alpha) + self.b
# 训练SVR模型
svr = SVR(C=10, epsilon=0.3)
svr.fit(X, y)
y_pred = svr.predict(X)
# 数据可视化
plt.figure(figsize=(12, 8))
# 原始数据和预测结果
plt.subplot(2, 2, 1)
plt.scatter(X, y, color='blue', label='Data')
plt.plot(X, true_y, color='green', linestyle='--', label='True Function')
plt.plot(X, y_pred, color='red', label='SVR Prediction')
plt.title('SVR Prediction with RBF Kernel')
plt.legend()
# 支持向量
plt.subplot(2, 2, 2)
plt.scatter(X, y, color='blue', label='Data')
support_vectors = X[np.abs(svr.alpha) > 1e-4]
plt.scatter(support_vectors, y[np.abs(svr.alpha) > 1e-4], edgecolor='red', s=100, label='Support Vectors')
plt.title('Support Vectors')
plt.legend()
# 残差分布
plt.subplot(2, 2, 3)
residuals = y - y_pred
plt.hist(residuals, bins=10, color='purple', edgecolor='black', alpha=0.7)
plt.axvline(0, color='red', linestyle='--')
plt.title('Residual Distribution')
plt.xlabel('Residual')
plt.ylabel('Frequency')
# 学习曲线(偏差与预测效果)
plt.subplot(2, 2, 4)
epsilon_values = np.linspace(0.1, 1.0, 10)
errors = []
for epsilon in epsilon_values:
svr = SVR(C=10, epsilon=epsilon)
svr.fit(X, y)
y_pred = svr.predict(X)
errors.append(np.mean((y - y_pred)**2))
plt.plot(epsilon_values, errors, marker='o', color='orange')
plt.title('Error vs Epsilon')
plt.xlabel('Epsilon')
plt.ylabel('Mean Squared Error')
plt.tight_layout()
plt.show()

SVR预测图:展示原始数据点、真实函数和SVR的预测结果,直观了解模型效果。 支持向量图:标注支持向量的位置,展示哪些点对模型最重要。 残差分布图:分析预测误差的分布情况,观察是否存在系统偏差。 学习曲线:展示不同 值对误差的影响,帮助优化模型参数。
当然,在实际情况下,更加建议大家使用自带库进行实现,在其中进行调优,这里仅仅作为大家学习使用~
最后

