基于LSSVM的时间序列预测模型:单输入单输出代码,含注释可直接替换数据
利用最小支持向量机LSSVM做时间序列预测模型数据是单输入单输出的替换数据就可以用代码内有注释最近帮楼下奶茶店老板救过个场——上周看他蹲在冰箱跟前扒坏的芋泥泥芋圆碎半箱都要长毛了说是上周刷了个本地芋泥节的预告瞎囤的。我心想这有啥搞个单输入单输出的销量预测小脚本替换下芋泥波波改成杨枝甘露替换成本地每周六气温改成本地周末某商圈人流量甚至随便改个股票收盘价、用电量序列敲敲回车就能跑。选模型的时候专门挑了最省心、单输出友好的最小支持向量机LSSVM普通SVM搞回归有时候得找ε不敏感带的边边角角算半天二次规划LSSVM直接改成了解线性方程组快得像老板摇奶茶盖儿。先给你们丢个完整带注释的Python脚本不用特意搜lssvm库有没有更新或者会不会报错我直接用numpy和scipy解了核心公式——自己捏轮子不是装逼是方便你们调得更顺手替换数据的时候绝对不会因为库版本不对卡壳。import numpy as np import pandas as pd from scipy.linalg import solve from sklearn.preprocessing import MinMaxScaler # 这里用了个sklearn的归一化新手不会踩单位大坑 import matplotlib.pyplot as plt # 画个图直观看看老板芋泥节预告翻车那天的预测 plt.rcParams[font.sans-serif] [SimHei] # 解决中文乱码 plt.rcParams[axes.unicode_minus] False # 替换数据只需要改这里的csv路径和列名比如csv里只有杨枝甘露销量就改成df[销量] df pd.read_csv(weekly_bubbletea.csv) # 我的csv里是日期,芋泥波波周销量 raw_data df[芋泥波波周销量].values.reshape(-1, 1) # 必须转成二维归一化和滑动窗口要用到 # 滑动窗口超关键比如用过去3周的销量预测第4周这里window_size3可以改 window_size 3 X, y [], [] for i in range(len(raw_data) - window_size): X.append(raw_data[i:iwindow_size, 0]) # 输入过去3周 y.append(raw_data[iwindow_size, 0]) # 输出第4周 X np.array(X) y np.array(y).reshape(-1, 1) # 同样转二维 # 数据归一化销量有时候差10倍ML模型会疯 scaler_X MinMaxScaler(feature_range(0, 1)) scaler_y MinMaxScaler(feature_range(0, 1)) X_scaled scaler_X.fit_transform(X) y_scaled scaler_y.fit_transform(y) # 简单分训练集测试集比如前80%训练后20%看效果 train_ratio 0.8 train_size int(len(X_scaled) * train_ratio) X_train, X_test X_scaled[:train_size], X_scaled[train_size:] y_train, y_test y_scaled[:train_size], y_scaled[train_size:] # ---------------------- 2. 手写LSSVM核心公式RBF核通用但效果还行 ---------------------- # RBF核的参数gamma新手可以先默认1.0后面调调老板芋泥销量应该更准 gamma 1.0 # LSSVM的正则化参数C控制拟合程度别太小欠拟合别太大过拟合新手默认10.0 C 10.0 def rbf_kernel(x1, x2, gamma): 计算RBF核矩阵别纠结数学公式记住它是把低维销量扔去高维找规律就行 return np.exp(-gamma * np.sum((x1 - x2)**2, axis1)) # 用广播机制加速不用循环 # 构造线性方程组的系数矩阵Omega和右边的向量Y n_train len(X_train) Omega np.zeros((n_train, n_train)) for i in range(n_train): # 这里取了X_train[i]和整个X_train的差省了一层循环 Omega[i, :] rbf_kernel(X_train[i].reshape(1, -1), X_train, gamma) # 系数矩阵A [0 1^T; 1 Omega I/C] A np.block([ [0, np.ones((1, n_train))], [np.ones((n_train, 1)), Omega np.eye(n_train)/C] ]) # 右边的向量b [0; y_train] b np.block([[0], y_train]) # 解线性方程组scipy的solve比自己写高斯消元快多了 solution solve(A, b) bias solution[0, 0] # 提取偏置项b alpha solution[1:, 0] # 提取拉格朗日乘子alpha # ---------------------- 3. 预测与反归一化 ---------------------- def lssvm_predict(X_pred, X_train, alpha, bias, gamma): 预测函数同样用广播机制 n_pred len(X_pred) y_pred_scaled np.zeros(n_pred) for i in range(n_pred): kernel_pred rbf_kernel(X_pred[i].reshape(1, -1), X_train, gamma) y_pred_scaled[i] np.sum(alpha * kernel_pred) bias return y_pred_scaled.reshape(-1, 1) # 预测训练集和测试集看看有没有过拟合老板芋泥节 y_train_pred_scaled lssvm_predict(X_train, X_train, alpha, bias, gamma) y_test_pred_scaled lssvm_predict(X_test, X_train, alpha, bias, gamma) # 反归一化不然是0-1的数字老板看不懂 y_train_pred scaler_y.inverse_transform(y_train_pred_scaled) y_test_pred scaler_y.inverse_transform(y_test_pred_scaled) y_train_true scaler_y.inverse_transform(y_train) y_test_true scaler_y.inverse_transform(y_test) # ---------------------- 4. 简单可视化和误差看看 ---------------------- # 可视化整个序列的真实值和预测值 plt.figure(figsize(12, 6)) # 训练集和测试集的x轴拼接一下看起来连贯 x_train np.arange(window_size, window_size train_size) x_test np.arange(window_size train_size, window_size train_size len(y_test_true)) plt.plot(x_train, y_train_true, label训练集真实销量, colorskyblue) plt.plot(x_train, y_train_pred, label训练集预测销量, colordodgerblue, linestyle--) plt.plot(x_test, y_test_true, label测试集真实销量, colororange) plt.plot(x_test, y_test_pred, label测试集预测销量, colororangered, linestyle--) # 标记老板芋泥节那周假设测试集第5周是随便举的你们不用 if len(x_test) 5: plt.scatter(x_test[4], y_test_true[4], colorred, marker*, s200, label芋泥节瞎囤周) plt.xlabel(时间周数) plt.ylabel(芋泥波波周销量) plt.title(楼下芋泥波波周销量LSSVM预测) plt.legend() plt.show() # 算个MAE平均绝对误差老板也看得懂平均每周差多少杯 mae_train np.mean(np.abs(y_train_true - y_train_pred)) mae_test np.mean(np.abs(y_test_true - y_test_pred)) print(f训练集平均每周差{mae_train:.0f}杯) print(f测试集平均每周差{mae_test:.0f}杯)接下来捏捏核心公式这块别被block吓到其实就是把普通SVM的二次规划目标函数和约束条件改了普通SVM是找个窄窄的ε不敏感带让尽量多的点落在带子里超参数要调C带外点的惩罚和ε带的宽度有时候ε调不对直接白搭LSSVM直接把约束条件里的不等式ξi≥0, ξi^≥0改成了等式损失函数换成了ξi²ξi^2就变成解Axb的线性方程了——新手不用懂具体推只需要记住这里面只有RBF核的gamma和正则化C两个超参数新手先随便试gamma0.5/1.0/2.0C1/10/100基本能凑合用要精准的话可以加个网格搜索比如把gamma和C放数组里循环跑算MAE最小的但楼下老板要的是快和能用懒得搞太复杂的。滑动窗口那块也很重要这个不是LSSVM独有的所有单输入单输出时间序列预测都得搞这个——时间序列的数据不是独立的这周卖多少肯定和上周上上周有关windowsize就是你选“多少周相关”老板奶茶店可能3周-4周就行股票收盘价可能得1周-2周随便改脚本里直接改windowsize数字。利用最小支持向量机LSSVM做时间序列预测模型数据是单输入单输出的替换数据就可以用代码内有注释归一化也是必加的新手友好操作比如老板芋泥波波销量最高1000杯最低100杯杨枝甘露销量最高2000杯最低200杯如果不归一化直接扔进去杨枝甘露的2000杯会把LSSVM的注意力全吸走预测芋泥波波就不准了用MinMaxScaler把所有数据缩到0-1之间公平竞争。可视化那块老板蹲在我手机屏幕上看了好久指着红色星星说“你看你看上周芋泥节真实销量只有800预测有1200我要是早看这个只囤一半芋泥泥就好了”我拍了拍他肩膀“下次杨枝甘露节记得把列名改了再来找我。”对了新手替换数据的时候真的只需要改第一步的csv路径和列名比如你们用的是csv里的苹果股价收盘价就把rawdata df[芋泥波波周销量]改成rawdata df[苹果股价收盘价]滑动窗口window_size改成5比如过去5天预测第6天其他代码一个字不用动敲敲回车就能跑。