数据挖掘实验:决策树算法实现C++

决策树算法看起来很好玩(我没开玩笑我真的这么觉得),就是简单的树上走然后得到不同的结果,一开始我很纳闷,书上那些东西都是啥,什么信息增益,ID3,C4.5,都是什么玩意(不好好听课的后果),后来仔仔细细的把书看了三遍,终于明白是干嘛的了。其实是根据给出的数据,判断不同属性对于决策的贡献,然后获得这棵树的分支。理解之后实现起来就容易一些了,实现的时候也借鉴了别人的代码,研究透了之后自己写的,同时也做了一些改动,数组没有用指针(我不喜欢指针),用的数组+下标寻址。然后,这代码你要是让我再写一遍我告诉你,


我肯定写不出来。


当时写了有六七个小时呢(还是弄懂了别人代码的前提下,光看书实在不懂到底想干嘛)。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 10005;

struct P {
    string name;
    string val;
    int id;
    vector son;
    P():id(-1){}
}Tree[maxn];

int n;///元组数
int m;///数据条数
int tot;///节点总数
int root;///根节点id
vector > dataset;///所有数据
vector col_name;///列名
map > Map;///存储属性对应的值
int nump[10];///用于标号
///判断是否是同一类
bool All(vector > D, string kind){
    for(int i = 0;i < D.size();i ++)
        if(D[i][n - 1] != kind) return false;
    return true;
}
///取多数类的属性
string Most(vector > D){
    int num = 0;
    for(int i = 0;i < D.size();i ++)
        if(D[i][n - 1] == "yes") num ++;
    return (num > D.size() - num)?"yes":"no";
}
///计算Info
double Cal_Info(vector  > D, string attribute, string value,bool first){
    int t1 = 0, t2 = 0;
    bool flag = false;
    for(int j = 0; j < n; j ++){
        if(flag) break;
        if(col_name[j] == attribute){
            for(int i = 0; i < D.size(); i++)
                if((!first&&D[i][j] == value) || first){
                    if(D[i][n - 1] == "yes") t1++;
                    else t2++;
                }
            flag = true;
        }
    }
    ///属于同一类
    if(t1 == 0 || t2 == 0 ) return 0;
    double sum = t1 + t2;
    double ans = -t1/sum*log(t1/sum)/log(2.0) - t2/sum*log(t2/sum)/log(2.0);
    return ans;
}
///计算信息增益
double Cal_Gain(vector  > D, string attribute){
    double Info = Cal_Info(D, attribute, "", true);
    double InfoA = 0;
    vector v = Map[attribute];
    vector ans;
    vector vv;
    int t1;
    for(int i = 0; i < v.size(); i++){
        t1 = 0;
        for(int k = 0; k < n - 1; k++)
            if(col_name[k] == attribute){
                for(int j = 0; j < D.size(); j++)
                    if(D[j][k] == v[i])
                        t1 ++;
            }
        vv.push_back(t1);
    }
    for(int i = 0; i < v.size();i ++)
        ans.push_back(1.0 * vv[i] / (D.size()));
    double temp;
    for(int i = 0; i < v.size();i ++){
        temp = Cal_Info(D, attribute, v[i], false);
        InfoA += ans[i] * temp;
    }
    return (Info - InfoA);
}
///建树过程
int Generate_decision_tree(int pos, vector > D, vector  attribute_list){
    if(Tree[pos].id == -1) Tree[pos].id = pos;
    ///所有数据结果都是yes
    if(All(D, "yes")){
        Tree[pos].name = "yes";
        return pos;
    }///所有数据结果都是no
    else if(All(D, "no")){
        Tree[pos].name = "no";
        return pos;
    }
    ///属性判断完毕仍不能分开,取多数
    if(attribute_list.size() == 0){
        Tree[pos].name = Most(D);
        return pos;
    }
    ///计算最大增益
    double maxg = -1;
    int maxpos = 0;
    for(int i = 0;i < attribute_list.size();i ++){
        double curg = Cal_Gain(D, attribute_list[i]);
        if(curg > maxg){
            maxg = curg;
            maxpos = i;
        }
    }
    ///根据最大增益对应的属性进行划分
    Tree[pos].name = attribute_list[maxpos];
    ///获得属性对应的所有值
    vector v = Map[attribute_list[maxpos]];
    int p;
    for(p = 0;p < n;p ++)
    if(col_name[p] == attribute_list[maxpos])
        break;
    vector tempatt;
    vector > tempD;
    for(int i = 0;i < attribute_list.size();i ++)
        if(i != maxpos) tempatt.push_back(attribute_list[i]);
    for(int i = 0;i < v.size();i ++){
        for(int j = 0;j < D.size();j ++)
            if(D[j][p] == v[i])
                tempD.push_back(D[j]);
        int curnum = ++ tot ;
        Tree[curnum].val = v[i];
        if(tempD.size() == 0) Tree[curnum].name = Most(D);
        else Generate_decision_tree(curnum, tempD, tempatt);
        Tree[pos].son.push_back(curnum);
        tempD.clear();
    }
    return pos;
}
///遍历
void show(int id, int dep){
    for(int i = 0;i < dep;i ++) cout<<"   ";
    if(Tree[id].val != ""){
        dep ++;
        cout<<++ nump[dep]<<"."< data;
    cin >> n >> m;
    for(int i = 0;i < n;i ++)
        cin >> t, col_name.push_back(t);
    for(int i = 0;i < m;i ++){
        data.clear();
        for(int j = 0;j < n;j ++){
            cin >> t;
            data.push_back(t);
        }
        dataset.push_back(data);
    }
    ///获得每个属性对应的值
    vector vt;
    set ss;
    for(int i = 0;i < n - 1;i ++){
        vt.clear();
        ss.clear();
        for(int j = 0;j < m;j ++)
            if(!ss.count(dataset[j][i])){
                ss.insert(dataset[j][i]);
                vt.push_back(dataset[j][i]);
            }
        Map[col_name[i]] = vt;
    }
    vt = col_name;
    vt.erase(vt.end() - 1);
    root = Generate_decision_tree(0, dataset, vt);
    show(root,0);
    return 0;
}

然后输入数据的话我就不附了,就是列数 记录条数,酱,主题的递归算法,过程跟书上是一样的。哦对了,我的书是机械工业出版社的数据挖掘,黑色大理石纹,我觉得还不错。起码我从书上还真学到了点啥(虽然后期忙着复习没有好好听课)。



你可能感兴趣的:(经验总结)