knn算法详解(附练习代码)

KNN算法

KNN算法是一个用于对数据样本进行分类预测的算法

KNN算法就是根据样本之间的距离,来对新的样本来进行分类

计算过程:将新的样本点,与历史样本点中的每一个样本点进行距离的计算 取前k个距离最近的样本点的分类结果 取分类结果频次最好的二分类项作为新样本的分类。

网络搜索:手动指定不同参数的检索范围,通过网络搜索来寻找最优的超参数或者模型参数

K就表示要取离新样本最近的K个样本进行分类决策

通常我们只提供已有数据的 90 %作为训练样本来训练分类器 ,而使用其余的 10% 数据去测试分类器(测试数据占总数据比例不同也会影响到算法的测试结果),且数据划分是随机的

机械学习中的两种类型参数

  1. 超参数:

在训练之前,需要设置的参数

​ k值

​ 距离权重

​ P值

​ 对于寻找最优超参数的过程,称之为网络搜索

  1. 模型参数

    通过样本训练处的参数

数据归一化:将所有数据的量纲映射到同一尺度下。

​ 1.最值归一化:把所有数据映射到0~1上(数据边界确定,例如学生分数,最低0,最高1)

​ 2.均值方差归一化:把数据归一到均值为0,方差为1的分布中(数据分布没有明确边界,有可能存在极端数据值)

​ 优点:

简单,易于理解,易于实现,无需参数估计,无需训练;
对异常值不敏感(个别噪音数据对结果的影响不是很大);
适合对稀有事件进行分类;
适合于多分类问题(multi-modal,对象具有多个类别标签),KNN要比SVM表现要好;

​ 缺点:

​ 对测试样本分类时的计算量大,内存开销大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本;

​ 可解释性差,无法告诉你哪个变量更重要,无法给出决策树那样的规则;

​ K值的选择:最大的缺点是当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进;

​ KNN是一种消极学习方法、懒惰算法。

	KNN算法是一个用于对数据样本进行分类预测的算法
#KNN算法
import numpy as np
import matplotlib.pyplot as plt

a_x = [np.random.random() * 10 for i in range(10)]
a_y = [np.random.random() * 10 for i in range(10)]

b_x = [np.random.random() * 10 for i in range(10)]
b_y = [np.random.random() * 10 for i in range(10)]

plt.scatter(a_x,a_y,color = 'r' , marker='+')
plt.scatter(b_x,b_y,color = 'b' , marker='o')

plt.show()

#新增样本
new_data = [np.random.random() * 10 for i in range(10)]

plt.scatter(a_x,a_y,color = 'r' , marker='+')

plt.scatter(b_x,b_y,color = 'b' , marker='o')

plt.scatter(new_data[0],new_data[1],color='g')

plt.show()

#KNN就是根据样本点之间的距离进行分类
#K就表示要取离新样本点最近的K个样本进行分类决策


#实现
train_data = np.array([np.random.random() * 10 for i in range(10)])
train_label = np.array([0,0,0,0,0,1,1,1,1,1])

print('train_data:',train_data)

print('train_label:',train_label)

test_data = [np.random.random() * 10]

distances = []
#计算两个样本之间的距离
for data in train_data:
    distances.append(np.sqrt(np.sum((data - 				test_data)**2)))

#首先对样本进行从小到大的排序,并返回排序后的,原始数据的索引
nearest = np.array(distances).argsort()
K = 3
predict_label = [train_label[i] for i in nearest[:K]]

print(predict_label)

from collections import Counter
votes = Counter(predict_label)

​```
result = votes.most_common()[0][0]
​```

print(result)

tr_data = np.array([np.random.random() * 10 for i in range(20)])
tr_data = tr_data.reshape((10,2))

print(tr_data)

n_data = np.array([np.random.random() * 10,np.random.random() * 10])

print(n_data)

axis = 1 ,是以行为单位 , 如果不加就会将所有的数进行求和

s = np.sqrt(np.sum((tr_data - n_data)**2,axis = 1)).argsort()

print(s)

pre_label = [train_label[i] for i in s[:K]]

res = Counter(pre_label).most_common()[0][0]

print(res)

plt.scatter(tr_data[train_label==0,0] , tr_data[train_label==0,1],color = 'r' , marker='+')

plt.scatter(tr_data[train_label==1,0] , tr_data[train_label==1,1],color = 'r' , marker='+')

plt.scatter(n_data[0],n_data[1],color='g')

plt.show()

from knn import KNNClassfer

from sklean.neighbors import KNeighborsClassifier

knn_clf = KNNClassfer(k = 3)
knn_clf.fit(tr_data,train_label)
x = knn_clf.predit(n_data)
print(x)


封装的KNN算法
import numpy as np
from collections import Counter
class KNNClassfer:

    def __init__(self, k=3):
        self.k = k
    
    def fit(self, train_data, train_label):
        self.train_data = train_data
        self.train_label = train_label
    
    def predit(self, test_data):
        predit_label = [self.train_label[i] for i in np.sqrt(np.sum((self.train_data - test_data)**2,axis = 1)).argsort()[:self.k]]
        return Counter(predit_label).most_common()[0][0]


数据集分割
from sklearn.model_selection import trai_test_spit

#加载数据
x = iris.data

#查看类别的目标值
y = iris.target

#打乱下标
np.random.permutation(len(x))

#随机数种子,以666作为种子随机,是保证以后每次随机结果都是一样的
train_data, test_data, train_label, test_label = train_test_split(x , y, test_size = 0.2, random_state=666)

模型训练
from sklearn.metrics import accuracy_score

accuracy_score(test_label, predict_label)
knn_clf.score(test_data, test_label)


超参数:在模型运行前需要决定的参数
模型参数:算法过程中学习的参数

KNN中的超参数
	1.K值
	2.p值
	3.距离权重

找到最好的K值
best_k = 0
best_score = 0.0
for k in range(1,11):
    knn_clf = KNeighborsClassifier(n_neighbors = k)
    knn_clf.fit(train_data, train_label)
    score = knn_clf.score(test_data, test_label)
    if score > best_score:
        best_score = score
        best_k = k

print('best_k:',best_k)
print('best_score:',best_score) 

距离权重
best_k = 0
best_method = ''
best_score = 0.0
for method in ['uniform','distance']:
    for k in range(1,11):
        knn_clf = KNeighborsClassifier(n_neighbors = k)
        knn_clf.fit(train_data, train_label)
        score = knn_clf.score(test_data, test_label)
        if score > best_score:
            best_method = method
            best_score = score
            best_k = k

print('best_k:',best_k)
print('best_score:',best_score)
print('best_method:',best_method)

寻找最好的P参数
best_k = 0
best_p = 0
best_score = 0.0
for k in range(1,11):
    for p in range(1,6):
        knn_clf = KNeighborsClassifier(n_neighbors = k, weights='distance',p=p)
        knn_clf.fit(train_data, train_label)
        score = knn_clf.score(test_data, test_label)
        if score > best_score:
            best_p = p
            best_score = score
            best_k = k

print('best_k:',best_k)
print('best_score:',best_score)
print('best_p:',best_p)

网格搜索
grid_param = [
    {
        "weight":['uniform'],
        "n_neighbors":[i for i in range(1,11)]
    },
    {
        "weight":['distance'],
        "n_neighbors":[i for i in range(1,11)],
        "p":[i for i in range(1,6)]
    }
    
]


最值归一化

x_scaler = (x - np.min(x)) / (np.max(x) - np.min(x))

向量最值归一化
X = np.random.randint(1,100,200)
X = np.array(X ,dtype='float')
X = X.reshape(100,2)
#X[:,0] 是对第1列进行操作
X[:,0] = (X[:,0] - np.min(X[:,0])) /(np.max(X[:,0]) - np.min(X[:,0]))
X[:,1] = (X[:,1] - np.min(X[:,1])) /(np.max(X[:,1]) - np.min(X[:,1]))


均值方差归一化
(std_x - np.mean(std_x)) / np.var(std_x)


sklearn的归一化
from sklearn.preprocessing import StandardScaler

先进行归一化,再进行模型计算
std_train_data = std_scaler.transform(train_data)
std_test_data = std_scaler.transform(test_data)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值