21、回归算法:支持向量回归与神经网络的探索与实践

回归算法:支持向量回归与神经网络的探索与实践

1. 支持向量回归(SVR)

1.1 SVR原理

支持向量回归(SVR)属于支持向量家族,与用于分类的支持向量机(SVM,也称为SVC)是“近亲”。SVC的目标是找到一个最优超平面,将不同类别的观测值分隔开,使得每个分隔空间中离超平面最近的点到超平面的距离最大化。而SVR的目标是找到一个由斜率向量 $w$ 和截距 $b$ 定义的超平面,使得与该超平面距离为 $\epsilon$ 的两个超平面 $wx + b = -\epsilon$ 和 $wx + b = \epsilon$ 能够覆盖大部分训练数据,即大部分数据点位于最优超平面的 $\epsilon$ 带内,同时让最优超平面尽可能“平坦”,也就是让 $|w|$ 尽可能小。这可以通过求解以下优化问题来实现:
最小化 $|w|$
约束条件:$|y(i) - (wx(i) + b)| \leq \epsilon$,给定训练集 $(x(1), y(1)), (x(2), y(2)), \cdots, (x(i), y(i)), \cdots, (x(m), y(m))$

1.2 SVR实现

为了解决上述优化问题,需要使用二次规划技术,但这超出了我们的学习范围。因此,我们使用scikit-learn中的SVR包来实现回归算法。SVC的一些重要技术,如作为偏差和方差权衡的惩罚项、处理线性不可分问题的核函数(如RBF),也可以应用到SVR中。以下是使用SVR解决房价预测问题的代码示例:

from sklearn.svm import SVR
regressor = SVR(C=0.1, epsilon=0.02, kernel='linear')
regressor.fit(X_train, y_train)
predictions = regressor.predict(X_test)
print(predictions)

2. 神经网络

2.1 神经网络原理

神经网络是媒体中最常被提及的模型之一,虽然公众常错误地将其等同于机器学习或人工智能,但它确实是最重要的机器学习模型之一,并且随着深度学习(DL)的革命而迅速发展。一个简单的神经网络由输入层、隐藏层和输出层三层组成。每层是节点(也称为单元)的概念集合,模拟生物大脑中的神经元。输入层代表输入特征 $x$,每个节点是一个预测特征 $x$;输出层代表目标变量。在二元分类中,输出层只有一个节点,其值是正类的概率;在多类分类中,输出层由 $n$ 个节点组成,$n$ 是可能的类别数,每个节点的值是预测该类别的概率;在回归中,输出层只有一个节点,其值是预测结果。隐藏层可以看作是从前面一层提取的潜在信息的组合,可能有多个隐藏层。使用具有两个或更多隐藏层的神经网络进行学习称为深度学习。我们先从一个隐藏层开始。

相邻两层通过概念上的边连接,类似于生物大脑中的突触,将信号从一层的一个神经元传递到下一层的另一个神经元。这些边由模型的权重 $W$ 参数化。例如,$W(1)$ 连接输入层和隐藏层,$W(2)$ 连接隐藏层和输出层。在标准神经网络中,数据仅从输入层通过隐藏层传递到输出层,因此这种网络称为前馈神经网络。逻辑回归本质上是一个没有隐藏层的前馈神经网络,输出层直接与输入层相连。在输入层和输出层之间有一个或多个隐藏层的神经网络应该能够更好地学习输入数据和目标之间的潜在关系。

假设输入 $x$ 是 $n$ 维的,隐藏层由 $H$ 个隐藏单元组成,连接输入层和隐藏层的权重矩阵 $W(1)$ 的大小是 $n \times H$,其中每一列代表与第 $h$ 个隐藏单元相关联的输入系数。隐藏层的输出(也称为激活)可以用数学公式表示为:
$a^{(2)} = f(z^{(2)}) = f(XW^{(1)} + b^{(1)})$
这里 $f(z)$ 是激活函数,常见的激活函数包括逻辑函数(在神经网络中更常称为sigmoid函数)、tanh函数(被认为是逻辑函数的重新缩放版本)以及ReLU(Rectified Linear Unit的缩写,常用于深度学习)。

2.2 神经网络实现

2.2.1 从零开始实现

我们以sigmoid函数作为激活函数为例,首先定义sigmoid函数及其导数函数:

import numpy as np
def sigmoid(z):
    return 1.0 / (1 + np.exp(-z))
def sigmoid_derivative(z):
    return sigmoid(z) * (1.0 - sigmoid(z))

然后定义训练函数,该函数接受训练数据集、隐藏层的单元数和迭代次数作为输入:

def train(X, y, n_hidden, learning_rate, n_iter):
    m, n_input = X.shape
    W1 = np.random.randn(n_input, n_hidden)
    b1 = np.zeros((1, n_hidden))
    W2 = np.random.randn(n_hidden, 1)
    b2 = np.zeros((1, 1))
    for i in range(1, n_iter+1):
        Z2 = np.matmul(X, W1) + b1
        A2 = sigmoid(Z2)
        Z3 = np.matmul(A2, W2) + b2
        A3 = Z3
        dZ3 = A3 - y
        dW2 = np.matmul(A2.T, dZ3)
        db2 = np.sum(dZ3, axis=0, keepdims=True)
        dZ2 = np.matmul(dZ3, W2.T) * sigmoid_derivative(Z2)
        dW1 = np.matmul(X.T, dZ2)
        db1 = np.sum(dZ2, axis=0)
        W2 = W2 - learning_rate * dW2 / m
        b2 = b2 - learning_rate * db2 / m
        W1 = W1 - learning_rate * dW1 / m
        b1 = b1 - learning_rate * db1 / m
        if i % 100 == 0:
            cost = np.mean((y - A3) ** 2)
            print('Iteration %i, training loss: %f' % (i, cost))
    model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}
    return model

我们使用波士顿房价数据集作为示例,在使用梯度下降时通常建议进行数据归一化,因此我们通过去除均值并缩放到单位方差来标准化输入数据:

from sklearn import datasets
from sklearn import preprocessing
boston = datasets.load_boston()
num_test = 10  # 最后10个样本作为测试集
scaler = preprocessing.StandardScaler()
X_train = boston.data[:-num_test, :]
X_train = scaler.fit_transform(X_train)
y_train = boston.target[:-num_test].reshape(-1, 1)
X_test = boston.data[-num_test:, :]
X_test = scaler.transform(X_test)
y_test = boston.target[-num_test:]

使用缩放后的数据集,我们可以训练一个具有20个隐藏单元、学习率为0.1、迭代2000次的单层神经网络:

n_hidden = 20
learning_rate = 0.1
n_iter = 2000
model = train(X_train, y_train, n_hidden, learning_rate, n_iter)

定义预测函数:

def predict(x, model):
    W1 = model['W1']
    b1 = model['b1']
    W2 = model['W2']
    b2 = model['b2']
    A2 = sigmoid(np.matmul(x, W1) + b1)
    A3 = np.matmul(A2, W2) + b2
    return A3

最后,将训练好的模型应用于测试集:

predictions = predict(X_test, model)
print(predictions)
print(y_test)
2.2.2 使用scikit-learn实现

我们可以使用scikit-learn中的MLPRegressor类来实现神经网络:

from sklearn.neural_network import MLPRegressor
nn_scikit = MLPRegressor(hidden_layer_sizes=(20, 8), 
                         activation='logistic', solver='lbfgs',
                         learning_rate_init=0.1, random_state=42, 
                         max_iter=2000)
nn_scikit.fit(X_train, y_train)
predictions = nn_scikit.predict(X_test)
print(predictions)
2.2.3 使用TensorFlow实现

首先指定模型的参数,包括两个分别具有20和8个节点的隐藏层、2000次迭代和0.1的学习率:

import tensorflow as tf
n_features = int(X_train.shape[1])
n_hidden_1 = 20
n_hidden_2 = 8
learning_rate = 0.1
n_iter = 2000

然后定义占位符并构建从输入层到隐藏层再到输出层的网络:

x = tf.placeholder(tf.float32, shape=[None, n_features])
y = tf.placeholder(tf.float32, shape=[None, 1])
layer_1 = tf.nn.sigmoid(tf.layers.dense(x, n_hidden_1))
layer_2 = tf.nn.sigmoid(tf.layers.dense(layer_1, n_hidden_2))
pred = tf.layers.dense(layer_2, 1)

定义损失函数(MSE)和梯度下降优化器:

cost = tf.losses.mean_squared_error(labels=y, predictions=pred)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

初始化变量并启动TensorFlow会话:

init_vars = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_vars)

开始训练过程,并每100次迭代打印一次损失:

for i in range(1, n_iter+1):
    _, c = sess.run([optimizer, cost], 
                    feed_dict={x: X_train, y: y_train})
    if i % 100 == 0:
        print('Iteration %i, training loss: %f' % (i, c))

将训练好的模型应用于测试集:

predictions = sess.run(pred, feed_dict={x: X_test})
print(predictions)
2.2.4 使用Keras实现

Keras是一个基于TensorFlow和其他两个深度学习框架的高级API,用于快速原型设计和实验神经网络模型。我们可以使用PyPI安装Keras:

pip install keras

安装后导入必要的模块:

from keras import models
from keras import layers

初始化Keras的Sequential模型:

model = models.Sequential()

逐层添加,从第一个隐藏层(20个单元)到第二个隐藏层(8个单元),再到输出层:

model.add(layers.Dense(n_hidden_1, activation="sigmoid", 
                       input_shape=(n_features, )))
model.add(layers.Dense(n_hidden_2, activation="sigmoid"))
model.add(layers.Dense(1))

定义优化器:

from keras import optimizers
sgd = optimizers.SGD(lr=0.01)

编译模型:

model.compile(loss='mean_squared_error', optimizer=sgd)

在训练集上拟合模型,并在测试集上验证性能:

model.fit(
    X_train, y_train,
    epochs=100,
    validation_data=(X_test, y_test)
)

使用训练好的模型对测试集进行预测:

predictions = model.predict(X_test)
print(predictions)

3. 回归性能评估

到目前为止,我们已经深入探讨了四种流行的回归算法,并从头开始和使用几个著名的库实现了它们。为了评估模型在测试集上的性能,我们可以使用以下指标:
- 均方误差(MSE) :衡量与期望值对应的平方损失。有时会对MSE取平方根,将值转换回被估计目标变量的原始尺度,得到均方根误差(RMSE)。
- 平均绝对误差(MAE) :衡量绝对损失,使用与目标变量相同的尺度,让我们了解预测值与实际值的接近程度。
- $R^2$(决定系数) :表示回归模型的拟合优度,范围从0到1,意味着从无拟合到完美预测。

以下是使用scikit-learn中的相应函数计算线性回归模型这三个指标的步骤:
1. 重新处理糖尿病数据集,并使用网格搜索技术微调线性回归模型的参数:

from sklearn import datasets
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import SGDRegressor
diabetes = datasets.load_diabetes()
num_test = 30  # 最后30个样本作为测试集
X_train = diabetes.data[:-num_test, :]
y_train = diabetes.target[:-num_test]
X_test = diabetes.data[-num_test:, :]
y_test = diabetes.target[-num_test:]
param_grid = {
    "alpha": [1e-07, 1e-06, 1e-05],
    "penalty": [None, "l2"],
    "eta0": [0.001, 0.005, 0.01],
    "n_iter": [300, 1000, 3000]
}
regressor = SGDRegressor(loss='squared_loss', 
                         learning_rate='constant')
grid_search = GridSearchCV(regressor, param_grid, cv=3)
  1. 获取最优参数集:
grid_search.fit(X_train, y_train)
print(grid_search.best_params_)
regressor_best = grid_search.best_estimator_
  1. 使用最优模型对测试集进行预测:
predictions = regressor_best.predict(X_test)
  1. 基于MSE、MAE和$R^2$指标评估模型在测试集上的性能:
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
print(mean_squared_error(y_test, predictions))
print(mean_absolute_error(y_test, predictions))
print(r2_score(y_test, predictions))

4. 使用四种回归算法预测股票价格

我们已经学习了四种常用且强大的回归算法以及性能评估指标,现在可以使用它们来解决股票价格预测问题。

4.1 数据准备

我们之前基于1988年到2016年的数据生成了特征,现在使用1988年到2015年的数据构建训练集,使用2016年的数据构建测试集:

import pandas as pd
data_raw = pd.read_csv('19880101_20161231.csv', index_col='Date')
data = generate_features(data_raw)
start_train = '1988-01-01'
end_train = '2015-12-31'
start_test = '2016-01-01'
end_test = '2016-12-31'
data_train = data.ix[start_train:end_train]
X_train = data_train.drop('close', axis=1).values
y_train = data_train['close'].values
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)

4.2 SGD-based线性回归

SGD-based算法对特征尺度差异较大的数据敏感,因此我们需要对特征进行归一化:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled_train = scaler.fit_transform(X_train)
X_scaled_test = scaler.transform(X_test)

搜索具有最优参数集的SGD-based线性回归模型:

param_grid = {
    "alpha": [1e-5, 3e-5, 1e-4],
    "eta0": [0.01, 0.03, 0.1],
}
lr = SGDRegressor(penalty='l2', n_iter=1000)
grid_search = GridSearchCV(lr, param_grid, cv=5, scoring='r2')
grid_search.fit(X_scaled_train, y_train)

选择最佳线性回归模型并对测试样本进行预测:

print(grid_search.best_params_)
lr_best = grid_search.best_estimator_
predictions_lr = lr_best.predict(X_scaled_test)

评估预测性能:

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
print('MSE: {0:.3f}'.format(mean_squared_error(y_test, predictions_lr)))
print('MAE: {0:.3f}'.format(mean_absolute_error(y_test, predictions_lr)))
print('R^2: {0:.3f}'.format(r2_score(y_test, predictions_lr)))

4.3 随机森林回归

指定500棵树进行集成,并调整树的最大深度、节点进一步分裂所需的最小样本数、每棵树使用的特征数等参数:

from sklearn.ensemble import RandomForestRegressor
param_grid = {
    'max_depth': [50, 70, 80],
    'min_samples_split': [5, 10],
    'max_features': ['auto', 'sqrt'],
    'min_samples_leaf': [3, 5]
}
rf = RandomForestRegressor(n_estimators=500, n_jobs=-1)
grid_search = GridSearchCV(rf, param_grid, cv=5, scoring='r2', 
                           n_jobs=-1)
grid_search.fit(X_train, y_train)

选择最佳回归森林模型并对测试样本进行预测:

print(grid_search.best_params_)
rf_best = grid_search.best_estimator_
predictions_rf = rf_best.predict(X_test)

评估预测性能:

print('MSE: {0:.3f}'.format(mean_squared_error(y_test, predictions_rf)))
print('MAE: {0:.3f}'.format(mean_absolute_error(y_test, predictions_rf)))
print('R^2: {0:.3f}'.format(r2_score(y_test, predictions_rf)))

4.4 SVR

使用线性和RBF核的SVR,并对惩罚参数 $C$、$\epsilon$ 以及RBF的核系数进行微调。由于SVR对特征尺度差异较大的数据效果不佳,我们使用缩放后的数据训练模型:

from sklearn.svm import SVR
param_grid = [
    {'kernel': ['linear'], 'C': [100, 300, 500], 
     'epsilon': [0.00003, 0.0001]},
    {'kernel': ['rbf'], 'gamma': [1e-3, 1e-4],
     'C': [10, 100, 1000], 'epsilon': [0.00003, 0.0001]}
]
svr = SVR()
grid_search = GridSearchCV(svr, param_grid, cv=5, scoring='r2')
grid_search.fit(X_scaled_train, y_train)

选择最佳SVR模型并对测试样本进行预测:

print(grid_search.best_params_)
svr_best = grid_search.best_estimator_ 
predictions_svr = svr_best.predict(X_scaled_test)

评估预测性能:

print('MSE: {0:.3f}'.format(mean_squared_error(y_test, predictions_svr)))
print('MAE: {0:.3f}'.format(mean_absolute_error(y_test, predictions_svr)))
print('R^2: {0:.3f}'.format(r2_score(y_test, predictions_svr)))

4.5 神经网络

微调神经网络的超参数,包括隐藏层大小、激活函数、优化器、学习率、惩罚因子和小批量大小:

from sklearn.neural_network import MLPRegressor
param_grid = {
    'hidden_layer_sizes': [(50, 10), (30, 30)],
    'activation': ['logistic', 'tanh', 'relu'],
    'solver': ['sgd', 'adam'],
    'learning_rate_init': [0.0001, 0.0003, 0.001, 0.01],
    'alpha': [0.00003, 0.0001, 0.0003],
    'batch_size': [30, 50]
}
nn = MLPRegressor(random_state=42, max_iter=2000)
grid_search = GridSearchCV(nn, param_grid, cv=5, scoring='r2', 
                           n_jobs=-1)
grid_search.fit(X_scaled_train, y_train)

选择最佳神经网络模型并对测试样本进行预测:

print(grid_search.best_params_)
nn_best = grid_search.best_estimator_
predictions_nn = nn_best.predict(X_scaled_test)

评估预测性能:

print('MSE: {0:.3f}'.format(mean_squared_error(y_test, predictions_nn)))
print('MAE: {0:.3f}'.format(mean_absolute_error(y_test, predictions_nn)))
print('R^2: {0:.3f}'.format(r2_score(y_test, predictions_nn)))

最后,我们还可以绘制每种算法生成的预测结果以及真实值,以便更直观地比较它们的性能。

性能指标对比表格

算法 MSE MAE R^2
SGD-based线性回归 18934.971 100.244 0.979
随机森林回归 260349.365 299.344 0.706
SVR 17466.596 95.070 0.980
神经网络 19619.618 100.956 0.978

预测流程mermaid流程图

graph LR
    A[数据准备] --> B[特征归一化]
    B --> C[模型选择与参数调优]
    C --> D[模型训练]
    D --> E[模型预测]
    E --> F[性能评估]

通过以上步骤,我们可以全面地了解和应用这些回归算法,并评估它们在股票价格预测问题上的性能。不同的算法在不同的数据集和任务中可能表现出不同的优势,因此在实际应用中需要根据具体情况选择合适的算法和参数。

4.6 各算法性能分析

从上述实验结果的性能指标对比表格可以看出,不同算法在股票价格预测任务中的表现存在差异。

  • SGD - based线性回归 :MSE为18934.971,MAE为100.244,$R^2$ 达到0.979。这表明该算法在预测股票价格时,预测值与实际值的误差相对较小,拟合效果较好。其优点是计算相对简单,训练速度较快,能够快速得到预测结果。但它假设特征与目标变量之间存在线性关系,对于复杂的非线性关系可能无法很好地捕捉。
  • 随机森林回归 :MSE高达260349.365,MAE为299.344,$R^2$ 为0.706。虽然 $R^2$ 表明有一定的拟合效果,但MSE和MAE的值较大,说明预测误差较大。随机森林是一种集成学习方法,能够处理非线性关系,并且具有较好的抗过拟合能力。然而,在这个任务中,可能由于特征选择或参数调整不当,导致其性能不如其他算法。
  • SVR :MSE为17466.596,MAE为95.070,$R^2$ 为0.980。SVR在四种算法中表现最佳,它能够通过调整核函数和参数,适应不同的数据分布和特征关系。线性核和RBF核的使用使得它在处理线性和非线性问题上都有较好的表现。
  • 神经网络 :MSE为19619.618,MAE为100.956,$R^2$ 为0.978。神经网络具有强大的学习能力,能够自动提取数据中的复杂特征和模式。但它的训练过程相对复杂,需要大量的计算资源和时间,并且容易过拟合。在本实验中,通过微调超参数,取得了较好的预测效果。

4.7 综合建议

根据各算法的性能表现,在实际应用中可以根据具体情况选择合适的算法:
- 如果数据特征与目标变量之间存在明显的线性关系,且对计算速度有较高要求,SGD - based线性回归是一个不错的选择。
- 当数据关系复杂,需要处理非线性问题,并且有足够的计算资源和时间进行模型训练和参数调优时,SVR和神经网络可能更适合。
- 随机森林回归可以作为一种备选方案,在特征选择和参数调整得当的情况下,也能取得较好的效果。

5. 总结与展望

5.1 总结

本文详细介绍了四种流行的回归算法:支持向量回归(SVR)、神经网络、SGD - based线性回归和随机森林回归,并将它们应用于股票价格预测问题。通过对这些算法的原理、实现步骤和性能评估的介绍,我们可以得出以下结论:
- 不同的回归算法具有不同的特点和适用场景,在实际应用中需要根据数据的特点和任务的需求选择合适的算法。
- 数据预处理(如特征归一化)对于算法的性能至关重要,特别是对于对特征尺度敏感的算法,如SGD - based线性回归和SVR。
- 模型的性能不仅取决于算法本身,还与参数调优密切相关。通过网格搜索等技术,可以找到最优的参数组合,提高模型的预测性能。

5.2 展望

虽然我们在股票价格预测问题上取得了一定的成果,但仍然存在一些可以改进和拓展的方向:
- 特征工程 :可以进一步挖掘和提取更多有价值的特征,如技术指标、宏观经济数据等,以提高模型的预测能力。
- 模型融合 :将多种算法进行融合,综合利用它们的优势,可能会得到更好的预测效果。例如,可以采用集成学习的方法,将多个不同的回归模型进行组合。
- 实时预测 :股票市场是动态变化的,实时数据的更新对于准确预测股票价格至关重要。可以考虑引入实时数据处理和更新机制,实现对股票价格的实时预测。

不同算法特点总结列表

  • SGD - based线性回归
    • 优点:计算简单,训练速度快,适用于线性关系数据。
    • 缺点:对非线性关系捕捉能力弱。
  • 随机森林回归
    • 优点:能处理非线性关系,抗过拟合能力较好。
    • 缺点:可能需要大量参数调优,本次实验中性能不佳。
  • SVR
    • 优点:可通过核函数适应不同数据关系,表现稳定且效果好。
    • 缺点:对特征尺度敏感,需要进行归一化处理。
  • 神经网络
    • 优点:学习能力强,能自动提取复杂特征。
    • 缺点:训练复杂,易过拟合,计算资源和时间要求高。

未来改进方向mermaid流程图

graph LR
    A[特征工程] --> B[模型融合]
    B --> C[实时预测]
    D[数据预处理] --> A
    D --> B
    D --> C

通过不断地探索和改进,我们有望提高回归算法在股票价格预测等实际问题中的性能,为投资者提供更准确的决策支持。在实际应用中,我们需要根据具体情况灵活选择和应用这些算法,并不断优化和改进模型,以适应不断变化的市场环境。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值