1. 程式人生 > >機器學習基石 (Machine Learning Foundations) 作業1 Q15-17的C++實現

機器學習基石 (Machine Learning Foundations) 作業1 Q15-17的C++實現

大家好,我是Mac Jiang。今天和大家分享Coursera-臺灣大學-機器學習基石 (Machine Learning Foundations) -作業1的Q15-17題的C++實現。這部分作業的任務主要是寫一個PLA分類器,用於解決一個4維資料的分類問題。我的程式碼也許能較好的執行PLA演算法,但它不一定是最好最快的實現過程,如果各位博友有更好的思路,請留言聯絡,謝謝!希望我的部落格能給您帶來一些學習上的幫助!
其他解答請看彙總帖:http://blog.csdn.net/a1015553840/article/details/51085129

PLA是一種十分簡單,快速的分類演算法,有速度快、實現簡單的特點,特別適用於樣本是線性可分的情況。對於線性可分的樣本,PLA的實現過程為:
{
1.尋找w(t)的下一個錯誤分類點(x,y)(即sign(w(t)’*x)!=y);
2.糾正錯誤:w(t+1) = w(t) + y*x;
}until(每個樣本都無錯)

#include<fstream>
#include<iostream>
#include<vector>
using namespace std;

#define DEMENSION 5

double weight[DEMENSION];//權重值
int step = 0;//修改次數
int n = 0;//訓練樣本數
char *file = "training_data.txt";//讀取檔名

//儲存訓練樣本,input為x,output為y
struct record{
    double input[DEMENSION];
    int output;
};

//把記錄存在向量裡而不是存在結構體陣列內,這樣可以根據實際一項項新增
vector<record> trainingSet; //將資料讀入訓練樣本向量中 void getData(ifstream &datafile) { while(!datafile.eof()) { record curRecord; curRecord.input[0] = 1; int i; for(i = 1; i < DEMENSION; i++){ datafile>>curRecord.input[i]; } datafile>>curRecord.output; trainingSet.push_back(curRecord); } datafile.close(); n = trainingSet.size(); } //計算sign值
int sign(double x){ if(x <= 0)return -1; else return 1; } //兩向量相加(實際為陣列相加),將結果儲存在第一個陣列內,用於計算w(i+1)=w(i)+y*x void add(double *v1,double *v2,int demension){ int i; for(i = 0;i < demension; i++)v1[i] += v2[i]; } //計算兩數值相乘值,用於判斷w*x是否小於0,若小於0要執行修正演算法 double multiply(double *v1,double *v2,int demension){ double temp = 0.0; int i; for(i = 0; i < demension; i++)temp += v1[i] * v2[i]; return temp; } //計算實數num與向量乘積放在result中,用於計算y*x void multiply(double *result,double *v,int demension,int num){ int i; for(i = 0; i < demension; i++)result[i] = num * v[i]; } void PLA() { int correctNum = 0;//當前連續正確樣本數,當等於n則表明輪完一圈,則表示全部正確,演算法結束 int index = 0;//當前正在計算第幾個樣本 bool isFinished = 0;//演算法是否全部完成的表示,=1表示演算法結束 while(!isFinished){ if(trainingSet[index].output == sign(multiply(weight,trainingSet[index].input,DEMENSION)))correctNum++;//當前樣本無錯,連續正確樣本數+1 else{//出錯,執行修正演算法 double temp[DEMENSION]; multiply(temp,trainingSet[index].input,DEMENSION,trainingSet[index].output);//計算y*x add(weight,temp,DEMENSION);//計算w(i+1)=w(i)+y*x step++;//進行一次修正,修正次數+1 correctNum = 0;//由於出錯了,連續正確樣本數歸0 cout<<"step"<<step<<":"<<endl<<"index="<<index<<" is wrong"<<endl; } if(index == n-1)index = 0; else index++; if(correctNum == n)isFinished = 1; } cout<<"total step:"<<step<<endl; } void main() { ifstream dataFile(file); if(dataFile.is_open()){ getData(dataFile); } else{ cout<<"出錯,檔案開啟失敗!"<<endl; exit(1); } int i; for(i = 0; i < DEMENSION; i++)weight[i] = 0.0; PLA(); }

(3)實驗結果:
這裡寫圖片描述
45次

2.第16題
這裡寫圖片描述
(1)題意:由於樣本的排列順序不同,最終完成PLA分類的迭代次數也不同。這道題要求我們打亂訓練樣本的順序,進行2000次PLA計算,得到平均迭代次數。
在C++中自帶打亂順序的演算法:random_shuffle函式,在呼叫之前,需要#include
(2)實現:

#include<fstream>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

#define DEMENSION 5

double weight[DEMENSION];//權重值
int step = 0;//修改次數
int totalStep = 0;
int n = 0;//訓練樣本數
char *file = "training_data.txt";//讀取檔名

//儲存訓練樣本,input為x,output為y
struct record{
    double input[DEMENSION];
    int output;
};

//把記錄存在向量裡而不是存在結構體陣列內,這樣可以根據實際一項項新增
vector<record> trainingSet;

//將資料讀入訓練樣本向量中
void getData(ifstream &datafile)
{
    while(!datafile.eof())
    {
        record curRecord;
        curRecord.input[0] = 1;
        int i;
        for(i = 1; i < DEMENSION; i++){
            datafile>>curRecord.input[i];
        }
        datafile>>curRecord.output;
        trainingSet.push_back(curRecord);
    }
    datafile.close();
    n = trainingSet.size(); 
}

//計算sign值
int sign(double x){
    if(x <= 0)return -1;
    else return 1;
}

//兩向量相加(實際為陣列相加),將結果儲存在第一個陣列內,用於計算w(i+1)=w(i)+y*x
void add(double *v1,double *v2,int demension){
    int i;
    for(i = 0;i < demension; i++)v1[i] += v2[i];
}

//計算兩數值相乘值,用於判斷w*x是否小於0,若小於0要執行修正演算法
double multiply(double *v1,double *v2,int demension){
    double temp = 0.0;
    int i;
    for(i = 0; i < demension; i++)temp += v1[i] * v2[i];
    return temp;
}

//計算實數num與向量乘積放在result中,用於計算y*x
void multiply(double *result,double *v,int demension,double num){
    int i;
    for(i = 0; i < demension; i++)result[i] =  num * v[i];
}

void PLA()
{
    int correctNum = 0;//當前連續正確樣本數,當等於n則表明輪完一圈,則表示全部正確,演算法結束
    int index = 0;//當前正在計算第幾個樣本
    bool isFinished = 0;//演算法是否全部完成的表示,=1表示演算法結束
    while(!isFinished){
        if(trainingSet[index].output == sign(multiply(weight,trainingSet[index].input,DEMENSION)))correctNum++;//當前樣本無錯,連續正確樣本數+1
        else{//出錯,執行修正演算法
            double temp[DEMENSION];
            multiply(temp,trainingSet[index].input,DEMENSION,trainingSet[index].output);//計算y*x
            add(weight,temp,DEMENSION);//計算w(i+1)=w(i)+y*x
            step++;//進行一次修正,修正次數+1
            correctNum = 0;//由於出錯了,連續正確樣本數歸0
            //cout<<"step"<<step<<":"<<endl<<"index="<<index<<" is wrong"<<endl;
        }
        if(index == n-1)index = 0;
        else index++;
        if(correctNum == n)isFinished = 1;
    }
}

void main()
{
    ifstream dataFile(file);
    if(dataFile.is_open()){
         getData(dataFile);
     }
     else{
         cout<<"出錯,檔案開啟失敗!"<<endl;
         exit(1);
     }
    int i;
    for(i = 0; i < 2000; i++)
    {
      random_shuffle(trainingSet.begin(), trainingSet.end());
      int j;
      for(j = 0; j < DEMENSION; j++)weight[j] = 0.0;
      PLA();
      totalStep += step;
      cout<<"第"<<i<<"次迭代的step:"<<step<<endl;
      step = 0;
    }
    cout<<"average step:"<<totalStep/2000<<endl;
}

(3)實驗結果:
這裡寫圖片描述
平均40次

3.第17題
這裡寫圖片描述
這道題實現更加簡單,只要在num之前*0.5就可以了

void multiply(double *result,double *v,int demension,double num){
    int i;
    for(i = 0; i < demension; i++)result[i] =  num * v[i];
}

大約為40次