贝叶斯分类基于概率论中与条件概率相关的贝叶斯定理,根据条件概率的计算方法:
贝叶斯定理提供了根据一系列已知概率来计算后验概率的方法。一系列已知概率,根据大数定理,我们可以用已有的统计样本(训练集)的频率来估计。因此准确性其实有赖于训练集的规模和代表性。
朴素之处
假设每条记录(元组)用一个n维向量
朴素贝叶斯分类之所以被称为朴素(Naive,幼稚的),是因为它对于很难计算的后验概率
这种假设有其局限性,因为属性之间条件独立是很不可能的,比如议员在议题A上的取态不太可能和议题B的无关(当然其中往往没有直接的逻辑关系,但数学上定义的条件独立要求两个事件共同发生的概率等于两者概率的乘积)。因此这个假设虽然方便,但带来误差,但这不影响这种“幼稚”的方法的实用性。
先验概率估算
如果不存在可用的训练集,最好的方法是遵循信息论中的熵最小原则,假设所有的类是等概率的。但其实我们往往都有办法得到训练元组,前面说过,离散属性的概率可以通过其频率获得,而对于连续属性,我们进行一个比较依靠经验法则的假设,我们假设连续属性都满足正态分布,根据训练集作为统计样本得到均值和标准差,定义出该属性的分布公式:
只要掌握了上述的思想,我们可以发现贝叶斯分类的数学模型是非常简洁好懂的。
拉普拉斯估计
根据类条件独立的假设,某属性向量的概率由其各维乘积得到,但如果遇到其中一个维的概率为0,那么估算出来的后验概率都会为0。如此一来该类的估算概率便为零。但这很可能只是因为训练集的局限性所致(因为规模不够大,或是不够全面)。这时我们引入另外一个假设,假设训练集很大,以致对每个计数结果加上1不会对估计概率产生不可忽略的影响,我们就可以用这种方法来避免零概率值的出现。
当然,在对k个技术结果都加一后,计算频率的分母应该加上k。
另,我们如果只是需要分类结果,因为我们是找具有最大后验概率的分类,而对于某个特定的属性向量X,其概率P(X)只是起到了归一化因子的作用,因此计算时只需要计算分子
测试
以下是对美国国会数据集进行朴素贝叶斯分类的代码:
import random class instance(): def __init__(self, party, votes): self.party = party self.votes = votes dataFile = open('dataset.txt', 'r') datas = dataFile.readlines() database = [] for line in datas: line = line[:-2] attrs = line.split(',') member = instance(attrs[0], attrs[1:]) database.append(member) partyName = ['democrat', 'republican'] trainset = [] checkset = [] for i in range(len(database)): if random.random() > 0.9: checkset.append(database[i]) else: trainset.append(database[i]) stats = {} for name in partyName: stats[name] = {"number" : 0, "votes" : []} for k in stats: for i in range(len(database[0].votes)): stats[k]['votes'].append({"y" : 0, "?" : 0, "n" : 0}) for record in trainset: stats[record.party]['number'] += 1 for i in range(len(record.votes)): stats[record.party]['votes'][i][record.votes[i]] += 1 wrong = 0.0 for record in checkset: probability = {} for name in partyName: probability[name] = 0.0 for k in probability: p = 1.0 for i in range(len(record.votes)): p *= (float(stats[k]['votes'][i][record.votes[i]]) / float(stats[k]['number'])) probability[k] = p if probability['democrat'] > probability['republican']: predict = "democrat" else: predict = "republican" print record.party + " , " + predict if record.party != predict: wrong += 1.0 print "correct rate: " + str(1 - wrong / len(checkset))每条记录有90%的可能选作训练集,剩余用于检验分类正确性,最后打印出正确率
无耻地选了难得的全对结果,实际的正确率大约稳定在85%以上。
以下观点摘自《数据挖掘》:
理论上贝叶斯分类具有最小的错误率,但实践中容易因缺乏可用的概率数据和其假定的不确定性影响。
没有评论 :
发表评论