C++机器学习(3)朴素贝叶斯

部分资料下载地址: http://pan.baidu.com/s/1bpsgt5t 提取码fwxf
源码下载地址:https://github.com/fawdlstty/hm_ML

朴素贝叶斯这东西呢,主要用于文本相关处理,比如通过邮件内容判断是否是垃圾邮件等等。
具体实现思路是:比如判断某个邮件的内容是否是垃圾邮件,那么弄两个文本向量,分别代表正常邮件的关键字与垃圾邮件关键字,然后计算哪边关键字出现的多就按次数多的定义。比如正常邮件关键字有3个,垃圾邮件关键字有20个,那么这邮件是垃圾邮件的概率大于这是正常邮件的概率,那就定义这邮件为垃圾邮件。
这个对于英文来说非常容易实现,但对于中文来说就不是那么回事了,因为中华汉字博大精深嘛,关键字非常不好找,算法的学习也是一件非常耗时的工作。所以这儿呢,我就简单实现一个类似的东西吧,我将实现,判断一句话的情感状态。
首先是分词,我选择friso;然后是情感词库,我找的一个网上的情感词汇本体库。这些东西在上面的源代码下载里面已经包括了。

接下来是实现。首先,基于C语言的friso的引用,是一件坑爹的事情:

1
2
3
4
5
6
7
8
#ifdef __cplusplus
extern "C" {
#endif
#include "friso/friso.h"
#ifdef __cplusplus
}
#endif
#pragma comment(lib, "friso/friso.lib")

接下来是朴素贝叶斯的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Bayes : public Feature_Object_Collection {
public:
    Bayes (std::initializer_list<Feature_Object> list) : Feature_Object_Collection (list) {}
 
    Bayes (Feature_Object_Collection& o) : Feature_Object_Collection (o) {}
 
    Bayes (const Bayes &o) : Feature_Object_Collection (o) {}
 
    Bayes () : Feature_Object_Collection () {
        std::ifstream ifs ("words/words_gbk.csv");
        std::string tmp_str;
        std::vector<std::string> v;
        std::getline (ifs, tmp_str);
        while (std::getline (ifs, tmp_str)) {
            if (tmp_str.length () > 0) {
                v.clear ();
                hTools::str::split (tmp_str, v, ',');
                Feature_Object fo (v [0]);
                auto p = m_map.lower_bound (v [4]);
                if (p != m_map.upper_bound (v [4])) {
                    fo << p->second;
                    fo << std::stoi (v [5]);
                    add_feature (fo);
                }
            }
        }
        ifs.close ();
    }
 
    std::string calc (std::string &doc) {
        ptrdiff_t feel_size = m_map2.size ();
        ptrdiff_t *feel = new ptrdiff_t [feel_size];
        ::memset (feel, 0, sizeof (ptrdiff_t)*feel_size);
 
        friso_t friso = ::friso_new ();
        friso_config_t config = ::friso_new_config ();
        if (1 != ::friso_init_from_ifile (friso, config, "friso/friso.ini")) {
            return "加载friso配置文件失败!";
        }
        friso_task_t task = ::friso_new_task ();
        ::friso_set_text (task, &doc [0]);
        ptrdiff_t size = get_size (), index;
        std::string word;
        while (::friso_next (friso, config, task) != NULL) {
            word = task->hits->word;
            for (index = 0; index < size; ++index)
                if (data [index].get_label () == word) break;
            if (index != size)
                feel [(ptrdiff_t) (data [index]) [0]] += (ptrdiff_t) (data [index]) [1];
        }
        ::friso_free_task (task);
        //friso_free_config (config);
        ::friso_free (friso);
 
        for (index = 0, size = 0; index < feel_size; ++index)
            if (feel [index] > feel [size]) size = index;
        if (0 == feel [size]) {
            word = "未知";
        } else {
            word = m_map2 [size];
        }
 
        delete[] feel;
        return word;
    }
 
protected:
    static std::map<std::string, int> m_map;
    static std::map<int, std::string> m_map2;
};

以及静态变量的定义

1
2
std::map<std::string, int> FawLearn::Bayes::m_map ({ { "PA", 0 }, { "PE", 1 }, { "PD", 2 }, { "PH", 3 }, { "PG", 4 }, { "PB", 5 }, { "PK", 6 }, { "NA", 7 }, { "NB", 8 }, { "NJ", 9 }, { "NH", 10 }, { "PF", 11 }, { "NI", 12 }, { "NC", 13 }, { "NG", 14 }, { "NE", 15 }, { "ND", 16 }, { "NN", 17 }, { "NK", 18 }, { "NL", 19 }, { "PC", 20 } });
std::map<int, std::string> FawLearn::Bayes::m_map2 ({ { 0, "快乐" }, { 1, "安心" }, { 2, "尊敬" }, { 3, "赞扬" }, { 4, "相信" }, { 5, "喜爱" }, { 6, "祝愿" }, { 7, "愤怒" }, { 8, "悲伤" }, { 9, "失望" }, { 10, "疚" }, { 11, "思" }, { 12, "慌" }, { 13, "恐惧" }, { 14, "羞" }, { 15, "烦闷" }, { 16, "憎恶" }, { 17, "贬责" }, { 18, "妒忌" }, { 19, "怀疑" }, { 20, "惊奇" } });

稍微解释下。Bayes()构造函数,用于加载情感词汇库文件,这文件里面也有,注意路径。
接下来,这个情感词汇库里面对每个情感词汇均加入了“权”值,这意味着更方便我们的实现。具体参考压缩包里面的压缩包的里面的文档。
还有就是friso.ini这配置文件里面的有个路径,必须要是绝对路径,并且路径中不能出现空格,否则运行之后会给你警告。(这儿的警告基本代表这次运行注定失败)。
然后静态变量的定义,这个定义是我根据文档写的。
最后,我这个实现并不科学,科学的做法是通过map来存储情感词汇,但我这儿为了方便,直接用之前实现的vector就存放了。后来的各路大神就别学我偷懒了。
噢对了,这次的代码调用了我之前的一个字符串处理库,详情请见C++中std::string实现trim、format等函数
以上代码告一段落,还剩调用了。调用就简单了,比如如下代码:

1
2
3
4
5
6
7
int main(int argc, char* argv[]) {
    Bayes b;
    string s = b.calc (string ("那个女孩真漂亮"));
    cout << "目标文字语义状态:" << s << endl;
 
    return 0;
}

以上代码运行结果为这样:
20160429185129
对这个感兴趣的朋友们可以试着加入学习功能,通过对垃圾邮件或者脏话关键字的学习,就可以实现过滤垃圾邮件、脏话过滤算法了。

Published by

fawdlstty

又一只萌萌哒程序猿~~

One thought on “C++机器学习(3)朴素贝叶斯”

未来机器女仆进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注