【问题标题】:Naive bayes classifer from scratch in python?python中从头开始的朴素贝叶斯分类器?
【发布时间】:2020-11-05 23:46:24
【问题描述】:

我为我的玩具数据集写了一个简单的朴素贝叶斯分类器

                 msg  spam
0  free home service     1
1      get free data     1
2  we live in a home     0
3    i drive the car     0

完整代码

import pandas as pd
from collections import Counter

data = {'msg':['free home service','get free data','we live in a home','i drive the car'],'spam':[1,1,0,0]}
df = pd.DataFrame(data=data)
print(df)

def word_counter(word_list):
    words = []
    for x in word_list:
        for i in x:
            words.append(i)
    
    word_count = Counter(words)
    return word_count

spam = [x.split() for x in set(df['msg'][df['spam']==1])]
spam = word_counter(spam)

ham = [x.split() for x in set(df['msg'][df['spam']==0])]
ham = word_counter(ham)

total = len(spam.keys())+len(ham.keys())

# Prior
spam_prior = len(df['spam'][df['spam']==1])/len(df)
ham_prior = len(df['spam'][df['spam']==0])/len(df)

new_data = ["get free home service","i live in car"]
print("\n\tSpamminess")
for msg in new_data:
    data = msg.split()
    
    # Likelihood
    spam_likelihood = 0.001 # low value to prevent divisional error
    ham_likelihood = 0.001
    for i in data:
        if i in spam:
            if spam_likelihood==0.001:
                spam_likelihood = spam[i]/total
                continue
            spam_likelihood = spam[i]/total * spam_likelihood
        if i in ham:
            if ham_likelihood==0.001:
                ham_likelihood = ham[i]/total
                continue
            ham_likelihood = ham[i]/total * ham_likelihood
    
    # marginal likelihood
    marginal = (spam_likelihood*spam_prior) + (ham_likelihood*ham_prior)
    
    spam_posterior = (spam_likelihood*spam_prior)/marginal
    print(msg,round(spam_posterior*100,2))

问题是它在我的Spamminess 分类中完全失败了,因为看不见的数据。

get free home service 0.07
i live in car 97.46

我预计 get free home service 的价值较高,而 i live in car 的价值较低。

我的问题是这个错误是由于缺少额外的数据还是因为我的编码错误?

【问题讨论】:

    标签: python machine-learning classification naivebayes


    【解决方案1】:

    问题出在代码上。可能性计算不正确。 请参阅Wikipedia:Naive_Bayes_classifier,了解词袋模型下可能性的正确公式。

    当该词以前未在垃圾邮件中遇到时,您的代码就好像 p(word | spam) 的可能性为 1 一样工作。使用拉普拉斯平滑,它应该是 1 / (spam_total + 1),其中 spam_total 为垃圾邮件中的总字数(有重复)。

    当该词之前在垃圾邮件中出现 x 次时,应该是 (x + 1) / (spam_total + 1)。

    我已将 Counter 更改为 defaultdict 以方便处理以前未遇到的单词,修复似然计算并添加拉普拉斯平滑:

    import pandas as pd
    from collections import defaultdict
    
    data = {'msg':['free home service','get free data','we live in a home','i drive the car'],'spam':[1,1,0,0]}
    df = pd.DataFrame(data=data)
    print(df)
    
    def word_counter(sentence_list):
        word_count = defaultdict(lambda:0)
        for sentence in sentence_list:
            for word in sentence:
                word_count[word] += 1
        return word_count
    
    spam = [x.split() for x in set(df['msg'][df['spam']==1])]
    spam_total = sum([len(sentence) for sentence in spam])
    spam = word_counter(spam)
    
    ham = [x.split() for x in set(df['msg'][df['spam']==0])]
    ham_total = sum([len(sentence) for sentence in ham])
    ham = word_counter(ham)
    
    # Prior
    spam_prior = len(df['spam'][df['spam']==1])/len(df)
    ham_prior = len(df['spam'][df['spam']==0])/len(df)
    
    new_data = ["get free home service","i live in car"]
    print("\n\tSpamminess")
    for msg in new_data:
        data = msg.split()
        
        # Likelihood
        spam_likelihood = 1
        ham_likelihood = 1
        for word in data:
            spam_likelihood *= (spam[word] + 1) / (spam_total + 1)
            ham_likelihood *= (ham[word] + 1) / (ham_total + 1)
        
        # marginal likelihood
        marginal = (spam_likelihood * spam_prior) + (ham_likelihood * ham_prior)
        
        spam_posterior = (spam_likelihood * spam_prior) / marginal
        print(msg,round(spam_posterior*100,2))
    

    现在结果如预期:

        Spamminess
    get free home service 98.04
    i live in car 20.65
    

    这可以进一步改进,例如为了数值稳定性,所有这些概率的乘法应该用对数相加来代替。

    【讨论】:

    • spam_total = len(spam) 是做什么的?我假设我们想要单词的数量,但要给出句子的数量。
    猜你喜欢
    • 2017-07-25
    • 2021-11-12
    • 2016-09-28
    • 2017-01-10
    • 2017-03-17
    • 2013-04-19
    • 2020-07-13
    • 2012-03-29
    相关资源
    最近更新 更多