[个人笔记]机器学习模型代码审计 - 以Python的sklearn库中的SVM模型预测股价为例

前言

自用。知识点跳跃且不适合Python或是编程0基础的同学看
主要是对现有代码的理解(审计)
本策略和金融没太大关系,主要是计算机和数学

1理论部分(可忽略)

  • 回归问题

是机器学习中的一类问题,其中的目标是预测连续型的数值输出。换句话说,回归问题是一种建立输入变量与连续型输出变量之间关系的问题。

  • K折交叉验证

在你的代码中,如果使用的是 K 折交叉验证且设置了 shuffle=False,那么每个样本确实会且仅会出现一次,但在不同的测试集中。

2 读取文件和数据标准化

读文件源程序

`# 读取 Excel 文件
df = pd.read_excel('E:\谷歌浏览器下载的文件\参考文献\Yinzi.xlsx')
# 对整个 DataFrame 进行线性插值
df_interpolated = df.interpolate(method='linear', axis=0)
df_interpolated.to_excel('E:\谷歌浏览器下载的文件\参考文献\merged_d123ta.xlsx', index=False)
# 检查是否存在缺失值
missing_values = df_interpolated.isnull().sum()

# 打印每列的缺失值数量
print(missing_values)
`

2.1read_excel

当你使用Pandas库中的read_excel()函数从Excel文件中读取数据时,Pandas会将Excel文件中的每个工作表(sheet)解析为一个DataFrame对象。DataFrame是一个二维的数据结构,类似于电子表格,由行和列组成。让我详细解释一下数据在读取和处理过程中可能的格式转换:

  • 数据类型推断

  • Pandas会尝试根据每列的内容推断数据类型。例如,如果一列包含数字,Pandas会将其识别为数值型数据,如果一列包含字符串,Pandas会将其识别为对象(字符串)数据类型。

  • 但有时候,Pandas可能会将数据错误地推断为不正确的数据类型。因此,可以通过dtype参数手动指定数据类型,以确保正确地解析数据。

  • 缺失值处理

  • 在Excel文件中,可能会存在一些空单元格,这些空单元格在读取后会被Pandas解析为缺失值(NaN)。Pandas提供了许多方法来处理缺失值,如填充、删除或插值。

  • 日期时间数据的解析

  • 如果Excel文件中包含日期时间数据,Pandas会尝试将其解析为日期时间数据类型。这使得可以对日期时间进行各种操作,如筛选、分组和计算时间间隔。

  • 索引处理

  • 默认情况下,Pandas会自动生成一个整数索引,从0开始递增。但是,你也可以通过index_col参数指定一个列作为DataFrame的索引,或者在读取后通过set_index()方法设置索引。

  • 数据转换

  • 在DataFrame中,每列的数据类型可能不同,可以使用Pandas提供的方法对数据进行转换。例如,可以使用astype()方法将某一列的数据类型转换为其他类型。


标准化源程序

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from scipy.stats import boxcox

# 读取金融股票数据,假设数据已经存储在一个名为 'stock_data.csv' 的文件中
df = pd.read_excel('E:\谷歌浏览器下载的文件\参考文献\merged_d12s3ta.xlsx')

df = df.fillna(df.mean())
# 排除 'Symbol' 和 'TradingDate' 列
exclude_columns = ['Symbol', 'TradingDate' ,'ShortName_x','SecurityID_x','BuySymbol','LimitStatus']
numeric_columns = df.select_dtypes(include=['float64', 'int64']).columns
features_to_standardize = [col for col in numeric_columns if col not in exclude_columns]

2.2 features_to_standardize = [col for col in numeric_columns if col not

in exclude_columns]

在 Python 中,列表推导式中的条件语句可以跨越多行,不需要显式地使用换行符。Python 解释器会根据缩进来确定条件语句的范围。因此,你可以在一行中编写条件语句,也可以将其分成多行以提高可读性,但要确保缩进正确。例如:

features_to_standardize = [
    col for col in numeric_columns if col not in exclude_columns
]

或者,如果条件语句较长,可以使用括号将其括起来:

features_to_standardize = [
    col for col in numeric_columns
    if (col not in exclude_columns and
        some_other_condition)
]

这种写法更容易阅读和维护。
举个例子

even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)

#even_squares=[0, 4, 16, 36, 64]

2.3 df[features_to_standardize] =

min_max_scaler.fit_transform(df[features_to_standardize])

可能情况为

df[['1', '11']] = min_max_scaler.fit_transform(df[['1', '11']])

说明这个方法是对多个列进行标准化的过程,而不是单个列


3模型训练-以SVM模型为例

以下为源程序

#SVM
import pandas as pd
from sklearn.model_selection import GridSearchCV, KFold
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error, mean_absolute_error
from datetime import timedelta
import joblib

# 读取数据
data = pd.read_excel(r'E:\谷歌浏览器下载的文件\参考文献\SVM\t.xlsx')



# 提取特征和标签
X = data.drop(columns=['Symbol','TradingDate','ClosePrice', 'SecurityID_x'])   # 解释变量

y = data['ClosePrice']  # 被解释变量




# 定义交叉验证
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 定义SVM模型
svm_model = SVR()

# 定义要调优的参数空间
param_grid = {
    'C': [0.1, 1, 10, 100],
    'gamma': [0.001, 0.01, 0.1, 1],
    'kernel': ['linear', 'rbf', 'poly']
}

# 定义评价指标
def rmse(y_true, y_pred):
    return mean_squared_error(y_true, y_pred, squared=False)

# 计算平均绝对误差
def mae(y_true, y_pred):
    return mean_absolute_error(y_true, y_pred)

# 定义用于滚动预测的函数
def rolling_predict(model, X, y, cv):
    y_true = []
    y_pred = []
    for train_index, test_index in cv.split(X):
        X_train, X_test = X.iloc[train_index], X.iloc[test_index]
        y_train, y_test = y.iloc[train_index], y.iloc[test_index]
        
        # 训练模型
        model.fit(X_train, y_train)
        
        # 预测
        y_pred.extend(model.predict(X_test))
        y_true.extend(y_test)
    
    return y_true, y_pred

# 执行交叉验证和参数优化
grid_search = GridSearchCV(svm_model, param_grid, cv=kf, scoring='neg_mean_squared_error', n_jobs=1)
grid_search.fit(X, y)

# 输出SVM默认参数
print("SVM默认参数:", svm_model.get_params())
svm_model.fit(X, y)
# 输出默认参数下的评价指标
default_predictions = svm_model.predict(X)
default_mse = mean_squared_error(y, default_predictions)
default_rmse = rmse(y, default_predictions)
default_mae = mae(y, default_predictions)

print("默认参数下的MSE:", default_mse)
print("默认参数下的RMSE:", default_rmse)
print("默认参数下的MAE:", default_mae)

# 输出最优参数和对应的评价指标
print("最优参数:", grid_search.best_params_)
print("最优评价指标(均方根误差):", abs(grid_search.best_score_) ** 0.5)

# 使用最优参数训练最终模型
best_model = grid_search.best_estimator_

# 保存最优参数的模型到.pkl文件中
joblib.dump(best_model, 'best_svm_model.pkl') 

# 滚动预测
y_true, y_pred = rolling_predict(best_model, X, y, kf)

# 计算评价指标
mse = mean_squared_error(y_true, y_pred)
rmse_value = rmse(y_true, y_pred)
mae_value = mae(y_true, y_pred)

print("参数优化后的MSE:", mse)
print("参数优化后的RMSE:", rmse_value)
print("参数优化后的MAE:", mae_value)

# 输出参数优化后的模型到.pkl文件中
joblib.dump(best_model, 'best_svm_model.pkl')

print("参数优化后的模型已保存到 best_svm_model.pkl 文件中")

3.1 kf = KFold(n_splits=5, shuffle=True, random_state=42)

 在这段代码中,`KFold` 对象被用于定义交叉验证的方式。让我解释一下其中的参数:
  • n_splits: 这是将数据分成的折数(即将数据集分成多少份)。在这个例子中,n_splits=5 表示将数据集分成了 5 折交叉验证。

  • shuffle: 这是一个布尔值参数,表示在分割数据前是否要对数据进行洗牌。如果设置为True,那么在每次分割前都会打乱数据集的顺序。这有助于避免某些特定顺序对模型的影响,并且在数据分布不均匀的情况下可以提高模型的稳定性。在这个例子中,shuffle=True 表示在分割数据之前要对数据进行洗牌。

  • random_state: 这是一个随机种子参数,用于控制数据的洗牌过程。如果两次分割数据时指定了相同的随机种子,那么得到的结果将是相同的。这有助于使实验结果具有可重复性。在这个例子中,random_state=42 表示指定了随机种子为42。


3.2 param_grid (How to 参数设定)

以随机森林模型为例,你可以这样来查看参数及其含义:

from sklearn.ensemble import RandomForestRegressor

# 使用 help() 函数查看随机森林模型的参数
help(RandomForestRegressor)

得到一个返回文档。。。

这段文档提供了关于 RandomForestRegressor 类的参数说明。让我来逐一解释一下:

  • n_estimators: (default=100) 随机森林中树的数量(即决策树的个数)。更多的树可以提高模型的稳定性和准确性,但会增加计算成本。

  • criterion: (default=‘squared_error’) 衡量分裂质量的标准。对于回归问题,一般使用均方误差 (‘mse’) 或均绝对误差 (‘mae’)。

  • max_depth: (default=None) 决策树的最大深度。如果不设置,则树会一直生长,直到每个叶节点都包含少于min_samples_split个样本。

  • min_samples_split: (default=2) 节点在分裂之前所需的最小样本数。如果节点的样本数量小于该值,则不会进行分裂。

  • min_samples_leaf: (default=1) 叶节点所需的最小样本数。如果叶节点的样本数量小于该值,则不会继续分裂。

  • min_weight_fraction_leaf: (default=0.0) 叶节点的最小权重总和的分数。如果设置了sample_weight,则样本的权重会按照样本数量的比例计算。

  • max_features: (default=‘auto’) 在每个节点处进行分裂时考虑的特征数。可以设置为 ‘auto’、‘sqrt’、‘log2’ 或具体的整数值。 ‘auto’ 表示使用所有特征, ‘sqrt’ 表示使用 sqrt(n_features),‘log2’ 表示使用 log2(n_features)。

  • max_leaf_nodes: (default=None) 最大叶节点数量。如果不为None,则树会在达到该数量后停止生长。

  • min_impurity_decrease: (default=0.0) 节点分裂的最小不纯度减少量。分裂后的不纯度减少量必须大于等于该值才会执行分裂。

  • bootstrap: (default=True) 是否使用自助法 (bootstrap) 来构建树。如果为True,则每棵树都是从数据集中有放回地随机抽样得到的。

  • oob_score: (default=False) 是否计算 out-of-bag (OOB) 评分。如果为True,则模型会在拟合后自动计算并保存在属性 oob_score_ 中。

  • n_jobs: (default=None) 并行运行的作业数量。如果设置为-1,则使用所有可用的处理器。

  • random_state: (default=None) 随机种子用于控制随机数生成。

  • verbose: (default=0) 控制拟合过程的详细程度。如果大于0,则会输出拟合进度。

  • warm_start: (default=False) 是否使用热启动策略。如果为True,则在调用 fit() 方法时,会从先前的拟合结果继续训练。

  • ccp_alpha: (default=0.0) 防止过度剪枝的复杂性参数。在每个节点的成本复杂性修剪(Cost-Complexity Pruning)中使用。

  • max_samples: (default=None) 每棵树的最大样本数。如果设置为整数,则使用每个子样本集合的样本数。

3.3 追寻最优参数

grid_search = GridSearchCV(svm_model, param_grid, cv=kf, scoring='neg_mean_squared_error', n_jobs=1)
grid_search.fit(X, y)

GridSearchCV 函数是 scikit-learn(sklearn)库中的一个模型调优工具。
GridSearchCV 是用于系统地遍历多种参数组合,通过交叉验证来确定最佳参数的工具。下面详细解释一下 GridSearchCV 函数的各个参数和功能:

参数解释:

  • estimator:即要使用的模型,可以是任何实现了 fitpredict 方法的对象。通常是一个分类器或回归器。在你的例子中,就是 svm_model,一个支持向量机模型的实例。

  • param_grid:一个字典或列表,用于指定要搜索的参数及其可能的取值范围。字典的键是参数名称,值是参数的可能取值列表。例如,{'C': [0.1, 1, 10], 'kernel': ['rbf', 'linear']} 表示要搜索 Ckernel 两个参数,它们的取值分别为 [0.1, 1, 10]['rbf', 'linear']

  • scoring:评分指标,用于评估模型的性能。可以是字符串(预定义的评分指标名称,比如 'accuracy''precision''recall' 等),或是可调用对象(自定义的评分函数)。在你的例子中,是 'neg_mean_squared_error',即负均方误差。

  • cv:交叉验证生成器或可迭代的次数。如果是整数,则表示 K 折交叉验证。如果是交叉验证生成器(比如 KFold 对象),则用于指定交叉验证的策略。在你的例子中,是 kf,一个 KFold 对象。

  • n_jobs:并行作业数量,用于加速参数搜索。如果是 -1,则使用所有可用的 CPU 核心进行计算。在你的例子中,是 1,表示仅使用一个 CPU 核心进行计算。

其他重要属性和方法:

  • best_params_:返回一个字典,包含使模型性能最佳的参数组合。

  • best_estimator_:返回使用最佳参数组合训练的最佳模型对象。

  • cv_results_:返回一个字典,包含交叉验证的详细结果,包括每个参数组合的评分、拟合时间等信息。

  • fit(X, y):执行参数搜索和交叉验证的过程。

  • predict(X):使用最佳模型对新数据进行预测。

参数里的解释:
scoring=‘neg_mean_squared_error’ 设置了评分指标为负均方误差,即模型预测值与真实值之间的均方误差的相反数。这里采用了负数是因为 GridSearchCV 会尝试最大化评分指标,而我们通常希望均方误差越小越好,所以采用了相反数。

功能解释:

GridSearchCV 遍历参数字典中指定的所有参数组合,并针对每个组合执行交叉验证。对于每个参数组合,它在指定的交叉验证集上拟合模型,并在验证集上计算所选的评分指标。然后,它选择具有最佳评分的参数组合,并使用这些参数在整个训练集上拟合最终模型。

总之,GridSearchCV 是一个功能强大的工具,可以帮助你系统地寻找模型的最佳参数组合,从而提高模型的性能。


此时就可以输出一下最优参数了

# 输出最优参数和对应的评价指标
print("最优参数:", grid_search.best_params_)
print("最优评价指标(均方根误差):", abs(grid_search.best_score_) ** 0.5)

4交叉预测-以SVM模型为例

源代码

kf = KFold(n_splits=5, shuffle=True, random_state=42)

def rolling_predict(model, X, y, cv):
    y_true = []
    y_pred = []
    for train_index, test_index in cv.split(X):
        X_train, X_test = X.iloc[train_index], X.iloc[test_index]
        y_train, y_test = y.iloc[train_index], y.iloc[test_index]
        
        # 训练模型
        model.fit(X_train, y_train)
        
        # 预测
        y_pred.extend(model.predict(X_test))
        y_true.extend(y_test)
    
    return y_true, y_pred
best_model = grid_search.best_estimator_
y_true, y_pred = rolling_predict(best_model, X, y, kf)

# 计算评价指标
mse = mean_squared_error(y_true, y_pred)
rmse_value = rmse(y_true, y_pred)
mae_value = mae(y_true, y_pred)

print("参数优化后的MSE:", mse)
print("参数优化后的RMSE:", rmse_value)
print("参数优化后的MAE:", mae_value)

4.1第二段的cv.split(X):

cv.split(X) 返回的是一个生成器,该生成器会产生一系列元组 (train_index, test_index),其中 train_index 是训练集的索引数组,test_index 是测试集的索引数组。在循环中,每次迭代都会返回一对这样的索引数组,然后可以使用这些索引数组来从数据集 X 中提取对应的训练集和测试集。

因此,循环 for train_index, test_index in cv.split(X): 允许你在每次迭代中获得一个新的训练集和测试集的索引数组,然后你可以使用这些索引数组来提取相应的数据子集,并在模型上进行训练和评估。

4.2 第二段的iloc:

X.iloc[1]  # 选择第2行的所有列数据
X.iloc[:, 1]  # 选择所有行的第2列数据
  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值