1 K近邻算法K-Nearest Neighbor (k-NN)
KNN是通过测量不同特征值之间的距离进行分类。它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
算法描述:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
#coding:utf-8
from numpy import *
import operator
##给出训练数据以及对应的类别
def createDataSet():
group = array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5]])
labels = ['A','A','B','B']
return group,labels
###通过KNN进行分类
def classify(input,dataSet,label,k):
dataSize = dataSet.shape[0]
####计算欧式距离
diff = tile(input,(dataSize,1)) - dataSet
sqdiff = diff ** 2
squareDist = sum(sqdiff,axis = 1)###行向量分别相加,从而得到新的一个行向量
dist = squareDist ** 0.5
##对距离进行排序
sortedDistIndex = argsort(dist)##argsort()根据元素的值从大到小对元素进行排序,返回下标
classCount={}
for i in range(k):
voteLabel = label[sortedDistIndex[i]]
###对选取的K个样本所属的类别个数进行统计
classCount[voteLabel] = classCount.get(voteLabel,0) + 1
###选取出现的类别次数最多的类别
maxCount = 0
for key,value in classCount.items():
if value > maxCount:
maxCount = value
classes = key
return classes
#-*-coding:utf-8 -*-
import sys
sys.path.append("...文件路径...")
import KNN
from numpy import *
dataSet,labels = KNN.createDataSet()
input = array([1.1,0.3])
K = 3
output = KNN.classify(input,dataSet,labels,K)
print("测试数据为:",input,"分类结果为:",output)
KNN用来回归预测(KNN for Regression (Prediction))
2 朴素贝叶斯 Naïve Bayes
2.1 贝叶斯法则 (Bayes Rule)
P
(
Y
∣
X
1
,
.
.
.
.
X
n
)
=
P
(
X
1
,
.
.
.
.
X
n
∣
Y
)
P
(
Y
)
P
(
X
1
,
.
.
.
X
n
)
P(Y|X_1,....X_n)=\frac{P(X_1,....X_n|Y)P(Y)}{P(X_1,...X_n)}
P(Y∣X1,....Xn)=P(X1,...Xn)P(X1,....Xn∣Y)P(Y)
P
(
X
1
,
.
.
.
.
X
n
∣
Y
)
P(X_1,....X_n|Y)
P(X1,....Xn∣Y)是似然概率,
P
(
Y
)
P(Y)
P(Y)是先验概率,
P
(
X
1
,
.
.
.
X
n
)
P(X_1,...X_n)
P(X1,...Xn)是标准化常量。
2.2 贝叶斯假设
在给定标签(类别Y)的情况下,所有的特征都是独立的。也就是说:
P
(
X
1
,
.
.
.
.
X
n
∣
Y
)
=
∏
i
=
1
n
P
(
X
i
∣
Y
)
P(X_1,....X_n|Y)=\prod_{i=1}^nP(X_i|Y)
P(X1,....Xn∣Y)=i=1∏nP(Xi∣Y)
2.3练习
整理数据:
预测数据
X
′
=
(
O
u
t
l
o
o
k
=
S
u
n
n
y
,
T
e
m
p
e
r
a
t
u
r
e
=
C
o
o
l
,
H
u
m
i
d
i
t
y
=
H
i
g
h
,
W
i
n
d
=
S
t
r
o
n
g
)
X^{'}=(Outlook=Sunny,Temperature=Cool,Humidity=High,Wind=Strong)
X′=(Outlook=Sunny,Temperature=Cool,Humidity=High,Wind=Strong)属于什么标签。
P
(
O
u
t
l
o
o
k
=
S
u
n
n
y
∣
Y
e
s
)
=
2
9
P(Outlook=Sunny|Yes)=\frac{2}{9}
P(Outlook=Sunny∣Yes)=92
P
(
T
e
m
p
e
r
a
t
u
r
e
=
C
o
o
l
∣
Y
e
s
)
=
3
9
P(Temperature=Cool|Yes)=\frac{3}{9}
P(Temperature=Cool∣Yes)=93
P
(
H
u
m
i
d
i
t
y
=
H
i
g
h
∣
Y
e
s
)
=
3
9
P(Humidity=High|Yes)=\frac{3}{9}
P(Humidity=High∣Yes)=93
P
(
W
i
n
d
=
S
t
r
o
n
g
∣
Y
e
s
)
=
3
9
P(Wind=Strong|Yes)=\frac{3}{9}
P(Wind=Strong∣Yes)=93
P
(
Y
e
s
)
=
9
14
P(Yes)=\frac{9}{14}
P(Yes)=149
P
(
O
u
t
l
o
o
k
=
S
u
n
n
y
∣
N
o
)
=
3
5
P(Outlook=Sunny|No)=\frac{3}{5}
P(Outlook=Sunny∣No)=53
P
(
T
e
m
p
e
r
a
t
u
r
e
=
C
o
o
l
∣
N
o
)
=
1
5
P(Temperature=Cool|No)=\frac{1}{5}
P(Temperature=Cool∣No)=51
P
(
H
u
m
i
d
i
t
y
=
H
i
g
h
∣
N
o
)
=
4
5
P(Humidity=High|No)=\frac{4}{5}
P(Humidity=High∣No)=54
P
(
W
i
n
d
=
S
t
r
o
n
g
∣
N
o
)
=
3
5
P(Wind=Strong|No)=\frac{3}{5}
P(Wind=Strong∣No)=53
P
(
N
o
)
=
5
14
P(No)=\frac{5}{14}
P(No)=145
结果:
P
(
Y
e
s
∣
X
′
)
≈
P
(
O
u
t
l
o
o
k
=
S
u
n
n
y
∣
Y
e
s
)
P
(
T
e
m
p
e
r
a
t
u
r
e
=
C
o
o
l
∣
Y
e
s
)
P
(
H
u
m
i
d
i
t
y
=
H
i
g
h
∣
Y
e
s
)
P
(
W
i
n
d
=
S
t
r
o
n
g
∣
Y
e
s
)
P
(
Y
e
s
)
=
0.0053
P(Yes|X^{'})\approx P(Outlook=Sunny|Yes)P(Temperature=Cool|Yes)P(Humidity=High|Yes)P(Wind=Strong|Yes)P(Yes)=0.0053
P(Yes∣X′)≈P(Outlook=Sunny∣Yes)P(Temperature=Cool∣Yes)P(Humidity=High∣Yes)P(Wind=Strong∣Yes)P(Yes)=0.0053
P
(
N
o
∣
X
′
)
≈
P
(
O
u
t
l
o
o
k
=
S
u
n
n
y
∣
N
o
)
P
(
T
e
m
p
e
r
a
t
u
r
e
=
C
o
o
l
∣
N
o
)
P
(
H
u
m
i
d
i
t
y
=
H
i
g
h
∣
N
o
)
P
(
W
i
n
d
=
S
t
r
o
n
g
∣
N
o
)
P
(
N
o
)
=
0.0206
P(No|X^{'})\approx P(Outlook=Sunny|No)P(Temperature=Cool|No)P(Humidity=High|No)P(Wind=Strong|No)P(No)=0.0206
P(No∣X′)≈P(Outlook=Sunny∣No)P(Temperature=Cool∣No)P(Humidity=High∣No)P(Wind=Strong∣No)P(No)=0.0206
因为
P
(
N
o
∣
X
′
)
>
P
(
Y
e
s
∣
X
′
)
P(No|X^{'})>P(Yes|X^{'})
P(No∣X′)>P(Yes∣X′),所以最终的标签是No。
2.4 实战项目·垃圾邮件分类(NB for Spam Filtering)
项目源代码和数据地址:
链接:https://github.com/Miraclemin/NB_for_Spam_Filtering 有帮助的话记得star一下,谢谢你。
构造正常邮件词汇表和垃圾邮件词汇表,词汇表的结构是一个二元组,key是单词,value是出现次数。对测试集中的每封邮件做一个统计,统计其中影响分类最重要的15个单词,求出其每个单词对垃圾邮件和正常邮件分类做的影响值。之后利用贝叶斯模型,15个词属于垃圾邮件的概率和正常邮件的概率,如果15个词在垃圾邮件占比大于90%则判定属于垃圾邮件。计算准确率方面,测试集中,名字低于1000的为正常邮件,这样既可以算正确率。
P
(
x
1
,
x
2
.
.
.
.
,
x
15
∣
Y
)
=
P
(
x
1
∣
Y
)
P
(
x
2
∣
Y
)
.
.
.
P
(
x
15
∣
Y
)
=
∏
i
=
1
15
P
(
x
i
∣
Y
)
P(x_1,x_2....,x_{15}|Y)=P(x_1|Y)P(x_2|Y)...P(x_{15}|Y)=\prod_{i=1}^{15}P(x_i|Y)
P(x1,x2....,x15∣Y)=P(x1∣Y)P(x2∣Y)...P(x15∣Y)=i=1∏15P(xi∣Y)
实战步骤:
(1)对训练集用结巴分词,并用停用表进行简单过滤,然后使用正则表达式过滤掉邮件中的非中文字符;
(2)分别保存正常邮件与垃圾邮件中出现的词有多少邮件出现该词,得到两个词典。例如词”疯狂”在8000封正常邮件中出现了20次,在8000封垃圾邮件中出现了200次;
(3)对测试集中的每一封邮件做同样的处理,并计算得到
P
(
s
∣
w
)
P(s|w)
P(s∣w)最高的15个词,在计算过程中,若该词只出现在垃圾邮件的词典中,则令
P
(
w
∣
n
)
=
0.01
P(w|n)=0.01
P(w∣n)=0.01,反之亦然;若都未出现,则令
P
(
s
∣
w
)
=
0.4
P(s|w)=0.4
P(s∣w)=0.4。PS.这里做的几个假设基于前人做的一些研究工作得出的。
(4)对得到的每封邮件中重要的15个词利用式2计算概率,若概率>>阈值α(一般设为0.9),则判为垃圾邮件,否则判为正常邮件。
核心代码(python)
#通过计算每个文件中p(s|w)来得到对分类影响最大的15个词
def getTestWords(self,testDict,spamDict,normDict,normFilelen,spamFilelen):
wordProbList={}
for word,num in testDict.items():
if word in spamDict.keys() and word in normDict.keys():
#该文件中包含词个数
pw_s=spamDict[word]/spamFilelen
pw_n=normDict[word]/normFilelen
ps_w=pw_s/(pw_s+pw_n)
wordProbList.setdefault(word,ps_w)
if word in spamDict.keys() and word not in normDict.keys():
pw_s=spamDict[word]/spamFilelen
pw_n=0.01
ps_w=pw_s/(pw_s+pw_n)
wordProbList.setdefault(word,ps_w)
if word not in spamDict.keys() and word in normDict.keys():
pw_s=0.01
pw_n=normDict[word]/normFilelen
ps_w=pw_s/(pw_s+pw_n)
wordProbList.setdefault(word,ps_w)
if word not in spamDict.keys() and word not in normDict.keys():
#若该词不在脏词词典中,概率设为0.4
wordProbList.setdefault(word,0.47)
sorted(wordProbList.items(),key=lambda d:d[1],reverse=True)[0:15]
return (wordProbList)
#计算贝叶斯概率
def calBayes(self,wordList,spamdict,normdict):
ps_w=1
ps_n=1
for word,prob in wordList.items() :
print(word+"/"+str(prob))
ps_w*=(prob)
ps_n*=(1-prob)
p=ps_w/(ps_w+ps_n)
# print(str(ps_w)+""+str(ps_n))
return p
运行代码时出现错误
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xd2 in position 302: invalid continuation byte
参考博文https://blog.csdn.net/qinguo123/article/details/78884213后半段。
利用命令tpye~~~