如何轉成libsvm支持的數據格式並做迴歸分析

在matlab中安裝好libsvm包(過程請見 matlab 安裝 libsvm 做迴歸分析)後,我們來用libsvm做一個迴歸。

本次實驗的數據是來自老師給的2006-2008年的日期,24小時的溫度、電力負荷數據,以及2009年的日期,24小時的溫度數據,目的是預測2009年每天24小時的電力負荷,實驗數據本文不予給出。

用libsvm進行預測的步驟大體是:將數據進行歸一化處理,並轉換成livsvm需要的格式,然後進行參數擇優,用選的最佳參數使用2006-2008 3年的數據建立模型,再用該模型預測2009年的電力負荷。實際過程中,我先用2006-2007年的數據建模,預測2008年的數據,以得到測試誤差。事實證明,用2006-2007 兩年的數據建模來預測2008年的電力負荷,效果要比單用2007年的數據建模預測2008年的電力負荷的效果好。所以最終我是用2006-2008 三年的數據進行建模,來預測。

libsvm訓練模型時,設置的參數有:
-s SVM類型,取值有 0,1,2,3,4 迴歸的話選3或4.
-t 核函數類型,取值有0,1,2,3 0是線性核函數,1是多項式核函數,2是RBF徑向基核函數,3是sigmoid 核函數。
-g gamma,這是針對多項式、RBF、sigmoid 核函數纔有的參數選項。默認是1/k,k是屬性數/類別數。
-c 爲 c-SVC、e-SVR 和 nu-SVR 設置的損失函數,默認爲1.

詳細的參數描述見 LIBSVM使用方法及參數設置(轉)

下面是進行迴歸預測的步驟:

1.將數據轉換成libsvm需要的格式

數據格式需要:

target屬性 第1個屬性:值 第2個屬性:值
2 1:7 2:5
1 1:4 2:2

即如果是分類問題的話,第一列是類別屬性。

在網上下載一個 write4libsvm.m 格式轉換程序,在matlab中直接運行,然後選擇需要轉換的數據文件即可,非常簡便易用。

write4libsvm.m

function write4libsvm 
% 爲了使得數據滿足libsvm的格式要求而進行的數據格式轉換 注意原始格式是mat的數據格式,轉化成txt或者dat都可以。
% 原始數據保存格式爲: 
%             [標籤 第一個屬性值 第二個屬性值...] 
% 轉換後文件格式爲滿足libsvm的格式要求,即: 
%             [標籤 1:第一個屬性值 2:第二個屬性值 3:第三個屬性值 ...] 
% Genial@ustc 
% 2004.6.16 
[filename, pathname] = uigetfile( {'*.mat', ... 
       '數據文件(*.mat)'; ... 
       '*.*',                   '所有文件 (*.*)'}, ... 
   '選擇數據文件'); 
try 
   S=load([pathname filename]); 
   fieldName = fieldnames(S); 
   str = cell2mat(fieldName); 
   B = getfield(S,str); 
   [m,n] = size(B); 
   [filename, pathname] = uiputfile({'*.txt;*.dat' ,'數據文件(*.txt;*.dat)';'*.*','所有文件 (*.*)'},'保存數據文件'); 
   fid = fopen([pathname filename],'w'); 
   if(fid~=-1) 
       for k=1:m 
           fprintf(fid,'%3d',B(k,1)); 
           for kk = 2:n 
               fprintf(fid,'\t%d',(kk-1)); 
               fprintf(fid,':'); 
               fprintf(fid,'%d',B(k,kk)); 
           end 
           k 
           fprintf(fid,'\n'); 
       end 
       fclose(fid); 
   else 
       msgbox('無法保存文件!'); 
   end 
catch 
end 

2. 選擇核函數類型

我選擇的是RBF核函數。

2.將數據做歸一化處理

不做歸一化處理的話,最後預測誤差會很大。
通過程序對屬性進行歸一化處理。一開始我並沒有做歸一化處理,結果測試誤差MAPE達14%,做屬性歸一化處理後,測試數據的MAPE是3.9556% 。

clear;
load('X1.mat');% X1.mat 是訓練集。
load('X2.mat');% X2.mat 是測試集。

X1_1 =normalization(X1);
X2_1 =normalization(X2);

%另存爲X1_1.mat X2_1.mat 然後運行 **write4libsvm.m** 轉成符合需要的格式的文件 X1_1.csv 和 X2_1.csv。


%進入D:\softwares_diy\MATLAB\R2014a\toolbox\libsvm-3.21目錄,將D:\softwares_diy\MATLAB\R2014a\toolbox\libsvm-3.21\matlab添加到路徑

[Y1, X1] = libsvmread('X1_1.csv');% Y1 X1 是2006-2008年的數據。
[Y2, X2] = libsvmread('X2_1.csv');%Y2 X2 是2009年的數據。

Y1_train =  Y1(1:17520,:); %06-07年的數據做訓練
X1_train = X1(1:17520,:);
Y1_test =  Y1(17521:end,:);%08年的數據做測試
X1_test = X1(17521:end,:);

3.參數尋優

需調整的重要參數是 -c 和 -g。 -c指定損失函數,-g是針對多項式、RBF、sigmoid核函數的γ值設置。

我用程序 SVM.cg.m 通過指定c的變化範圍和g的變化範圍來尋找最優的參數c和g。

這是 預測代碼

%尋找最優的 c 和 g
result1 = [];
% 06-07年的數據訓練,08年的數據做測試。
%SVMcg(train_label,train,cmin,cmax,gmin,gmax,v,cstep,gstep,accstep)
%參數 c的變化範圍是 [2^cmin,2^cmax]
%參數g的變化範圍是[2^gmin,2^gmax]
%cstep是c的變化步長,gstep是g的變化步長。
[bestacc,bestc,bestg] = SVMcg(Y1_train,X1_train,0,8,-1,4,2,1,1,0.9);
%跑了很久纔出來
cmd = ['-s 3 -t 2',' -c ',num2str(bestc),' -g ',num2str(bestg)];
model = libsvmtrain(Y1_train, X1_train, cmd);
[y_08_pre,mse,decision_values] = libsvmpredict(Y1_test,X1_test,model);
MAPE = mean(abs(y_test_pre-Y1_test)./Y1_test);%計08年的MAPE
RMSE = sqrt(mean((y_test_pre-Y1_test).^2));
MAE = mean(abs(y_test_pre-Y1_test));
MSE = mean((y_test_pre-Y1_test).^2);     
clear model cmd y_test_pre mse decision_values MAPE RMSE MAE MSE bestacc bestc bestg;

%06-08年的數據做訓練,09年測試。
[bestacc,bestc,bestg] = SVMcg(Y1,X1,0,8,-1,4,2,1,1,0.9);
cmd = ['-s 3 -t 2',' -c ',num2str(bestc),' -g ',num2str(bestg)];

model = libsvmtrain(Y1, X1, cmd);
[y_09_pre,mse,decision_values] = libsvmpredict(Y2,X2,model);

其中 y_09_pre 是預測的 2009年每天24小時的電力負荷,由於並沒有2009年電力負荷的真實值,所以忽略libsvmpredict的返回值mse。

SVM.cg.m

function [bestacc,bestc,bestg] = SVMcg(train_label,train,cmin,cmax,gmin,gmax,v,cstep,gstep,accstep)
%SVMcg cross validation by faruto
%Email:[email protected] QQ:516667408 http://blog.sina.com.cn/faruto BNU
%last modified 2009.8.23
%Super Moderator @ www.ilovematlab.cn
%% about the parameters of SVMcg 
if nargin < 10
    accstep = 1.5;
end
if nargin < 8
    accstep = 1.5;
    cstep = 1;
    gstep = 1;
end
if nargin < 7
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
end
if nargin < 6
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
end
if nargin < 5
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
end
if nargin < 4
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
end
if nargin < 3
    accstep = 1.5;
    v = 3;
    cstep = 1;
    gstep = 1;
    gmax = 5;
    gmin = -5;
    cmax = 5;
    cmin = -5;
end
%% X:c Y:g cg:acc
[X,Y] = meshgrid(cmin:cstep:cmax,gmin:gstep:gmax);
[m,n] = size(X);
cg = zeros(m,n);
%% record acc with different c & g,and find the bestacc with the smallest c
bestc = 0;
bestg = 0;
bestacc = 0;
basenum = 2;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -c ',num2str( basenum^X(i,j) ),' -g ',num2str( basenum^Y(i,j) )];
        cg(i,j) = libsvmtrain(train_label, train, cmd);

        if cg(i,j) > bestacc
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end
        if ( cg(i,j) == bestacc && bestc > basenum^X(i,j) )
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end

    end
end
%% to draw the acc with different c & g
[C,h] = contour(X,Y,cg,60:accstep:100);
clabel(C,h,'FontSize',10,'Color','r');
xlabel('log2c','FontSize',10);
ylabel('log2g','FontSize',10);
grid on;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章