近朱者赤,近墨者黑
kNN中的k是指取几个近邻来预测分类规律
当k取1时,算法1-NN被称为最近邻分类器
最近邻分类器(1-NN)出错的概率
最近邻分类器出错的概率为
P
(
e
r
r
)
=
1
−
∑
c
∈
y
P
(
c
∣
x
)
P
(
c
∣
z
)
P(err)=1-\sum_{c \in y}{P(c|x)P(c|z)}
P(err)=1−∑c∈yP(c∣x)P(c∣z)
为何是这个公式呢?
∑
c
∈
y
P
(
c
∣
x
)
=
P
(
c
∣
z
)
\sum_{c \in y}P(c|x)=P(c|z)
∑c∈yP(c∣x)=P(c∣z)为分类器分类正确的概率,意思是分类的类型与最近邻的样本z分类的类型相同的概率,即分类正确的概率,这里的
y
y
y等同于总的分类类别,上述式子也等同于
∑
c
∈
y
P
(
c
∣
x
)
P
(
c
∣
z
)
\sum_{c \in y}P(c|x)P(c|z)
∑c∈yP(c∣x)P(c∣z)
那么分类错误的概率很明显就是:1-分类正确的概率
即
P
(
e
r
r
)
=
1
−
∑
c
∈
y
P
(
c
∣
x
)
P
(
c
∣
z
)
P(err)=1-\sum_{c \in y}P(c|x)P(c|z)
P(err)=1−∑c∈yP(c∣x)P(c∣z)
1-NN分类器的性能
我们可以用1-NN分类器和最理想的分类器进行对比,这里我们用贝叶斯最优分类器与1-NN分类器进行性能对比
贝叶斯最优分类器结果表示:
c
∗
=
a
r
g
m
a
x
c
∈
y
P
(
c
∣
x
)
c^*=argmax_{c \in y}P(c|x)
c∗=argmaxc∈yP(c∣x),大体意思就是说,分类出哪种类别的概率最高,那么分类结果就是哪种类别,这里最优的类别是
c
∗
c^*
c∗,同时我们也能得到,贝叶斯最优分类器出错的概率为
1
−
P
(
c
∗
∣
x
)
1-P(c^* | x)
1−P(c∗∣x)
推导过程:
P
(
e
r
r
)
=
1
−
∑
c
∈
y
P
(
c
∣
x
)
P
(
c
∣
z
)
这里
x
与
z
充分接近的话
,
那么
P
(
c
∣
x
)
充分接近
P
(
c
∣
z
)
故
P
(
e
r
r
)
≃
1
−
∑
c
∈
y
P
2
(
c
∣
x
)
有因为
P
(
c
∣
x
)
=
P
(
c
1
∣
x
)
+
P
(
c
2
∣
x
)
+
⋯
+
P
(
c
y
∣
x
)
故
P
(
c
∗
∣
x
)
≤
P
(
c
∣
x
)
故
P
(
e
r
r
)
≤
1
−
P
2
(
c
∗
∣
x
)
根据完全平方公式
P
(
e
r
r
)
≤
(
1
+
P
2
(
c
∗
∣
x
)
)
(
1
−
P
2
(
c
∗
∣
x
)
)
因为
P
(
c
∗
∣
x
)
≤
1
故
P
(
e
r
r
)
≤
2
(
1
−
P
2
(
c
∗
∣
x
)
P(err)=1-\sum_{c \in y}P(c|x)P(c|z) \\ 这里x与z充分接近的话,那么P(c|x)充分接近P(c|z) \\ 故P(err) \simeq 1-\sum_{c \in y}P^2(c|x) \\ 有因为P(c|x)=P(c_1|x)+P(c_2|x)+\cdots+P(c_y|x) \\ 故P(c^*|x) \leq P(c|x) \\ 故P(err) \leq 1-P^2(c^*|x) \\ 根据完全平方公式 P(err) \leq (1+P^2(c^*|x))(1-P^2(c^*|x)) \\ 因为P(c^*|x) \leq 1 \\ 故P(err) \leq 2(1-P^2(c^*|x)
P(err)=1−c∈y∑P(c∣x)P(c∣z)这里x与z充分接近的话,那么P(c∣x)充分接近P(c∣z)故P(err)≃1−c∈y∑P2(c∣x)有因为P(c∣x)=P(c1∣x)+P(c2∣x)+⋯+P(cy∣x)故P(c∗∣x)≤P(c∣x)故P(err)≤1−P2(c∗∣x)根据完全平方公式P(err)≤(1+P2(c∗∣x))(1−P2(c∗∣x))因为P(c∗∣x)≤1故P(err)≤2(1−P2(c∗∣x)
由上述可知贝叶斯最优分类器的出错概率为
1
−
P
(
c
∗
∣
x
)
1-P(c^*|x)
1−P(c∗∣x),由此可得,最近邻分类器虽然简单,但它的泛化错误率不超过贝叶斯最优分类器的错误率的两倍
通用步骤
①计算距离(常用欧几里得距离或马氏距离)
②升序排列
③取前k个
④加权平均
k的取值
k太大:导致分类模糊
k太小:受个例影响,波动较大
如何选取k
①经验
②均方根误差
import random
import csv
#读取
with open('Prostate_Cancer.csv','r') as file:
reader=csv.DictReader(file)
datas=[row for row in reader]
#分组
random.shuffle(datas)
n=len(datas)//3
test_set=datas[0:n]
train_set=datas[n:]
#KNN
#距离
def distance(d1,d2):
res=0
for key in ('radius','texture','perimeter','area','smoothness','compactness','symmetry','fractal_dimension'):
res+=(float(d1[key])-float(d2[key]))**2
return res**0.5
K=5
def knn(data):
#求解所有的距离
res=[
{'result':train['diagnosis_result'],'distance':distance(data,train)}
for train in train_set
]
#排序——升序
res=sorted(res,key=lambda item:item['distance'])
#取前k个
res2=res[0:K]
#加权平均
result={'B':0,'M':0}
#总的距离
sum=0
for r in res2:
sum+=r['distance']
for r in res2:
result[r['result']]+=1-r['distance']/sum
if result['B']>result['M']:
return 'B'
else:
return 'M'
#测试阶段
correct=0
for test in test_set:
result=test['diagnosis_result']
result2=knn(test)
if result==result2:
correct+=1
print("{:.2f}%".format(100*correct/len(test_set)))
癌症数据:
https://pan.baidu.com/s/1tAM4-PxIo1RBtNaBSgnnDQ?pwd=r5fi