from:http://www.doczj.com/list_31/
使用libSVM求解分類問題的C++小例
1.libSVM簡介
訓練模型的結構體
struct svm_problem//儲存參加計算的所有樣本
{
? ? ? int l; //記錄樣本總數
? ? ? double *y; //指向樣本類別的組數 ?//prob.y = new double[prob.l];?
? ? ? struct svm_node **x;//數據樣本 ? ?//prob.x = new svm_node[prob.l][] ==>svm_node[index][value] ; ?
};
當樣本類別事先已經被告知時,可以通過數字來給樣本數據進行標識(如果是兩類通常以1與-1來表示)。如果不清楚樣本類別可以用樣本個數編號來設置,這時候分類的準確率也就無法判定了。
數據樣本是一個二維數組,其中每個單元格儲存的是一個svm_node,y與樣本數據的對應關系為:
數據節點的結構體
struct svm_node//儲存單一向量的單個特征
{
? ? ? int index; //索引
? ? ? double value; //值
};
如果需要儲存向量,就可以使用6個svm_node來保存,內存映像為:
SVM模型類型枚舉
enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR };
◆C_SVC: C表示懲罰因子,C越大表示對錯誤分類的懲罰越大
◆NU_SVC: 和C_SVC相同。
◆ONE_CLASS: 不需要類標號,用于支持向量的密度估計和聚類.
◆EPSILON_SVR:-不敏感損失函數,對樣本點來說,存在著一個不為目標函數提供任何損失值的區域,即-帶。
◆NU_SVR:由于EPSILON_SVR需要事先確定參數,然而在某些情況下選擇合
適的參數卻不是一件容易的事情。而NU_SVR能夠自動計算參數。
注意:C_SVC與NU_SVC其實采用的模型相同,但是它們的參數C的范圍不同C_SVC采用的是0到正無窮,NU_SVC是[0,1]。
核函數類型枚舉
enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED };
◆LINEAR:線性核函數(linear kernel)
◆POLY:多項式核函數(ploynomial kernel)
◆RBF:徑向機核函數(radical basis function)
◆SIGMOID:神經元的非線性作用函數核函數(Sigmoid tanh)
◆PRECOMPUTED:用戶自定義核函數
計算模型參數結構體
struct svm_parameter
{
? ? ? int svm_type; //支持向量機模型類型
? ? ? int kernel_type; //核函數類型
? ? ? int kernel_type; //核函數類型
? ? ? int degree; /* 使用于POLY模型*/
? ? ? double gamma; /* for poly/rbf/sigmoid */
? ? ? double coef0; /* for poly/sigmoid */
? ? ? /* these are for training only */
? ? ? double cache_size; /* 緩存塊大小(MB) */
? ? ? double eps; /* 終止條件(默認0.001) */
? ? ? double C; /*懲罰因子for C_SVC, EPSILON_SVR and NU_SVR */
? ? ? int nr_weight; /*權重的數目for C_SVC */
? ? ? int *weight_label; /* for C_SVC */
? ? ? double* weight; /* for C_SVC */
? ? ? double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */
? ? ? double p; /* for EPSILON_SVR */
? ? ? int shrinking; /*指明訓練過程是否使用壓縮*/
? ? ? int probability; /*指明是否要做概率估計*/
};
結構體svm_mod el
用于保存訓練后的訓練模型,當然原來的訓練參數也必須保留。
struct svm_model
{
? ? ? struct svm_parameter param; /*訓練參數*/
? ? ? int nr_class; /*類別數, = 2 in regression/one class svm */
? ? ? int l; /*支持向量數*/
? ? ? struct svm_node **SV; /*支持向量的指針*/
? ? ? double **sv_coef; /*相當于判別函數中的alpha */
? ? ? double *rho; /*相當于判別函數中的b */
? ? ? double *probA; /* pariwise probability information */
? ? ? double *probB; /* for classification only */
? ? ? int *label; /* label of each class (label[k]) */
? ? ? int *nSV; /* numbe
? ? ? r of SVs for each class (nSV[k]) */
? ? ? int *nSV; /* number of SVs for each class (nSV[k]) */
? ? ? /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ int free_sv;
? ? ? /* 1 if svm_model is created by svm_load_model*/
? ? ? /* 0 if svm_model is created by svm_train */
};
2.程序代碼實現
這里定義SVMExample類,類主要成員變量為:
struct svm_parameter param; //模型參數
struct svm_problem prob;//
struct svm_model *model; //
struct svm_node *x_space; //
構造函數
構造函數里主要進行參數的初始化,和基本函數的調用
param.svm_type = C_SVC;
param.kernel_type = LINEAR;
param.degree = 3;
param.gamma = 0; // 1/num_features
param.coef0 = 0;
param.nu = 0.5;
param.cache_size = 1;//緩存塊大小
param.C = 1;
param.eps = 1e-3;
param.p = 0.1;
param.shrinking = 1;
param.probability = 0;
param.nr_weight = 0;
param.weight_label = NULL;
param.weight = NULL;
cross_validation = 0;
核函數的選取直接影響到分類的結果,如何正確選取核函數就需要使用者對數據的特性有所了解,根據實際情況,這里的核函數選用的是線性的。
?實例分析
成員函數一:初始化樣本數據
樣本選取是學生的身
高和體重:
樣本選取是學生的身高和體重:
男1:身高:190cm,體重:70kg;
男2:身高:180cm,體重:80kg;
女1:身高:161cm,體重:80kg;
女2:身高:161cm,體重:47kg;
這里由于事先已經知道樣本有男女類別之分,所以設置男生標簽為-1,女生標簽為1,相對于程序中的y值(樣本類別)。
void SVMExample::initliazeData()
{struct svm_node **_node = Malloc(struct svm_node*, 4);//分配4個空間存放4個人信息x_space = Malloc(svm_node, 3);//男1:身高:190cm,體重:70kg;x_space[0].index = 1;x_space[0].value = 190;x_space[1].index = 2;x_space[1].value = 70;x_space[2].index = -1; //x_space[2].value = NULL_node[0] = x_space;x_space = Malloc(svm_node, 3); //男2:身高:180cm,體重:80kg;x_space[0].index = 1;x_space[0].value = 180;x_space[1].index = 2;x_space[1].value = 80;x_space[2].index = -1;//x_space[2].value = NULL_node[1] = x_space;x_space = Malloc(svm_node, 3); //女1:身高:161cm,體重:80kg;x_space[0].index = 1;x_space[0].value = 161;x_space[1].index = 2;x_space[1].value = 45;x_space[2].index = -1;//x_space[2].value = NULL_node[2] = x_space;x_space = Malloc(svm_node, 3); //女2:身高:161cm,體重:47kg;x_space[0].index = 1;x_space[0].value = 163;x_space[1].index = 2;x_space[1].value = 47;x_space[2].index = -1;//x_space[2].value = NULL_node[3] = x_space;double *y1 = Malloc(double, 4); y1[0] = -1;y1[1] = -1;y1[2] = 1;y1[3] = 1;prob.l = 4;prob.x = _node;prob.y = y1;
}
成員函數二:訓練樣本數據,得出模型
void SVMExample::analysisData()
{const char *error_msg;error_msg = svm_check_parameter(&prob,¶m);if(error_msg){fprintf(stderr, "\nerror:%s\n", error_msg);exit(1);}//如果有必要可以進行交叉性檢驗/*if(cross_validation){do_cross_validation();}*/model = svm_train(&prob, ¶m);
}
成員函數三:預測數據
預測數據1:身高180cm,體重85kg;
預測數據2:身高161cm,體重50kg;
void SVMExample::displayResult()
{//進行預報struct svm_node *node1 = Malloc(svm_node, 3);node1[0].index = 1;node1[0].value = 180;node1[1].index = 2;node1[1].value = 85;node1[2].index = -1;double r1 = svm_predict(model, node1);printf("預測值r1:%f\n", r1);free(node1);struct svm_node *node2 = Malloc(svm_node, 3);node2[0].index = 1;node2[0].value = 161;node2[1].index = 2;node2[1].value = 50;node2[2].index = -1;double r2 = svm_predict(model, node2);printf("預測值r2:%f\n", r2);free(node2);
}
預測結果
得出分類結果:預測樣本1的輸出為-1(男),預測樣本2的輸出為1(女)。如果有需要的話請聯系:ikuler@http://www.doczj.com/doc/517f7fa1f524ccbff121846b.html