原文:http://blog.csdn.net/u014691453/article/details/40393137
軟件版本:
Visual Studio版本:VS2012
(注:使用方法在 VS2010 上面親測同樣可用,只是可能會出現的問題是: VS2010 和 VS2012 之間有些函數寫法不同,需在編譯前做改動,譬如 VS2010 的 scanf 對比 VS2012 的 scanf_s )
libsvm版本:libsvm-3.18
聲明:
如果你找到了我這篇標題的文章,那很大程度上意味着你一定是在 VS 里或者 MFC 里使用 libsvm 工具箱出現了問題。那你也一定知道了,libsvm 在VS工程里的使用與它在 matlab 或者是 python 里面的使用,是多么的不同。
致謝:
如果沒有 gg 百分之百的幫助,就憑我在 VS 里編程的菜鳥能力,是絕對不可能1天就搞好的,我絕對會弄半年不止
所以非常感謝非常感謝,今后我一定認真學習編程。
正文:
分三部分:第一部分:先把 VS 工程的框架建好
第二部分:工程里包含主函數的 cpp 文件要怎么寫
第三部分:把 libsvm 工具箱移植到 MFC 中進行使用
第四部分:在本文代碼中能夠正確運行的數據格式
資源地址:如何在Visual Studio(VS)里使用libsvm工具箱(與博文相關的代碼包)
第一部分:先把 VS 工程的框架建好
對於java、matlab、python、windows 都有相對應的文件夾,文件夾里面的內容和上圖中的這個 readme 就可以幫助你在以上四種情況下使用了。
那在 VS 里該怎么使用呢?
首先,我們先建立一個Win32控制台項目,起名為 MM ,如下步驟:



然后,把 libsvm 文件夾里的這幾個文件(如下圖),都拷貝到 MM 項目的文件夾(如下下圖)里去,以備后續使用。


然后,在 MM 項目里,我們把 svm.h 和 svm.cpp 分別添加到頭文件和源文件里面去,如下圖:

然后,在源文件里,右鍵——新建項:MM.cpp
接下來是第二部分
第二部分:工程里包含主函數的 cpp 文件要怎么寫
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <list>
- #include <fstream>
- #include <iostream>
- #include "svm.h"
- using namespace std;
接下來的內容大致分五部分:
第一:讀入訓練數據和測試數據
- #define XLEN 10 //生產測試數據,這個感覺就是無用的地方
- #define YLEN 10
- ofstream outdata; //需要准備的所有數據的標簽label和特征feature都是分開的,而且特征feature前面不需要加序號冒號這種東西,只需用空格隔開就好
- ifstream indata; //所以這里indata只包含特征,indata_label只包含label,每一行是一個樣本的。
- ofstream outdata_lable;
- ifstream indata_lable;
- int NUM = 1440; //由於我的樣本特征是 1440 維,所以讀數據的時候,我定義了個數,你可以根據自己特征的維度對 NUM 進行更改。
- //char default_param[] = "-t 2 -c 100"; // 這個是 svm_toy.cpp 里對參數的選擇
- char default_param[] = "-t 2 -c 4 -g 32"; // 這個是匹配我數據的參數
- struct point { //這個是后面 svm_train 拿來數據做訓練時候的數據傳入方式
- double *feature;
- //signed char value;
- int value;
- };
- list<point> point_list; // 通過 indata 讀進來的數據就放在 point_list 里面
- int current_value = 1; // 路人甲變量
- void clear_all() // 清空鏈表
- {
- point_list.clear();
- }
然后,我們先讀入訓練數據,用來訓練模型
- void readFile1(char *file,char *file_lable) //定義讀入訓練數據的函數叫做 readFile1
- {
- indata.open(file,ios::in); //讀入特征
- indata_lable.open(file_lable,ios::in); // 讀入標簽
- cout <<"read data begin"<<endl; // 屏顯
- clear_all();
- while(!indata.eof()) // 如果沒有讀到文件結束,就繼續讀,知道讀完整個 traindata 文件
- {
- double *line = new double[NUM];
- for(int i =0;i<NUM;i++)
- {
- indata >> line[i]; //把特征存起來
- }
- point p;
- indata_lable >>p.value; //把label存起來
- p.feature = line;
- point_list.push_back(p);
- }
- point_list.pop_back(); //如果你的 traindata.txt 文件數據的最后有一個空格的話,需要加上這句話,否則預測會有錯如果沒有空格,這句話就不需要了
- indata.close();
- indata_lable.close();
- cout <<"read data end"<<endl;
- }
接下來,讀入測試數據:
- void readFile2(char *file,char *file_lable) // 讀入測試文件的函數叫做 readFile2
- {
- indata.open(file,ios::in); //接下來代碼和上面讀訓練數據是一個樣子的
- indata_lable.open(file_lable,ios::in); // <span style="font-family: Arial, Helvetica, sans-serif;">由於讀訓練數據之后就會建立model,然后才會讀測試數據,所以不用擔心會有數據覆蓋的問題</span>
- cout <<"read test data begin"<<endl;
- clear_all();
- while(!indata.eof())
- {
- double *line = new double[NUM];
- for(int i =0;i<NUM;i++)
- {
- indata >> line[i];
- }
- point p;
- indata_lable >>p.value;
- p.feature = line;
- point_list.push_back(p);
- }
- point_list.pop_back();
- cout <<"read test data end size = "<<point_list.size()<<endl;
- indata.close();
- indata_lable.close();
- }
第二:構建參數 param 的結構體
第三:構建分類問題 prob 的結構體
第四:主函數如下
- int main()
- {
- int choice;
- cout<<"1 train model\n2 test1\n3 test2\n"<<endl;
- cin >>choice;
- switch(choice)
- {
- case 1:
- {
- readFile1("traindata.txt","trainlabel.txt"); //選擇1 是訓練模型,模型會保存為“model.txt”
- run();
- break;
- }
- case 2:
- {
- readFile2("1.txt","1_label.txt"); // 選擇2 是用第一份測試數據進行測試
- testData();
- break;
- }
- case 3:
- {
- readFile2("11.txt","11_label.txt"); // 選擇3 是用第二份測試數據進行測試
- testData();
- break;
- }
- }
- system("pause");
- return 0;
- }
第五:結果展示
