美文网首页
JS简单实现朴素贝叶斯分类器

JS简单实现朴素贝叶斯分类器

作者: 关爱单身狗成长协会 | 来源:发表于2018-01-08 14:37 被阅读331次

    推荐阅读:带你搞懂朴素贝叶斯分类算法

    首先放代码

    function NB(data) {
        this.fc = {}; //记录特征的数量 feature conut 例如 {a:{yes:5,no:2},b:{yes:1,no:6}}
        this.cc = {}; //记录分类的数量 category conut 例如 {yes:6,no:8} 
    }
    NB.prototype = {
        infc(w, cls) { //插入新特征值
            if (!this.fc[w]) this.fc[w] = {};
            if (!this.fc[w][cls]) this.fc[w][cls] = 0;
            this.fc[w][cls] += 1;
        },
        incc(cls) { //插入新分类
            if (!this.cc[cls]) this.cc[cls] = 0;
            this.cc[cls] += 1;
        },
        allco() { //计算分类总数 all count
            var t = 0;
            for (var k in this.cc) t += this.cc[k];
            return t;
        },
        fprob(w, ct) { //特征标识概率   
            if (Object.keys(this.fc).indexOf(w) >= 0) {
                if (Object.keys(this.fc[w]).indexOf(ct) < 0) {
                    this.fc[w][ct] = 0
                }
                var c = parseFloat(this.fc[w][ct]);
                return c / this.cc[ct];
            } else {
                return 0.0;
            }
        },
        cprob(c) { //分类概率
            return parseFloat(this.cc[c] / this.allco());
        },
        train(data, cls) { //参数:学习的Array,标识类型(Yes|No)
            for (var w of data) this.infc(String(w), cls);
            this.incc(cls);
        },
        test(data) {
            var ccp = {}; //P(类别)
            var fccp = {}; //P(特征|类别)
            for (var k in this.cc) ccp[k] = this.cprob(k);
            for (var i of data) {
                i = String(i);
                if (!i) continue;
                if (Object.keys(this.fc).indexOf(i)) {
                    for (var k in ccp) {
                        if (!fccp[k]) fccp[k] = 1;
                        fccp[k] *= this.fprob(i, k); //P(特征1|类别1)*P(特征2|类别1)*P(特征3|类别1)...
                    }
                }
            }
            var tmpk = "";
            for (var k in ccp) {
                ccp[k] = ccp[k] * fccp[k];
                if (!tmpk) tmpk = k;
                if (ccp[k] > ccp[tmpk]) tmpk = k;
            }
            return tmpk;
        }
    };
    

    1.学习(train)功能

    学习功能非常简单,只是将学习的数据进行统计
    代码实现你可以查看代码中的train函数

    假设,某个医院早上收了六个门诊病人:

    症状 职业 疾病
    打喷嚏 护士 感冒
    打喷嚏 农夫 过敏
    头痛 建筑工人 脑震荡
    头痛 建筑工人 感冒
    打喷嚏 教师 感冒
    头痛 教师 脑震荡

    我们先统计记录这些信息数据:

    var nb = new NB();
    var data=[
                   {d:["打喷嚏","护士"],c:"感冒"},
                   {d:["打喷嚏","农夫"],c:"过敏"},
                   {d:["头痛","建筑工人"],c:"脑震荡"},
                   {d:["头痛","建筑工人"],c:"感冒"},
                   {d:["打喷嚏","教师"],c:"感冒"},
                   {d:["头痛","教师"],c:"脑震荡"},
    ];
     for(var i of data){
        nb.train(i.d, i.c);
    }
    

    统计结果:


    2.预测(test)功能

    预测功能就要用到朴素贝叶斯算法

    首先来看,贝叶斯公式:

    可能你看不懂公式或看懂公式不知道公式怎么用
    那我来简单的翻译一下:

    P( Category |Feature) = P ( Feature | Category ) * P( Category)/ P(Feature) 
    

    其实也是就是:

    P(类别|特征)=P(特征|类别)*P(类别)/p(特征)
    

    所以我们只要计算以下数据即可:

    P(特征|类别)
    P(类别)
    p(特征)
    

    假设两个类别,分别是类别1,与类别2
    那么类别总次数就是两个类别出现次数总和
    加上可能我们输入的特征有多个假设就3个把那么也简单:

    P((特征1、特征2、特征3)|类别1)= P(特征1|类别1)*P(特征2|类别1)*P(特征3|类别1) 
    P(类别1)=类别1的次数/(类别总数)
    P(特征1、特征2、特征3)=P(特征1)*P(特征2)*P(特征3) 
    

    因为根据公式我们知道:

    P(类别1|特征)=P(特征|类别1)*P(类别1)/p(特征)
    P(类别2|特征)=P(特征|类别2)*P(类别2)/p(特征)
    

    刚好p(特征)为分母所以如果比较P(类别1|特征)P(类别2|特征)的概率
    只要比较P(特征|类别1)*P(类别1)P(特征|类别2)*P(类别2)的大小就行了

    代码实现查看代码部分的test函数

    3.测试数据

    在已经学习了
    我们预测一下打喷嚏的建筑工人是生了什么病

    console.log(nb.test(["打喷嚏","建筑工人"]));
    
    结果是感冒

    预测性别示例:

    性别 身高(英尺) 体重(磅) 脚掌(英寸)
    6 180 12
    5.92 190 11
    5.58 170 12
    5.92 165 10
    6 165 10
    5.72 164 9
    5 100 6
    5.5 150 8
    5.42 130 7
    5.75 150 9
    var nb = new NB();
    nb.train([6, 180, 12], "男");
    nb.train([5.92, 190, 11], "男");
    nb.train([5.58, 170, 12], "男");
    nb.train([5.72, 164, 9], "男");
    nb.train([6, 165, 10], "男");
    nb.train([5.92, 165, 10], "男");
    nb.train([5, 100, 6], "女");
    nb.train([5.5, 150, 8], "女");
    nb.train([5.42, 130, 7], "女");
    nb.train([5.75, 150, 9], "女");
    console.log(nb.test([6, 180, 11]));
    

    中文脏话测试

    function defaultTokenizer(text) {
        // 仅保留英文、中文、数字
        var rgxPunctuation = /[^(a-zA-ZA-Яa-я\u4e00-\u9fa50-9_)+\s]/g;
        // 英文以空格分词,中文不分词,以单个字为单位
        return text.replace(rgxPunctuation, ' ').replace(/[\u4e00-\u9fa5]/g, function(word) {
            return word + ' ';
        }).split(/\s+/);
    };
    // 中文测试
    nb.train(defaultTokenizer('我的名字叫司马萌.'), '正常')
    nb.train(defaultTokenizer('没什么,就是一道测试程序!!'), '正常')
    nb.train(defaultTokenizer('不要皱眉,即使在伤心的时刻,因为你从不知道有谁会醉心于你的笑容。'), '正常')
    nb.train(defaultTokenizer('去只是一种姿势,得到并不等同于幸福。'), '正常')
    nb.train(defaultTokenizer('理和美女都是赤裸裸的。'), '正常')
    nb.train(defaultTokenizer('们看错了这个世界,却说世界欺骗了我们。'), '正常')
    nb.train(defaultTokenizer('们人这一辈子不是别人的楷模,就是别人的借鉴。'), '正常')
    nb.train(defaultTokenizer('万别说直到永远,因为你压根不知道永远有多远。'), '正常')
    nb.train(defaultTokenizer('些无法复制的浪漫,只能在回忆里慢慢变淡。'), '正常')
    nb.train(defaultTokenizer('调是永恒的美德,缺心眼的话就要学会沉默。'), '正常')
    nb.train(defaultTokenizer('用什么优势赢得人生,就会用同样的原因输掉人生。'), '正常')
    nb.train(defaultTokenizer('人最可悲的是,有自由的思想,却没有冲破羁绊的勇气。'), '正常')
    nb.train(defaultTokenizer('爱情就像俩个拉着橡皮筋的人,受伤的总是不愿意放手的那一个。'), '正常')
    nb.train(defaultTokenizer('人生的经历就像铅笔一样…开始很尖…经历的多了也就变得圆滑了…如果承受不了就会断了。'), '正常')
    nb.train(defaultTokenizer('在你往上爬的时候,一定要保持梯子的整洁,否则你下来时可能会滑倒。'), '正常')
    nb.train(defaultTokenizer('人生是没有穷尽的,所以也就没有什么所谓的归宿。'), '正常')
    nb.train(defaultTokenizer('幸福是因为你看到别人的不幸,不幸是因为你只看到别人的幸福。'), '正常')
    nb.train(defaultTokenizer('我们的安全感,来自于充分体验不安全感。'), '正常')
    nb.train(defaultTokenizer('男人最大的武器是眼神,女人最大的武器是眼泪。'), '正常')
    nb.train(defaultTokenizer('心清如水即是佛,了无牵挂佛无边。'), '正常')
    nb.train(defaultTokenizer('人活着为了什么?答案:一个念想。'), '正常')
    nb.train(defaultTokenizer('有些事遇见了就无法放手,有些事放开了手就不必再回首。'), '正常')
    nb.train(defaultTokenizer('我操,你他妈咋回事!!'), '脏话')
    nb.train(defaultTokenizer('你他妈整个脑残了,不惜拿自己的父母家人来骗别人的精液。!!'), '脏话')
    nb.train(defaultTokenizer('跟一个你视为他为狗的人将素质,你真心逗B,脑子也秀逗了吧!'), '脏话')
    nb.train(defaultTokenizer('贱人的生活方式就是,只许自己吃屎,不许别人放屁。'), '脏话')
    nb.train(defaultTokenizer('你爹有点多,我忍不住笑了下,不好意思啊,你不要去想你那悲伤的母亲。'), '脏话')
    nb.train(defaultTokenizer('我们骂不骂关你个婊子什么事,草你吗的瞎眼白内胀!'), '脏话')
    nb.train(defaultTokenizer('你他妈那么喜欢被人擦,我想说我退出我不喜欢兽交。'), '脏话')
    nb.train(defaultTokenizer('我只是你祖宗而已,你怎么可以这样,你个傻逼怎么能把你祖宗都忘记了?'), '脏话')
    nb.train(defaultTokenizer('你要是不扒一扒脸皮,我还真不晓得原来你的脸皮如此的厚呢!'), '脏话')
    nb.train(defaultTokenizer('对不起哈,当年老子我没忍住,一个屁把这二逼给蹦出来了!'), '脏话')
    nb.train(defaultTokenizer('你是脑子有病还是怎么?你以为你是谁?不就是傻逼一个嘛!'), '脏话')
    nb.train(defaultTokenizer('整天把逼脸摆给别人看,是想要告诉别人你是黄世仁他妈吗?'), '脏话')
    nb.train(defaultTokenizer('你是不是每次拉完屎,然后又自己舔干净了,还到处炫耀自己拉屎很香。'), '脏话')
    nb.train(defaultTokenizer('你妈是靠卖逼把你养大的吧,到你这代还能继续卖逼,真的是母业女继承啊。'), '脏话')
    nb.train(defaultTokenizer('难道你是吃大姨妈拌饭长大的,怪不得长那么恶心呢!'), '脏话')
    nb.train(defaultTokenizer('操你妈,日子那么难过像被人强奸了,但是经典他妈说与其挣扎不如学会享受!'), '脏话')
    nb.train(defaultTokenizer('就你那鸟样还整得跟个吉娃娃卖烧烤串似得,重口味卖得都是巨根火腿吧。'), '脏话')
    nb.train(defaultTokenizer('你大哥拉破车、一直拉到耗子窝、耗子给你两块糖、你管耗子叫大娘。'), '脏话')
    nb.train(defaultTokenizer('就你这样子不好好读书,以后做鸡都没人敢要!'), '脏话')
    nb.train(defaultTokenizer('看你这尖嘴猴腮样,长的那么丑还每天学人家自拍,太恶心人了。'), '脏话')
    console.log('预期:脏话,实际:', nb.test(defaultTokenizer('我操')));
    console.log('预期:正常,实际:', nb.test(defaultTokenizer('还没使用中文分词就分的这么棒')));
    console.log('预期:脏话,实际:', nb.test(defaultTokenizer('你大爷的吧'))); // 脏话
    console.log('预期:脏话,实际:', nb.test(defaultTokenizer('你丫有病吧'))); // 脏话
    console.log('预期:正常,实际:', nb.test(defaultTokenizer('妈妈,我饿了'))); // 正常
    console.log('预期:正常,实际:', nb.test(defaultTokenizer('马克思主义')));  
    

    英文脏话测试

    function defaultTokenizer(text) {
        // 仅保留英文、中文、数字
        var rgxPunctuation = /[^(a-zA-ZA-Яa-я\u4e00-\u9fa50-9_)+\s]/g;
        // 英文以空格分词,中文不分词,以单个字为单位
        return text.replace(rgxPunctuation, ' ').replace(/[\u4e00-\u9fa5]/g, function(word) {
            return word + ' ';
        }).split(/\s+/);
    };
    // 英文学习
    // positive
    nb.train(defaultTokenizer('What is your name?'), 'positive');
    nb.train(defaultTokenizer('amazing, awesome movie!! Yeah!! Oh boy.'), 'positive');
    nb.train(defaultTokenizer('Sweet, this is incredibly, amazing, perfect, great!!'), 'positive');
    nb.train(defaultTokenizer('Do one thing at a time, and do well.'), 'positive');
    nb.train(defaultTokenizer('Never forget to say “thanks”.'), 'positive');
    nb.train(defaultTokenizer('Believe in yourself.'), 'positive');
    nb.train(defaultTokenizer('Never put off what you can do today until tomorrow.'), 'positive');
    nb.train(defaultTokenizer('Do not aim for success if you want it; just do what you love and believe in, and it will come naturally.'), 'positive');
    nb.train(defaultTokenizer('Whatever is worth doing is worth doing well.'), 'positive');
    nb.train(defaultTokenizer('Keep on going never give up.'), 'positive');
    // foul
    nb.train(defaultTokenizer('Get out !Beat it! Get lost!'), 'foul');
    nb.train(defaultTokenizer('Go to hell! Go to the devil!'), 'foul');
    nb.train(defaultTokenizer('Oh, hell is bells!'), 'foul');
    nb.train(defaultTokenizer('You SOB (son of a)!'), 'foul');
    nb.train(defaultTokenizer('You damned (disgusting) bastard!'), 'foul');
    nb.train(defaultTokenizer('Idiot! You damned fool!'), 'foul');
    nb.train(defaultTokenizer('Disgusting!'), 'foul');
    nb.train(defaultTokenizer('I will see you in hell first!'), 'foul');
    nb.train(defaultTokenizer('FUCK Fuck fuck'), 'foul');
    nb.train(defaultTokenizer('You pig!'), 'foul');
    nb.train(defaultTokenizer('God damn !'), 'foul');
    nb.train(defaultTokenizer('Whore! Slut!'), 'foul');
    nb.train(defaultTokenizer('You hypocrite!'), 'foul');
    nb.train(defaultTokenizer('You ass licker (kisser)!'), 'foul');
    // 判断分类
    console.log('预期:positive,实际:', nb.test(defaultTokenizer('My name is Surmon.')));
    console.log('预期:positive,实际:', nb.test(defaultTokenizer('awesome, cool, amazing!! Yay.')));
    console.log('预期:foul,实际:', nb.test(defaultTokenizer('get out!!!')));
    console.log('预期:foul,实际:', nb.test(defaultTokenizer('Fuck!')));
    

    相关文章

      网友评论

          本文标题:JS简单实现朴素贝叶斯分类器

          本文链接:https://www.haomeiwen.com/subject/ldhbnxtx.html