如果需要对检测器获取的关键点做分类的话,还需要了解特征工程相关算法,如KNN。之所以会用到KNN,是因为其伟大且渺小。虽然算法简单,但精确度真的很高。本篇文章会把KNN相关的绝大部分内容过一遍:
什么是KNN?
- 就是:根据你相邻的K个对象的类别,推断出你的类别。
算法具体原理
- 第一步:计算距离(欧氏距离或马氏距离),确定待分类的点的每一个特征与其他点的每一个特征的距离。将所有特征的距离相加再开方。距离公式如下:
- 第二步:按照距离升序排列。距离最近的排在前面,距离最远的排在后面。
- 第三步:取前K个距离最近的点,计算加权距离。之所以计算加权距离是因为比如前三个点离待分类点特别近,那么理应赋予更高的权重。但比如前五个点的后两个点,虽然也在前五,但是和待分类点的距离并不接近,因此需要赋予一个更低的权重。如果直接做算数平均那就跑偏了,距离也就没用参考价值了。
关于K的选取
- 太大:导致分类模糊。因为如果K过于接近整个数据集的个数,那么无论怎么分都是整个数据集的状态,导致任何数据进来都是相同的类。
- 太小:容易受到个例影响,波动较大。
- 那么如何选取呢,有两个方法:
- 经验法。也就是试一试。随便选一个K,跑一跑数据看看结果,接着不断向精度更高的方向微调K的值。
- 均方根误差。
代码实现 (数据集:提取码:bzlz)
- 如果自己实现:
import csv
import random
# 读取
with open(r"J:\KNN源码及数据集\prostate-cancer\Prostate_Cancer.csv") 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 = 6 # K取几
# 将传入单个字典
def knn(data):
res = [
{"result": train["diagnosis_result"], "distance": distance(data, train)} # 1.距离
for train in train_set
]
sorted(res, key=lambda item: item['distance']) # 2.排序-----升序
# 取前K个值
res2 = res[0:k]
# 加权平均(result是最终判据)
result = {'B': 0, 'M': 0}
# 总长度
sum_dist = 0
for r1 in res2:
sum_dist += r1['distance']
# 逐个分类加和
for r2 in res2:
result[r2["result"]] += 1 - r2["distance"] / sum_dist # 1 - r2["distance"] / sum_dist就是权重
print(result)
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 = correct + 1;
print(str(correct / len(test_set)))
- 如果调用官方API:
from sklearn.neighbors import KNeighborsClassifier import numpy as np import random import pandas as pd def knn(): K = 8 data=pd.read_csv(r"Prostate_Cancer.csv") n = len(data) // 3 test_set = data[0:n] train_set = data[n:] train_set = np.array(train_set) test_set = np.array(test_set) A = [i for i in range(0, len(train_set))] B = [i for i in range(2, 10)] C = [i for i in range(n)] D = [1] x_train = train_set[A] x_train = x_train[:, B] y_train = train_set[A] y_train = y_train[:, D] x_test = test_set[C] x_test = x_test[:, B] y_test = test_set[C] y_test = y_test[:, D] # 训练模型 model = KNeighborsClassifier(n_neighbors=K) model.fit(x_train, y_train) score = model.score(x_test, y_test) print("准确率为:", score) if __name__=='__main__': knn()