由于项目需要建立一个SVR模型,记录一下libsvm的使用流程。

因为要做的是回归,所以我们应该有一些输入$x$(每一行代表一个样本),输出$y$,从而得到$y=f(x)$的关系用于预测;当$y$为多维时,逐维进行回归。

Step 1 对数据进行scaleing,训练数据和测试数据都需要!

这里提供一个自己写的scaling函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 2020/02/19 by Minghao Chen, this function is used to scale the data; 
 
 %Usage: 
 %for traindata: [traindata,minimums,ranges] = svm_scale(traindata),
 %it will return the minimums and ranges of traindata, which will be needed 
 %in testdata scaling
 %For testdata:  [testdata,minimums,ranges] = svm_scale(testdata,minimums,ranges)
 
 function [data,minimums,ranges] = svm_scale(data,minimums,ranges)
    if nargin == 1
        minimums = min(data, [], 1);
        ranges = max(data, [], 1) - minimums;
        data = (data - repmat(minimums, size(data, 1), 1)) ./ repmat(ranges, size(data, 1), 1);
    else
        data = (data - repmat(minimums, size(data, 1), 1)) ./ repmat(ranges, size(data, 1), 1);
    end

Step 2 首先考虑RBF核函数,通过grid search进行参数$C, \gamma$寻优,可以先粗后细(大区间到小区间)

在进行参数搜索时可以用交叉验证,中途会涉及数据的划分,这里提供一个自己写的数据划分的程序

1
2
3
4
5
6
7
function [train_data,train_target,valid_data,valid_target] = data_split(data,target,k)
    N = size(data,1);
    p = randperm(N)';
    train_data = data(p(1:round(k*N)),:);
    valid_data = data(p(1+round(k*N):end),:);
    train_target = target(p(1:round(k*N)),:);
    valid_target = target(p(1+round(k*N):end),:);

其中data放的就是$x$,target放的就是$y$,参数$k$取值$(0,1)$表示你要拿多少的数据用于训练

Step 3 用最优的超参数来训练模型

这里就需要用到libsvm里的训练函数了:

model = svmtrain(train_y,train_x,‘options’)

需要注意的是’options’, 直接给个例子在解释吧,比如:

1
model = svmtrain(train_y,train_x,'-s 3 -t 2 -p 0.01 -c 2 -g 2')

其中各个缩写表示的含义为:

-s 类型 : set type of SVM (default 0)

1
2
3
4
5
6
7
8
9
0 -- C-SVC

1 -- nu-SVC

2 -- one-class SVM

3 -- epsilon-SVR

4 -- nu-SVR

-t 核函数 : set type of kernel function (default 2)

1
2
3
4
5
6
7
0 -- linear

1 -- polynomial

2 -- radial basis function: $exp(-\gamma*|u-v|^2)$

3 -- sigmoid

-g gamma : set gamma in kernel function (default 1/num_features)

-c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)

-p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)

Step 4 模型训练好可以直接保存下来,是个结构体的形式

save RegressModel.mat model

Step 5 如果有测试数据就可以进一步进行验证了

这里涉及libsvm的预测函数

[predict_y,accuracy,dec_value] = svmpredict(test_y,test_x,model)

其中,test_y如果没有可以用任意向量替代,此时输出accuracy是一个$3*1$向量,分别表示分类准确率(分类问题使用),MSE(越小越好),平方关系系数$r^2$(越接近1越好)。

例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
x=(-10:0.5:9.5)'; 
y=-x.^2;

[x_scale,minimums,ranges] = svm_scale(x);

% grid search for hyperparameters
c = [];
g = [];
N_grid = 11;
for i = 1:N_grid
    c = [c, 2^(-7+2*i)];
    g = [g, 2^(-7+2*i)];
end

MSE = 0; 
for i = 1:N_grid
    for j = 1:N_grid
        ops = ['-s 3 -t 2 -p 0.01 -c ',num2str(c(i)),' -g ',num2str(g(j))];
        [train_data,train_target,valid_data,valid_target] = data_split(x_scale,y,0.7);
        model = svmtrain(train_target,train_data,ops);
        [py,mse,prob_estimates]=svmpredict(valid_target,valid_data,model); 
        MSE(i,j) = mse(2);
    end
end
[i,j]=find(MSE==min(min(MSE)));
ops = ['-s 3 -t 2 -p 0.01 -c ',num2str(c(i)),' -g ',num2str(g(j))];

% 根据网格搜索得到的最优参数进行全部数据建模
model = svmtrain(y,x_scale,ops);
[py,mse,prob_estimates]=svmpredict(y,x_scale,model); 

% 画图 训练数据的拟合结果
figure; 
plot(x,y,'o'); 
hold on 
plot(x,py,'r*'); 
legend('原始数据','回归数据'); grid on;


% 测试
testx = [-16:0.2:-8]'; 
testy = -testx.^2;
[testx_scale,minimums,ranges] = svm_scale(testx,minimums,ranges);
[ptesty,tmse,prob_estimates]=svmpredict(testy,testx_scale,model); 

figure; 
plot(testx,testy,'o'); 
hold on 
plot(testx,ptesty,'r*'); 
legend('原始数据','回归数据'); grid on;