python机器学习案例系列教程——分类器,朴素贝叶斯分类器,费舍尔分类器

来源:互联网 发布:社会调查数据方法 编辑:程序博客网 时间:2024/05/19 03:30

全栈工程师开发手册 (作者:栾鹏)

python教程全解

分类器与聚类算法不同。聚类算法是非监督算法,只是对一群输入对象进行分组,每组属于什么类别是不知道的。而分类器是在没有任何数据前就已经定好了拥有哪些类。分类器是监督算法。对一批已知所属分类的数据集进行统计训练。然后再对新来的数据进行判定属于哪个分类。

过程概述:首先有一批已知分类的数据集。对每个输入对象提取特征,根据输入对象的特征属性和输入对象的所属分类,计算分类与特征属性之间的概率关系,以此来实现样本的训练。当对新的输入对象进行预测所属分类时,提取新输入对象的特征,根据训练好的概率,判断输入对象属于每个分类的概率。

本文以垃圾邮件识别为例进行python代码演示。

首先我们先定义一批简单的已知样本数据,也就是邮件内容和所属分类。当然后面我们会添加特征提取的地方,包含邮件时间,邮件来源,邮件标题,邮件质量等。分类也不仅限于垃圾和非垃圾,可以包含订阅邮件,推广邮件,有毒邮件,购物邮件,学习邮件等等。现在这里我们仅对邮件文本内容进行识别,将邮件区分为垃圾和非垃圾。

在分类器中,你需要重点理清,文章属于某个分类器的概率Pr(category|Document)和在指定分类中文章出现的概率Pr(Document|category)的区别

分类器对输入对象进行分类的原理就是判断输入对象(邮件文档)属于哪个分类的概率更大。
也就是比较在文档已知的情况下,属于每个分类的概率的大小。即Pr( category|Document))概率的大小。

样本数据集

# 邮件数据集,,邮件内容和所属分类data=[    ['Nobody owns the water.','good'],    ['the quick rabbit jumps fences','good'],    ['buy pharmaceuticals now','bad'],    ['make quick money at the online casino','bad'],    ['the quick brown fox jumps','good'],]

特征提取函数

要实现对输入对象进行分类,首要要能够对输入对象提取用于分类的特征。在邮件中特征就是单词,我们就是根据单词来进行垃圾邮件识别。
对输入对象进行特征提取。(对邮件文档提取对单词)

# 从输入对象中提取特征(文档中提取不重复单词)def getwords(doc):    splitter=re.compile('\\W*')    print(doc)    # 根据非字母字符进行单词拆分    words=[s.lower() for s in splitter.split(doc) if len(s)>2 and len(s)<20]    # 只返回一组不重复的单词。(特征不重复)    return dict([(w,1) for w in words])

特征概率(指定分类中指定特征出现的概率)

指定分类中指定特征出现的概率(Pr (word | classification ))=指定分类中指定特征出现的次数/指定分类中所有特征出现的次数。

计算特征概率,我们可以通过样本数据集进行统计。

我们将这个基本功能写在classifier类中,该类将特征存储在sqlite数据库中,并实现对样本数据集和特征的相关统计。后面我们会在classifier类的基础上派生朴素贝叶斯分类器和派生费舍尔分类器。

在classifier类中我们实现将训练集中提取来的特征和分类存储到数据库中,并添加特征与分类之间的概率统计函数。

# 统计基类。主要为了计算特征概率Pr (word | classification )。有多种不同的分类器方式,在此类上派生。定义成类,这样每个实例对象可以训练自己的数据集class classifier:    #getfeatures为特征提取函数    def __init__(self,getfeatures,filename=None):        # 统计特征/分类组合的数量。(每个特征在不同分类中的数量)        self.fc={}        # 统计每个分类中的文档数量。(每个分类中的输入对象的数量)        self.cc={}        self.getfeatures=getfeatures        self.setdb('test.db')    #设定数据库    # 链接数据库,创建表    def setdb(self,dbfile):        self.con=sqlite3.connect(dbfile)        self.curs = self.con.cursor()        self.curs.execute('create table if not exists fc(feature,category,count)')        self.curs.execute('create table if not exists cc(category,count)')    # 增加对特征feature/分类cat组合的计数值    def incf(self,feature,cat):        count=self.fcount(feature,cat)   #计算某一特征在某一分类中出现的次数        if count==0:            self.curs.execute("insert into fc values ('%s','%s',1)" % (feature,cat))        else:            self.curs.execute("update fc set count=%d where feature='%s' and category='%s'" % (count+1,feature,cat))    # 查询某一特征出现于某一分类中的次数    def fcount(self,feature,cat):        res=self.curs.execute('select count from fc where feature="%s" and category="%s"' %(feature,cat)).fetchall()        if res==None or len(res)==0: return 0        else: return float(res[0][0])    # 增加对某一分类的计数值    def incc(self,cat):        count=self.catcount(cat)        if count==0:            self.curs.execute("insert into cc values ('%s',1)" % (cat))        else:            self.curs.execute("update cc set count=%d where category='%s'" % (count+1,cat))    # 查询属于某一分类的输入对象(文章)的数量    def catcount(self,cat):        res=self.curs.execute('select count from cc where category="%s"' %(cat)).fetchall()        if res==None or len(res)==0: return 0        else: return float(res[0][0])    # 查询所有分类的列表。因为要计算每个属于每个分类的比例    def categories(self):        cur=self.curs.execute('select category from cc')        return [d[0] for d in cur]    # 所有输入对象(文章)的数量.这是一项无用的计算。    def totalcount(self):        res=self.curs.execute('select sum(count) from cc').fetchall()        if res==None or len(res)==0: return 0        return res[0][0]    # 对样本进行统计训练,完善数据库。参数为:输入对象,所属分类    def train(self,input,cat):        features=self.getfeatures(input)  #提取特征        # 针对该分类为提取到的特征增加计数值        for feature in features:            self.incf(feature,cat)        # 增加针对该分类的计数值        self.incc(cat)        self.con.commit()#=================上面是存储特征和分类=================#=================下面是计算特征概率Pr (word | classification )=================    # 统计指定分类中某一特征出现的概率(单词在分类中出现的概率,Pr(word/classification))    def fprob(self,feature,cat):        if self.catcount(cat)==0: return 0        # 该特征在分类中出现的次数,除以分类中所有特征的数目        return self.fcount(feature,cat)/self.catcount(cat)    # 计算加权概率,为特征设置权重,避免极少特征的强烈震荡。比如money单词只出现了一次在垃圾邮件中。也就是100%是垃圾邮件。所以添加权重概率避免这种事情。    def weightedprob(self,feature,cat,prf,weight=1.0,ap=0.5):        # 计算在某一分类中某一特征出现的概率        basicprob=prf(feature,cat)        # 统计某一特征在所有分类中出现的次数        totals=sum([self.fcount(feature,cat) for cat in self.categories()])        # 计算加权平均        bp=((weight*ap)+(totals*basicprob))/(weight+totals)        return bp  #返回加权平均概率

在classifier基类中计算了在指定分类(垃圾非垃圾)中每个特征(单词)出现的概率

Pr (word | classification )

为了计算新输入对象(一批特征)出现时,属于某个分类的概率

Pr ( Document | category )

我们采用两种情况以应对不同的场景。

输入对象概率——朴素贝叶斯分类

朴素贝叶斯分类器的过程。

这里写图片描述

对于特征间相互独立的情况。则指定分类中所有特征都出现的概率等于指定分类中每个特征出现的概率的乘机。即

Pr ( Document | category ) = Pr ( word1| category )*Pr ( word2| category )*Pr ( word3| category )...
# 派生朴素贝叶斯分类器(适用于特征间相互独立的情况)。将单词在目标分类中的概率组合成输入对象(文章)在分类中的概率。class naivebayes(classifier): # 获取输入对象(文章)在指定分类中的概率。Pr(Document|Categrory)    def docprob(self,input,cat):        features=self.getfeatures(input)        # 将所有特征的概率相乘        p=1        for feature in features: p*=self.weightedprob(feature,cat,self.fprob)        return p

有了指定分类器文档出现的概率,不能就此计算输入对象属于每个分类器的概率,并比较大小来判断属于哪个分类器。因为每个分类出现的概率本身并不是相等的。

Pr(category|Document)=Pr(Document|category)*Pr(category)/Pr(Document)

我们的目的是为了计算Pr(category|Document),现在我们已经计算了Pr(Document|category),而且对于每一个输入对象Pr(Document)都是相等的,所以要比较大小(而不是计算具体的概率值),只需要再计算Pr(category)。很显然Pr(category)等于指定分类中的特征数目除以总的特征数即可得到。

    # 统计分类的概率,并返回Pr(Document|Category)*Pr(Category)/Pr(Document)。朴素贝叶斯用这个概率代表最终概率进行比较    def prob(self,input,cat):        catprob=self.catcount(cat)/self.totalcount()        docprob=self.docprob(input,cat)   #获取指定分类中,输入对象的概率.Pr(Document|Categrory)        return docprob*catprob

通过上面的过程,我们就完成输入对象属于每种分类的相对大小。但是很多情况下,并不是输入对象属于一种分类的概率比另一种分类概率高,就把输入对象设置概率高的分类。例如一个邮件属于垃圾邮件的概率为60%,属于正常邮件的概率为40%。但是如果我们的判断有误,会对用户造成巨大的损失,为您情愿不判也不愿判断错误。为解决这一问题,我们可以为每个分类定义一个最小阈值n。输入对象属于该分类的概率至少大于属于其他分类的概率的n倍,才被认为属于该分类。

    def __init__(self,getfeatures):        classifier.__init__(self,getfeatures)        self.thresholds={}    def setthreshold(self,cat,t):        self.thresholds[cat]=t    def getthreshold(self,cat):        if cat not in self.thresholds: return 1.0        return self.thresholds[cat]    def classify(self,input,default=None):        probs={}        # 寻找概率最大的分类        max=0.0        cats = self.categories()        for cat in cats:            probs[cat]=self.prob(input,cat)            if probs[cat]>max:                max=probs[cat]                best=cat        # 确保概率值超过阈值*次大概率值        for cat in probs:            if cat==best: continue            if probs[cat]*self.getthreshold(best)>probs[best]: return default        return best

使用朴素贝叶斯分类器进行分类的试验

# 简单的样本训练def sampletrain(cl,data):    for item in data:        cl.train(item[0],item[1])if __name__=="__main__":     #只有在执行当前模块时才会运行此函数    cl=naivebayes(getwords)   #定义朴素贝叶斯分类器    sampletrain(cl,data)   #训练样本数据    best = cl.classify('quick money')  #利用分类器进行分类    print(best)   #打印分类结果

输入对象概率——费舍尔分类器

对于特征间不相互独立的情况。朴素贝叶斯分类器的效果就会受到影响。这里介绍一种新的分类器——费舍尔分类器。

同样在classifier类的基础上派生出费舍尔分类器。费舍尔分类器先计算某特征属于指定分类的概率Pr(Category|feature),再根据此概率计算费舍尔方法的值(所有概率相乘,取自然对数,再乘以-2)。最后通过输入对象的费舍尔值对输入对象进行分类。

1、计算某特征属于指定分类的概率Pr(Category|feature)

class fisherclassifier(classifier):    # 计算某特征属于指定分类的概率Pr(Category|feature)    def cprob(self,f,cat):        # 特征在该分类中出现的概率        clf=self.fprob(f,cat)        if clf==0: return 0        # 特征在所有分类中出现的频率        freqsum=sum([self.fprob(f,c) for c in self.categories()])        # 概率等于特征在该分类中出现的频率除以总体频率        p=clf/(freqsum)        return p

2、计算费舍尔值

# 根据输入对象获取属性特征,计算特征属于分类的概率,再计算费舍尔的值作为输入对象(文章)属于指定分类的概率    def fisherprob(self,input,cat):        # 将所有概率值相乘        p=1        features=self.getfeatures(input)        for f in features:            p*=(self.weightedprob(f,cat,self.cprob))        # 取自然对数,并乘以-2        fscore=-2*math.log(p)        # 利用倒置对数卡方函数求得概率        return self.invchi2(fscore,len(features)*2)    # 倒置对数卡方函数    def invchi2(self,chi, df):        m = chi / 2.0        sum = term = math.exp(-m)        for i in range(1, df//2):            term *= m / i            sum += term        return min(sum, 1.0)

3、使用费舍尔值,通过为不同的分类设定各自的费舍尔值类判断是否划分到各自的分类。输入对象的属于不同分类的费舍尔值之间就没有相互比较的意义。他们只需要个每个分类对象的费舍尔门限比较就可以了。

比如,在朴素贝叶斯分类器中,一封邮件要计算出属于正常邮件的概率,还要计算出属于垃圾邮件的概率(在其他应用中还有更多的分类),通过计算至此之间的概率倍数,来决定是否划归到某分类。而在费舍尔分类器中,会先计算邮件属于正常邮件的费舍尔值,如0.7,如果大于正常邮件这个分类的费舍尔门限,如0.6,就直接被划归到正常邮件分类中。如果低于门限,再计算属于其他分类的费舍尔值。

代码实现

    def setminimum(self,cat,min):        self.minimums[cat]=min    def getminimum(self,cat):        if cat not in self.minimums: return 0        return self.minimums[cat]    # 使用具体的下限费舍尔值来对输入对象进行分类    def classify(self,input,default=None):        # 循环遍历并寻找最佳结果        best=default        max=0.0        for c in self.categories():            p=self.fisherprob(input,c)   #计算输入对象的费舍尔值            # 确保其超过下限值            if p>self.getminimum(c) and p>max:                best=c                max=p        return best

测试代码

if __name__=="__main__":     #只有在执行当前模块时才会运行此函数    cl = fisherclassifier(getwords)  # 定义费舍尔分类器    sampletrain(cl, data)  # 训练样本数据(数据清洗、转换、提取)    best = cl.classify('quick money')  # 利用分类器进行分类    print(best)  # 打印分类结果

上面的案例我们使用邮件垃圾筛选。我们将全部代码存储为docclass.py文件。全部代码如下。
后面我们使用这个分类器来为博客文章进行分类。

# 文档过滤,垃圾邮件分类。跟聚类(不知道多少分类,也不知道有什么类别)不同,它是一种监督式的学习方法。因此也就在分类前已知道分类(垃圾邮件和非垃圾邮件)。判断对象属于哪种分类。import sqlite3import reimport math# 邮件数据集,,邮件内容和所属分类data=[    ['Nobody owns the water.','good'],    ['the quick rabbit jumps fences','good'],    ['buy pharmaceuticals now','bad'],    ['make quick money at the online casino','bad'],    ['the quick brown fox jumps','good']]# 从输入对象中提取特征(文档中提取不重复单词)def getwords(doc):    splitter=re.compile('\\W*')    # print(doc)    # 根据非字母字符进行单词拆分    words=[s.lower() for s in splitter.split(doc) if len(s)>2 and len(s)<20]    # 只返回一组不重复的单词。(特征不重复)    return dict([(w,1) for w in words])# 统计基类。主要为了计算特征概率Pr (word | classification )。有多种不同的分类器方式,在此类上派生。定义成类,这样每个实例对象可以训练自己的数据集class classifier:    #getfeatures为特征提取函数    def __init__(self,getfeatures,filename=None):        # 统计特征/分类组合的数量。(每个特征在不同分类中的数量)        self.fc={}        # 统计每个分类中的文档数量。(每个分类中的输入对象的数量)        self.cc={}        self.getfeatures=getfeatures        self.setdb('test.db')    #设定数据库    # 链接数据库,创建表    def setdb(self,dbfile):        self.con=sqlite3.connect(dbfile)        self.curs = self.con.cursor()        self.curs.execute('create table if not exists fc(feature,category,count)')        self.curs.execute('create table if not exists cc(category,count)')    # 增加对特征feature/分类cat组合的计数值    def incf(self,feature,cat):        count=self.fcount(feature,cat)   #计算某一特征在某一分类中出现的次数        if count==0:            self.curs.execute("insert into fc values ('%s','%s',1)" % (feature,cat))        else:            self.curs.execute("update fc set count=%d where feature='%s' and category='%s'" % (count+1,feature,cat))    # 查询某一特征出现于某一分类中的次数    def fcount(self,feature,cat):        res=self.curs.execute('select count from fc where feature="%s" and category="%s"' %(feature,cat)).fetchall()        if res==None or len(res)==0: return 0        else: return float(res[0][0])    # 增加对某一分类的计数值    def incc(self,cat):        count=self.catcount(cat)        if count==0:            self.curs.execute("insert into cc values ('%s',1)" % (cat))        else:            self.curs.execute("update cc set count=%d where category='%s'" % (count+1,cat))    # 查询属于某一分类的输入对象(文章)的数量    def catcount(self,cat):        res=self.curs.execute('select count from cc where category="%s"' %(cat)).fetchall()        if res==None or len(res)==0: return 0        else: return float(res[0][0])    # 查询所有分类的列表。因为要计算每个属于每个分类的比例    def categories(self):        cur=self.curs.execute('select category from cc')        return [d[0] for d in cur]    # 所有输入对象(文章)的数量.这是一项无用的计算。    def totalcount(self):        res=self.curs.execute('select sum(count) from cc').fetchall()        if res==None or len(res)==0: return 0        return res[0][0]    # 对样本进行统计训练,完善数据库。参数为:输入对象,所属分类    def train(self,input,cat):        features=self.getfeatures(input)  #提取特征        # 针对该分类为提取到的特征增加计数值        for feature in features:            self.incf(feature,cat)        # 增加针对该分类的计数值        self.incc(cat)        self.con.commit()#=================上面是存储特征和分类=================#=================下面是计算特征概率Pr (word | classification )=================    # 统计指定分类中某一特征出现的概率(单词在分类中出现的概率,Pr(word/classification))    def fprob(self,feature,cat):        if self.catcount(cat)==0: return 0        # 该特征在分类中出现的次数,除以分类中所有特征的数目        return self.fcount(feature,cat)/self.catcount(cat)    # 计算加权概率,为特征设置权重,避免极少特征的强烈震荡。比如money单词只出现了一次在垃圾邮件中。也就是100%是垃圾邮件。所以添加权重概率避免这种事情。    def weightedprob(self,feature,cat,prf,weight=1.0,ap=0.5):        # 计算在某一分类中某一特征出现的概率        basicprob=prf(feature,cat)        # 统计某一特征在所有分类中出现的次数        totals=sum([self.fcount(feature,cat) for cat in self.categories()])        # 计算加权平均        bp=((weight*ap)+(totals*basicprob))/(weight+totals)        return bp  #返回加权平均概率# 派生朴素贝叶斯分类器(适用于特征间相互独立的情况)。将单词在目标分类中出现的概率相乘组成输入对象(文章)出现在分类中的概率。class naivebayes(classifier):    def __init__(self,getfeatures):        classifier.__init__(self,getfeatures)        self.thresholds={}    # 获取输入对象(文章)出现在指定分类中的概率。Pr(Document|Categrory)    def docprob(self,input,cat):        features=self.getfeatures(input)        # 将所有特征的概率相乘        p=1        for feature in features: p*=self.weightedprob(feature,cat,self.fprob)        return p    # 统计分类的概率,并返回Pr(Document|Category)*Pr(Category)/Pr(Document)。朴素贝叶斯用这个概率代表最终概率进行比较    def prob(self,input,cat):        catprob=self.catcount(cat)/self.totalcount()        docprob=self.docprob(input,cat)   #获取指定分类中,输入对象的概率.Pr(Document|Categrory)        return docprob*catprob    def setthreshold(self,cat,t):        self.thresholds[cat]=t    def getthreshold(self,cat):        if cat not in self.thresholds: return 1.0        return self.thresholds[cat]    def classify(self,input,default=None):        probs={}        # 寻找概率最大的分类        max=0.0        cats = self.categories()        for cat in cats:            probs[cat]=self.prob(input,cat)            if probs[cat]>max:                max=probs[cat]                best=cat        # 确保概率值超过阈值*次大概率值        for cat in probs:            if cat==best: continue            if probs[cat]*self.getthreshold(best)>probs[best]: return default        return best# 派生费舍尔分类器。先计算某特征属于指定分类的概率Pr(Category|feature),再根据此概率计算费舍尔方法的值(所有概率相乘,取自然对数,再乘以-2)。class fisherclassifier(classifier):    # 计算某特征属于指定分类的概率Pr(Category|feature)    def cprob(self,f,cat):        # 特征在该分类中出现的概率        clf=self.fprob(f,cat)        if clf==0: return 0        # 特征在所有分类中出现的频率        freqsum=sum([self.fprob(f,c) for c in self.categories()])        # 概率等于特征在该分类中出现的频率除以总体频率        p=clf/(freqsum)        return p    # 根据输入对象获取属性特征,计算特征属于分类的概率,再计算费舍尔的值作为输入对象(文章)属于指定分类的概率    def fisherprob(self,input,cat):        # 将所有概率值相乘        p=1        features=self.getfeatures(input)        for f in features:            p*=(self.weightedprob(f,cat,self.cprob))        # 取自然对数,并乘以-2        fscore=-2*math.log(p)        # 利用倒置对数卡方函数求得概率        return self.invchi2(fscore,len(features)*2)    # 倒置对数卡方函数    def invchi2(self,chi, df):        m = chi / 2.0        sum = term = math.exp(-m)        for i in range(1, df//2):            term *= m / i            sum += term        return min(sum, 1.0)    def __init__(self,getfeatures):        classifier.__init__(self,getfeatures)        self.minimums={}    def setminimum(self,cat,min):        self.minimums[cat]=min    def getminimum(self,cat):        if cat not in self.minimums: return 0        return self.minimums[cat]    # 使用具体的下限费舍尔值来对输入对象进行分类    def classify(self,input,default=None):        # 循环遍历并寻找最佳结果        best=default        max=0.0        for c in self.categories():            p=self.fisherprob(input,c)   #计算输入对象的费舍尔值            # 确保其超过下限值            if p>self.getminimum(c) and p>max:                best=c                max=p        return best# 简单的样本训练def sampletrain(cl,data):    for item in data:        cl.train(item[0],item[1])if __name__=="__main__":     #只有在执行当前模块时才会运行此函数    cl=naivebayes(getwords)   #定义朴素贝叶斯分类器    sampletrain(cl,data)   #训练样本数据(数据清洗、转换、提取)    best = cl.classify('quick money')  #利用分类器进行分类    print(best)   #打印分类结果    cl = fisherclassifier(getwords)  # 定义费舍尔分类器    sampletrain(cl, data)  # 训练样本数据(数据清洗、转换、提取)    best = cl.classify('quick money')  # 利用分类器进行分类    print(best)  # 打印分类结果

下面我们使用上面的分类器,来对博客文章进行分类。

首先我们要搜集一个数据集。读者可以自己爬取,下面给出一个收集好的数据集python_search.xml

点击下载。

使用前面的分类器对博客文章进行分类。

# 利用分类器,应用到过滤博客订阅源import feedparserimport reimport docclass# 接受一个博客订阅源的url文件名并对内容项进行分类def read(feedfile,classifier):    # 得到订阅源的内容项并遍历循环    f=feedparser.parse(feedfile)    for entry in f['entries']:        print        print('-----')        # 将内容项打印输出        print('Title:     '+entry['title'])        print('Publisher: '+entry['publisher'])        print        print(entry['summary'])        # 将所有文本组合在一起,为分类器构建一个内容项        fulltext='%s\n%s\n%s' % (entry['title'],entry['publisher'],entry['summary'])        # 将当前分类的最佳推测结果打印输出        print('Guess: '+str(classifier.classify(fulltext)))        # 请求用户给出正确分类,并据此进行训练        if(entry.has_key('cat') and entry['cat']!=None):            classifier.train(fulltext, entry['cat'])        else:            cl=input('Enter category: ')            classifier.train(fulltext,cl)if __name__=="__main__":     #只有在执行当前模块时才会运行此函数    # 对博客文章进行分类和训练    cl=docclass.fisherclassifier(docclass.getwords)    cl.setdb('python_feed.db')    read('python_search.xml',cl)

除了我们可以选择使用不同的分类器来实现对输入对象的分类效果。我们还可以明显的注意到特征的选择对分类也是至关重要的。前面的所有例子,我们均使用文章的所有单词作为输入对象的特征。
但有时能代表一篇文章的可能是标题,作者,摘要等重要信息,而不是全部单词。所以我们还可以对特征提取函数进行改进,以使分类效果更好。

# 利用分类器,应用到过滤博客订阅源import feedparserimport reimport docclass# 接受一个博客订阅源的url文件名并对内容项进行分类def read(feedfile,classifier):    # 得到订阅源的内容项并遍历循环    f=feedparser.parse(feedfile)    for entry in f['entries']:        print        print('-----')        # 将内容项打印输出        print('Title:     '+entry['title'])        print('Publisher: '+entry['publisher'])        print        print(entry['summary'])        # 将所有文本组合在一起,为分类器构建一个内容项        fulltext='%s\n%s\n%s' % (entry['title'],entry['publisher'],entry['summary'])        # 将当前分类的最佳推测结果打印输出        print('Guess: '+str(classifier.classify(fulltext)))        # 请求用户给出正确分类,并据此进行训练        if(entry.has_key('cat') and entry['cat']!=None):            classifier.train(fulltext, entry['cat'])        else:            cl=input('Enter category: ')            classifier.train(fulltext,cl)# 对特征检测的改进。新的特征提取函数。更关注文章的名称、摘要、作者介绍def entryfeatures(entry):    splitter=re.compile('\\W*')    features={}    # 提取标题中的单词并进行标识    titlewords=[s.lower() for s in splitter.split(entry['title']) if len(s)>2 and len(s)<20]    for w in titlewords: features['Title:'+w]=1    # 提取摘要中单词    summarywords=[s.lower() for s in splitter.split(entry['summary']) if len(s)>2 and len(s)<20]    # 统计大写单词    uc=0    for i in range(len(summarywords)):        w=summarywords[i]        features[w]=1        if w.isupper(): uc+=1        # 将从摘要中获得词组作为特征        if i<len(summarywords)-1:            twowords=' '.join(summarywords[i:i+1])            features[twowords]=1    # 保持文章创建者和发布者名字的完整性    features['Publisher:'+entry['publisher']]=1    # UPPERCASE是一个“虚拟”单词,用以指示存在过多的大写内容    if float(uc)/len(summarywords)>0.3: features['UPPERCASE']=1    return featuresif __name__=="__main__":     #只有在执行当前模块时才会运行此函数    # 使用改进的特征提取函数对文章分类进行处理    cl = docclass.fisherclassifier(entryfeatures)    cl.setdb('python_feed.db')    read('python_search.xml', cl)
阅读全文
1 0
原创粉丝点击