【建模算法】KNN分类(Python实现)
01 算法用途
KNN(K- Nearest Neighbor)法即K最邻近法,最初由 Cover和Hart于1968年提出,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。KNN算法的核心思想是,如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
02 实例分析
用经典iris莺尾花标准数据集为例,最后一列class为分类结果,一共有3类,标签设置为(0,1,2),把前面几个特征指标作为自变量进行类别判定。
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass6.42.85.62.225.02.33.31.014.92.54.51.724.93.11.50.10
03 原理解析
KNN的算法原理通俗易懂,已知带有不同类别标签的数据,有测试数据要根据特征进⾏判别。计算测试数据到所有已知标签数据的距离,确定⼀个值K,将距离从小到⼤排序,识别前K个最⼩距离(通常采⽤欧式距离)分别属于哪类,统计前K个最小距离中不同类别的个数,哪类出现次数最多就被判定为哪类。
算法步骤:
(1)计算待测试数据与各训练数据的距离
(2)将计算的距离进行由小到大排序
(3)找出距离最小的k个值
(4)计算找出的值中每个类别的频次
(5) 返回频次最高的类别
Python源码:
import csv
import random
import numpy as np
import operator
from sklearn.neighbors import KNeighborsClassifier
def openfile(filename):
"""
打开数据集,进行数据处理
:param filename: 数据集的路径
:return: 返回数据集的数据,标签,以及标签名
"""
with open(filename) as csv_file:
data_file = csv.reader(csv_file)
temp = next(data_file)
n_samples = int(temp[0])
n_features = int(temp[1])
target_names = np.array(temp[2:])
data = np.empty((n_samples, n_features))
target = np.empty((n_samples,), dtype=np.int)
for i, j in enumerate(data_file):
data[i] = np.asarray(j[:-1], dtype=np.float64)
target[i] = np.asarray(j[-1], dtype=np.int)
return data, target, target_names
def random_number(data_size):
"""
该函数使用shuffle()打乱一个包含从0到数据集大小的整数列表。因此每次运行程序划分不同,导致结果不同
改进:
可使用random设置随机种子,随机一个包含从0到数据集大小的整数列表,保证每次的划分结果相同。
:param data_size: 数据集大小
:return: 返回一个列表
"""
number_set = []
for i in range(data_size):
number_set.append(i)
random.shuffle(number_set)
return number_set
def split_data_set(data_set, target_data, rate=0.25):
"""
说明:分割数据集,默认数据集的25%是测试集
:param data_set: 数据集
:param target_data: 标签数据
:param rate: 测试集所占的比率
:return: 返回训练集数据、训练集标签、训练集数据、训练集标签
"""
train_size = int((1-rate) * len(data_set))
data_index = random_number(len(data_set))
x_train = data_set[data_index[:train_size]]
x_test = data_set[data_index[train_size:]]
y_train = target_data[data_index[:train_size]]
y_test = target_data[data_index[train_size:]]
return x_train, x_test, y_train, y_test
def data_diatance(x_test, x_train):
"""
:param x_test: 测试集
:param x_train: 训练集
:return: 返回计算的距离
"""
distances = np.sqrt(sum((x_test - x_train) ** 2))
return distances
def knn(x_test, x_train, y_train, k):
"""
:param x_test: 测试集数据
:param x_train: 训练集数据
:param y_train: 测试集标签
:param k: 邻居数
:return: 返回一个列表包含预测结果
"""
predict_result_set=[]
train_set_size = len(x_train)
distances = np.array(np.zeros(train_set_size))
for i in x_test:
for indx in range(train_set_size):
distances[indx] = data_diatance(i, x_train[indx])
sorted_dist = np.argsort(distances)
class_count = {}
for i in range(k):
sort_label = y_train[sorted_dist[i]]
class_count[sort_label]=class_count.get(sort_label, 0) + 1
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
predict_result_set.append(sorted_class_count[0][0])
return predict_result_set
def score(predict_result_set, y_test):
"""
:param predict_result_set: 预测结果列表
:param y_test: 测试集标签
:return: 返回测试集精度
"""
count = 0
for i in range(0, len(predict_result_set)):
if predict_result_set[i] == y_test[i]:
count += 1
score = count / len(predict_result_set)
return score
if __name__ == "__main__":
iris_dataset = openfile('iris_data.csv')
x_train, x_test, y_train, y_test = split_data_set(iris_dataset[0], iris_dataset[1])
result = knn(x_test,x_train, y_train, 6)
print("原有标签:", y_test)
print("预测结果:", np.array(result))
score = score(result, y_test)
print("手写KNN算法准确率:%.2f" % score)
knn = KNeighborsClassifier(n_neighbors=6)
knn.fit(x_train, y_train)
prediction=[]
for i in range(len(x_test)):
prediction+=list(knn.predict(x_test[i].reshape(1,4)))
print("原有标签:",y_test)
print("预测结果:",np.array(prediction))
print("sklearn库自带KNN算法准确率:{:.2f}".format(knn.score(x_test,y_test)))
以上分别使用原理手写代码和sklearn库自带KNN算法。因为随机选取训练集和测试集,每次结果可能不一样,运行三次结果如下:
第一次运行:
第二次运行:
第三次运行:
可见用原理手写KNN算法和sklearn库自带KNN算法效果是一样的,有时候会更好。
Original: https://blog.csdn.net/baidu/article/details/124388603
Author: 果州做题家
Title: 【建模算法】KNN分类(Python实现)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/662344/
转载文章受原作者版权保护。转载请注明原作者出处!