SVM作为机器学习里面的经典算法在实际中一直被广泛采用,而且其准确性也是非常之高,特别是在引入了核函数之后对识别性能变得非常高。

说明:本文不打算就SVM原理就深入分析,虽然对其原理略懂一二,但是对于SMO算法的理解确实比较浅,所以也不打算班门弄斧,略微介绍,本文重点在于SVM的应用,也就是对垃圾邮件的文本分类

关于支持向量机的原理性分析在CSDN上有July大神的博客 :http://blog.csdn.net/v_july_v/article/details/7624837,我就之略微介绍一下原理

一,SVM原理象征性简述:

SVM主要应用是分类操作,以二元线性分类为例,主要思想是根据特征向量的超空间创建一条超平面分隔线,当然在加入核函数后,可以把非线性分类映射到高维空间使之成为线性分类,而在求参数的过程中会使用SMO算法选取参数,会有不错的性能

二,SVM对垃圾邮件的分类:

这篇文章中的SVM的python实现代码参考自《Machine Learning in Action》一书,其训练数据来自该书的朴素贝叶斯分类一章,朴素贝叶斯也是一种比较简单而实用的分类方法,这里是使用了那一章的邮件数据

步骤说明:

1,提取训练邮件数据的特征向量

由于邮件的内容很多,因此找出其主要的分类关键词尤为关键,在找出关键词后就可以用这些关键词对邮件进行特征标记,也就是如果关键词在这篇文章中标记为1不出现则标记为0

其中每一个邮件类别中的关键词的选取方法有很多,我决定采用 TF-IDF方法选取关键词,在计算IDF的时候,考虑到我们是对整个类邮件进行分类,因此就没有采用IDF的传统计算方法,而是计算这词语在整个类邮件中的邮件占比,也就是出现该词语的文档数量除以文档总数量

关于 TF-IDF的介绍见百度百科

http://baike.baidu.com/link?url=oYpXqrTb6yQB1KaNUl8LS-01gUsy09s0w9JGpPq4QH8s_AzFI796tvWXnXtoGtpW-WAvLrKYwhsHp1l3i3JGpK

在得出所有的词语的TF-IDF数后,我选取数最大的前100个词作为这一类邮件的关键词(每个类不重复的词语数量大概在300多个)

得到关键词后我们就可以对每个邮件进行特征向量标记了,每个邮件由100个特征值标记,也就是对每个上文提出的关键词,如果这个邮件存在这个词语就标记为1,如果不存在,那么这个词语就标记为0,

这样就可以得出了每个邮件的特征向量值了

2,将步骤1得到的特征值使用SVM训练,本文的SVM代码实现基本是基于李航的《统计学习方法》一书,因为本文不是来叙述原理的,所以也略过不表,在这个例子中使用了rbf作为核函数

3,得到训练模型后就可以使用交叉验证方法验证数据的正确性了,具体的说,就是使用50个训练数据中的40个邮件的特征向量训练数据,使用剩下的10个邮件的特征向量作为测试向量

还是那句话,代码是硬道理,下面直接上代码

SVM主要代码:

# -*- coding: utf-8 -*-
from numpy import *
from time import sleep
import matplotlib.pyplot as pltdef loadDataSet(fileName):dataMat = []; labelMat = []fr = open(fileName)for line in fr.readlines():lineArr = line.strip().split('\t')dataMat.append([float(lineArr[0]), float(lineArr[1])])labelMat.append(float(lineArr[2]))return dataMat,labelMatdef selectJrand(i,m):j=i #we want to select any J not equal to iwhile (j==i):j = int(random.uniform(0,m))return jdef clipAlpha(aj,H,L):if aj > H: aj = Hif L > aj:aj = Lreturn ajdef smoSimple(dataMatIn, classLabels, C, toler, maxIter):dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose()b = 0; m,n = shape(dataMatrix)alphas = mat(zeros((m,1)))iter = 0while (iter < maxIter):alphaPairsChanged = 0for i in range(m):fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + bEi = fXi - float(labelMat[i])#if checks if an example violates KKT conditionsif ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):j = selectJrand(i,m)fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + bEj = fXj - float(labelMat[j])alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();if (labelMat[i] != labelMat[j]):L = max(0, alphas[j] - alphas[i])H = min(C, C + alphas[j] - alphas[i])else:L = max(0, alphas[j] + alphas[i] - C)H = min(C, alphas[j] + alphas[i])if L==H: print "L==H"; continueeta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].Tif eta >= 0: print "eta>=0"; continuealphas[j] -= labelMat[j]*(Ei - Ej)/etaalphas[j] = clipAlpha(alphas[j],H,L)if (abs(alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; continuealphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#update i by the same amount as j#the update is in the oppostie directionb1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].Tb2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].Tif (0 < alphas[i]) and (C > alphas[i]): b = b1elif (0 < alphas[j]) and (C > alphas[j]): b = b2else: b = (b1 + b2)/2.0alphaPairsChanged += 1print "iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)if (alphaPairsChanged == 0): iter += 1else: iter = 0print "iteration number: %d" % iterreturn b,alphasdef kernelTrans(X, A, kTup): #calc the kernel or transform data to a higher dimensional spacem,n = shape(X)K = mat(zeros((m,1)))if kTup[0]=='lin': K = X * A.T   #linear kernelelif kTup[0]=='rbf':for j in range(m):deltaRow = X[j,:] - AK[j] = deltaRow*deltaRow.TK = exp(K/(-1*kTup[1]**2)) #divide in NumPy is element-wise not matrix like Matlabelse: raise NameError('Houston We Have a Problem -- \That Kernel is not recognized')return Kclass optStruct:def __init__(self,dataMatIn, classLabels, C, toler, kTup):  # Initialize the structure with the parameters self.X = dataMatInself.labelMat = classLabelsself.C = Cself.tol = tolerself.m = shape(dataMatIn)[0]self.alphas = mat(zeros((self.m,1)))self.b = 0self.eCache = mat(zeros((self.m,2))) #first column is valid flagself.K = mat(zeros((self.m,self.m)))for i in range(self.m):self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)def calcEk(oS, k):fXk = float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b)Ek = fXk - float(oS.labelMat[k])return Ekdef selectJ(i, oS, Ei):         #this is the second choice -heurstic, and calcs EjmaxK = -1; maxDeltaE = 0; Ej = 0oS.eCache[i] = [1,Ei]  #set valid #choose the alpha that gives the maximum delta EvalidEcacheList = nonzero(oS.eCache[:,0].A)[0]if (len(validEcacheList)) > 1:for k in validEcacheList:   #loop through valid Ecache values and find the one that maximizes delta Eif k == i: continue #don't calc for i, waste of timeEk = calcEk(oS, k)deltaE = abs(Ei - Ek)if (deltaE > maxDeltaE):maxK = k; maxDeltaE = deltaE; Ej = Ekreturn maxK, Ejelse:   #in this case (first time around) we don't have any valid eCache valuesj = selectJrand(i, oS.m)Ej = calcEk(oS, j)return j, Ejdef updateEk(oS, k):#after any alpha has changed update the new value in the cacheEk = calcEk(oS, k)oS.eCache[k] = [1,Ek]def innerL(i, oS):Ei = calcEk(oS, i)if ((oS.labelMat[i]*Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i]*Ei > oS.tol) and (oS.alphas[i] > 0)):j,Ej = selectJ(i, oS, Ei) #this has been changed from selectJrandalphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();if (oS.labelMat[i] != oS.labelMat[j]):L = max(0, oS.alphas[j] - oS.alphas[i])H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])else:L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)H = min(oS.C, oS.alphas[j] + oS.alphas[i])if L==H: print "L==H"; return 0eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] #changed for kernelif eta >= 0: print "eta>=0"; return 0oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/etaoS.alphas[j] = clipAlpha(oS.alphas[j],H,L)updateEk(oS, j) #added this for the Ecacheif (abs(oS.alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; return 0oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])#update i by the same amount as jupdateEk(oS, i) #added this for the Ecache                    #the update is in the oppostie directionb1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,i] - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[i,j]b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,j]- oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[j,j]if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2else: oS.b = (b1 + b2)/2.0return 1else: return 0def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)):    #full Platt SMOoS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup)iter = 0entireSet = True; alphaPairsChanged = 0while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):alphaPairsChanged = 0if entireSet:   #go over allfor i in range(oS.m):        alphaPairsChanged += innerL(i,oS)print "fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)iter += 1else:#go over non-bound (railed) alphasnonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]for i in nonBoundIs:alphaPairsChanged += innerL(i,oS)print "non-bound, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)iter += 1if entireSet: entireSet = False #toggle entire set loopelif (alphaPairsChanged == 0): entireSet = True  print "iteration number: %d" % iterreturn oS.b,oS.alphas

提取特征以及使用SVM训练测试代码

# -*- coding: cp936 -*-
"""
基于支持向量机的邮件分类系统
使用0,1标记词的出现与否
author :luchi
data :1025/11/29
"""
import re
from math import *
from SVMKernel import *
#切割文本,统计词频
def splitText(bigString):wordlist={}rtnList=[]wordFreqList={}#分词listofTokens=re.split(r'\W*',bigString)length=len(listofTokens)for token in listofTokens:if  not wordlist.has_key(token):wordlist[token]=1rtnList.append(token)else:wordlist[token]+=1wordFreqList[token]=float(wordlist[token])/lengthreturn rtnList,wordFreqList#统计单词反文档频率
def docFre(word):fre=0for i in range(1,26):if word in re.split(r'\W*',open('spam/%d.txt' % i).read()):fre+=1return float(fre)/25#特征词提取,这里面使用TF-IDF方法def extractFeature(textType):docList=[];classList=[];fullText=[]wordTFIDF={}#每个类测试邮件一共有25封for i in range(1,26):wordlist,wordFreqList=splitText(open(textType+'/%d.txt' % i).read())fullText.append(wordlist)for word in wordFreqList:wordIDF=docFre(word)wordTFIDFValue=wordIDF*wordFreqList[word]if not  wordTFIDF.has_key(word):wordTFIDF[word]=wordTFIDFValueelse :wordTFIDF[word]+=wordTFIDFValuesortedWordTFIDF=sorted(wordTFIDF.iteritems(),key=lambda asd:asd[1],reverse=True)#选取前100个词为分类词keywords=[word[0] for word in sortedWordTFIDF[:100]]return keywords#对一个邮件词集构建特征向量(使用0,1表示存在与否)
def extaxtDocFeatureVec(text,keyword):vec=[]for i,word in enumerate(keyword):if word in text:vec.append(1)else :vec.append(0)return vec#抽取所有邮件的特征向量
def extactFeatureVec():hamWordsVec=extractFeature('ham')spamWordsVec=extractFeature('spam')wordVecs=[]classList=[]for i in range(1,26):wordlistHam,wordFreqList=splitText(open('ham/%d.txt' % i).read())wordlistSpam,wordFreqList=splitText(open('spam/%d.txt' % i).read())vecHam=extaxtDocFeatureVec(wordlistHam,hamWordsVec)vecSpam=extaxtDocFeatureVec(wordlistSpam,spamWordsVec)wordVecs.append(vecHam)classList.append(1)wordVecs.append(vecSpam)classList.append(-1)
##    print wordVecs
##    print classListreturn wordVecs,classList#使用SVM训练数据并使用交叉测试测试正确率
def textSpam(k1=1.3):dataArr,labelArr=extactFeatureVec()trainDataArr=dataArr[:40]trainLabelArr=labelArr[:40]b,alphas = smoP(trainDataArr, trainLabelArr, 200, 0.0001, 10000, ('rbf', k1)) #C=200 importantdatMat=mat(trainDataArr); labelMat = mat(trainLabelArr).transpose()svInd=nonzero(alphas.A>0)[0]sVs=datMat[svInd] #get matrix of only support vectorslabelSV = labelMat[svInd];print "there are %d Support Vectors" % shape(sVs)[0]testDataMat=mat(dataArr[39:-1])testLabel=labelArr[39:-1]
##    testLabel[2]=testLabel[2]*-1m,n = shape(testDataMat)errorCount = 0for i in range(m):kernelEval = kernelTrans(sVs,testDataMat[i,:],('rbf', k1))predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + bif sign(predict)!=sign(testLabel[i]): errorCount += 1print "the training error rate is: %f" % (float(errorCount)/m)if __name__=='__main__':textSpam()

测试结果如下:

iteration number: 8
there are 38 Support Vectors
the training error rate is: 0.000000

可以看出,SVM对于分类是具有很好的性能,这也是SVM强大之处,本例中使用了100维向量,但是SVM对更高维的数据也有很好的作用,然后我选取了15个数据作为训练数据,检测的失败率是22%,所以说SVM方法还是需要训练数据支持的

代码和测试数据都在附件

参考文献:

http://blog.csdn.net/v_july_v/article/details/7624837

李航 《统计学习方法》

Peter Harrington 《Machine Learning in Action》

SVM实战之垃圾邮件过滤相关推荐

  1. 实战7:机器学习实战之 随机森林、逻辑回归、SVM算法方法进行垃圾邮件过滤分类 代码+数据

    任务描述: 我们日常学习以及工作中会收到非常多的邮件,除了与学习工作相关的邮件,还会收到许多垃圾邮件,包括广告邮件.欺诈邮件等等.本任务通过邮件中包含的文本内容来判断该邮件是正常邮件(ham)还是垃圾 ...

  2. 【机器学习】贝叶斯算法详解 + 公式推导 + 垃圾邮件过滤实战 + Python代码实现

    文章目录 一.贝叶斯简介 二.贝叶斯公式推导 三.拼写纠正案例 四.垃圾邮件过滤案例 4.1 问题描述 4.2 朴素贝叶斯引入 五.基于朴素贝叶斯的垃圾邮件过滤实战 5.1 导入相关库 5.2 邮件数 ...

  3. 【机器学习实战】朴素贝叶斯应用之垃圾邮件过滤

    1.什么是朴素贝叶斯 2.贝叶斯公式 3.朴素贝叶斯常用的三个模型 4.朴素贝叶斯实现垃圾邮件过滤的步骤 5.垃圾邮件过滤实验: (一).准备收集好的数据集,并下载到本地文件夹 (二).朴素贝叶斯分类 ...

  4. 朴素贝叶斯算法实现垃圾邮件过滤(Python3实现)

    目录 1.朴素贝叶斯实现垃圾邮件分类的步骤 2.邮件数据 3.代码实现 4.朴素贝叶斯的优点和缺点 1.朴素贝叶斯实现垃圾邮件分类的步骤 (1)收集数据:提供文本文件. (2)准备数据:将文本文件解析 ...

  5. 垃圾邮件过滤python_手把手教你用 python 和 scikit-learn 实现垃圾邮件过滤

    原标题:手把手教你用 python 和 scikit-learn 实现垃圾邮件过滤 雷锋网按:本文原文来自一篇国外大神的,由雷锋网字幕组 彭艳蕾.林立宏 两位组员共同编译完成,转载请注明出处. 文本挖 ...

  6. 禁用outlook2007 垃圾邮件过滤功能

    (1)如果是Outlook 2007,修改 (如果没有就创建): HKEY_CURRENT_USER\Software\Policies\Microsoft\office\12.0\outlook D ...

  7. 【数据挖掘】贝叶斯公式在垃圾邮件过滤中的应用 ( 先验概率 | 似然概率 | 后验概率 )

    文章目录 I . 垃圾邮件过滤 需求 及 表示方法 II . 贝叶斯方法 步骤 1 : 提出假设 III . 贝叶斯方法 步骤 2 : 计算垃圾邮件假设概率 IV . 贝叶斯方法 步骤 2 : 计算正 ...

  8. php贝叶斯,php – 将单个概率与朴素贝叶斯垃圾邮件过滤相结合

    我正在尝试通过分析我已经积累的语料库来生成垃圾邮件过滤器. 我已经实现了代码来计算消息是垃圾邮件的概率,因为它包含一个特定的单词,通过从wiki实现以下公式: 我的PHP代码 public funct ...

  9. 使用线性SVM实现对垃圾邮件分类

    本文内容 代码地址 使用线性SVM实现对垃圾邮件分类 (1)问题描述: (2)实现过程: 实验小结: 代码地址 代码地址 使用线性SVM实现对垃圾邮件分类 (1)问题描述: ​ 编程实现一个垃圾邮件S ...

最新文章

  1. 2021年春季学期-信号与系统-第八次作业参考答案-第十二小题
  2. 技术文:微信小程序和服务器通信-WebSocket
  3. Jenkins Gitlab持续集成打包平台搭建
  4. koa --- restful规范及其栗子
  5. JavaScript 游动层onmouseover
  6. 【perl】simpleHTTP
  7. 视频的播放的用例设计点
  8. Spring Framework 官方文档学习(一)介绍
  9. Luogu3205 合唱队
  10. 泰凌微TLSR8258烧录
  11. 使用Grafana搭建监控系统
  12. 计算机中的数学【集合论】现代数学的共同基础
  13. 2.1 A k-armed Bandit Problem
  14. mac解压缩命令大全
  15. Android SqlDelight详解和Demo例子
  16. Java制作简单小画板
  17. Docker(24)- docker login 命令详解
  18. asp 支付宝 企业版 接口 支持网银接口 ,网银直接支付
  19. css animate动画demo
  20. 通过DHTS(分布式散列表系统)引导P2P控制传输

热门文章

  1. r6220 虚拟服务器,自动配置设置友好 R6220系统体验_NETGEAR R6220_网络设备评测-中关村在线...
  2. 2020年美容师(初级)证考试题库及美容师(初级)试题解析
  3. treegrid 与java交互_针对dhtmlX当中的treegrid在java类当中的封装实现的步骤(后台代码)...
  4. 修复 matlab 文件关联
  5. java实现CRC16 MODBUS校验算法
  6. 敬请各位付费专栏的订阅者花点时间移步帮忙做个调查,谢谢!
  7. 关于Java中的日期与时间的相关类说明详解
  8. 爬虫实战-用beautifulsoup提取丁香园论坛的回复内容
  9. 武汉地图json文件_echarts各省市地图js和json文件
  10. Win7提速如何进行磁盘清理和碎片整理