机器学习02 K近邻模型
K近邻的主要思想就是首先将数据分为训练数据集和测试数据集。然后用训练数据集来建立模型。通过判断测试数据到其他训练数据集中的欧式距离然后排序,选取离测试数据点最近的K个数据,然后根据这K个数据的类别及多数表决原则,来决定此测试点的数据类别。
接下来是具体实例:
这里仅用一个测试点来说明问题。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib as mpl
from collections import Counter
#data加载数据
iris=load_iris()
df=pd.DataFrame(iris.data,columns=iris.feature_names)
df['label']=iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
plt.scatter(df[:50]['sepal length'],df[:50]['sepal width'],label='0')
plt.scatter(df[50:100]['sepal length'],df[50:100]['sepal width'],label='1')
plt.xlabel=('sepal length')
plt.ylabel=('sepal width')
plt.legend()
plt.show()
data=np.array(df.iloc[:100,[0,1,-1]])
X,y=data[:,:-1],data[:,-1]
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2)
class KNN:
def __init__(self, X_train, y_train, n_neighbors=3, p=2):
"""
parameter: n_neighbors 临近点个数
parameter: p 距离度量
"""
self.n = n_neighbors
self.p = p
self.X_train = X_train
self.y_train = y_train
def predict(self, X):
# 取出n个点
knn_list = []
for i in range(self.n):
#np.linalg.norm用来进行范数运算,ord=2表示二范数
dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
#将测试点与取出的n个数之间的距离,以及这n个数的类别存储在knn_list中
knn_list.append((dist, self.y_train[i]))
#再从剩下的X_train-n个数据中进行依次距离计算,
#将这些数据中与测试点距离小于刚刚取出来的k个数据中的距离时,进行替换。
#达到取出来的k个数据到测试点的距离为最短距离的目的。
for i in range(self.n, len(self.X_train)):
#max(knn_list,key=lambda x:x[0])是把knn_list中的数据按照x[0]第一位素(距离)进行比较取最大值,再取其索引赋值给max_index。
max_index = knn_list.index(max(knn_list, key=lambda x: x[0]))
#计算测试点到剩余数据的距离
dist = np.linalg.norm(X - self.X_train[i], ord=self.p)
#如果knn_list中的最大距离的点的距离大于其余点计算的距离,
if knn_list[max_index][0] > dist:
knn_list[max_index] = (dist, self.y_train[i])
# 统计
#将knn_list中的k[-1](即,点的类别)进行统计。
knn = [k[-1] for k in knn_list]
#Counter()可以用于计数,会返回一个key为列表的值,value为该值出现个数,的对
count_pairs = Counter(knn)
# max_count = sorted(count_pairs, key=lambda x: x)[-1]
#将count_pairs中的数据排序,最终将[-1][0]即出现次数最多的类别给max_count
max_count = sorted(count_pairs.items(), key=lambda x: x[1])[-1][0]
return max_count
def score(self, X_test, y_test):
right_count = 0
n = 10
#zip即打包为元组
for X, y in zip(X_test, y_test):
label = self.predict(X)
if label == y:
right_count += 1
return right_count / len(X_test)
#clf即classifier的缩写
clf = KNN(X_train, y_train)
clf.score(X_test, y_test)
test_point = [5.0,3.5]
#输出测试点的分类
print('Test Point: {}'.format(clf.predict(test_point)))
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.plot(test_point[0], test_point[1], 'bo', label='test_point')
plt.legend()
plt.show()
至此我们可以简单了解了KNN模型的原理。但是为了提高K近邻搜索的效率,可以考虑用特殊的结构来存储训练数据。即KD树。