【机器学习】KNN算法

KNN是什么?

邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。

KNN是有监督学习

KNN原理?

如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别

KNN实现步骤?

1.数据预处理
2.采用合适的数据结构储存训练集和测试集
3.设定参数,如K
4.维护一个大小为k的的按距离由大到小的优先级队列
5.遍历训练元组集,计算当前训练元组与测试元组的距离
6.将当前训练元组存入优先级队列
7.计算优先级队列中k 个元组的多数类,并将其作为测试元组的类别
8.测试元组集测试完毕后计算误差率,继续设定不同的k值重新进行训练,最后取误差率最小的k 值

适用场景:

二分类、多分类问题。如鸢尾花的品种、邮件过滤、文本分类等。

优点:

1.简单,易于理解,易于实现,无需估计参数,无需训练;
2. 适合对稀有事件进行分类;
3.特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好。

缺点:

1.样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。
2.计算量较大
3.可理解性差,无法给出像决策树那样的规则
4.最大的缺点是无法给出数据的内在含义。

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)]

# 新增一个样本
new_data = [np.random.random() * 10, np.random.random() * 10]

plt.scatter(a_x, a_y, color='r', marker='+')
plt.scatter(b_x, b_y, color='b', marker='x')
plt.scatter(new_data[0],new_data[1],color='g')
plt.show()

在这里插入图片描述

新增样本绿色点属于哪一类?
说人话:看这个点周围距离最近的k个点属于哪个类的个数比较多,这个点就属于哪个类。

KNN算法流程

  1. 准备数据,对数据进行预处理
  2. 选用合适的数据结构存储训练数据和测试元组
  3. 设定参数,如k
  4. 维护一个大小为k的的按距离由大到小的优先级队列,用于存储最近邻训练元组。随机从训练元组中选取k个元组作为初始的最近邻元组,分别计算测试元组到这k个元组的距离,将训练元组标号和距离存入优先级队列
  5. 遍历训练元组集,计算当前训练元组与测试元组的距离,将所得距离L 与优先级队列中的最大距离Lmax
  6. 进行比较。若L>=Lmax,则舍弃该元组,遍历下一个元组。若L < Lmax,删除优先级队列中最大距离的元组,将当前训练元组存入优先级队列。
  7. 遍历完毕,计算优先级队列中k 个元组的多数类,并将其作为测试元组的类别。
  8. 测试元组集测试完毕后计算误差率,继续设定不同的k值重新进行训练,最后取误差率最小的k 值。

KNN算法实现(Python)

一维

# 训练样本
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])

# 测试样本
test_data = np.array([np.random.random() * 10])

# 计算两点间的距离
distance = []
for data in train_data:
    distance.append(np.sqrt(np.sum((data - test_data) ** 2)))
print(distance)

# 求最近的K个点
K = 3
nearest = np.array(distance).argsort()

# K个点的标签
k_label = [train_label[i] for i in nearest[:K]]
print(k_label)

# 求K个点中哪个标签最多,以得出测试样本的标签
votes = Counter(k_label)
result = votes.most_common()[0][0]
print(result)

二维(多维)

import numpy as np
import matplotlib.pyplot as plt
from collections import Counter

# 训练样本
train_data = np.array([np.random.random() * 10 for i in range(20)])
train_data = train_data.reshape((10, 2))
# 训练标签,目标值
train_label = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

# 测试样本
test_data = np.array([np.random.random() * 10, np.random.random() * 10])

distance = np.sqrt(np.sum((train_data - test_data) ** 2, axis=1))

# 求最近的K个点
K = 3
nearest = np.array(distance).argsort()

# K个点的标签
k_label = [train_label[i] for i in nearest[:K]]
print(k_label)

# 求K个点中哪个标签最多,以得出测试样本的标签
votes = Counter(k_label)
result = votes.most_common()[0][0]
print(result)

sklearn中的KNN

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 训练样本
train_data = np.array([np.random.random() * 10 for i in range(20)])
train_data = train_data.reshape((10, 2))
# 训练标签,目标值
train_label = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

# 测试样本
test_data = np.array([np.random.random() * 10, np.random.random() * 10])
knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(train_data, train_label)

print(knn_clf.predict(test_data.reshape(1, -1)))

准确度计算

我们把数据集分为测试集与训练集,用训练集训练模型,再用测试集给模型测试得出准确度。

from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
# 训练样本
x = np.array([np.random.random() * 10 for i in range(20)])
x = x.reshape((10, 2))
# 训练标签,目标值
y = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

train_data, test_data , train_label , test_lable = train_test_split(x, y, test_size=0.2,random_state=666)

knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(train_data, train_label)

print(knn_clf.predict(test_data))
print(knn_clf.score(test_data, test_lable))

超参数

在机器学习的上下文中,超参数是在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据。通常情况下,需要对超参数进行优化,给学习机选择一组最优超参数,以提高学习的性能和效果。

寻找最好的K值

搞一个数组[1,…,n]作为K,每个K计算score,准确度score最高时的K最好。

最好的距离权重

[‘uniform’,‘distance’],看用哪个准确度高

最好的P值

best_k=0
best_p=0
best_score=0.0
for k in range(1,9):
    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_lable)
        if score>best_score:
            best_score=score
            best_k=k
            best_p=p

print(best_k,best_p,best_score)

网格搜索:寻找最佳超参数

program_grid = [
    {
        'weights': ['uniform'],
        'n_neighbors': [i for i in range(1, 10)]
    },
    {
        'weights': ['distance'],
        'n_neighbors': [i for i in range(1, 9)],
        'p': [i for i in range(1, 6)],
    }
]

from sklearn.model_selection import GridSearchCV
knn_clf = KNeighborsClassifier()
grid_search = GridSearchCV(knn_clf, program_grid, verbose=1)
grid_search.fit(train_data, train_label)
grid_search.best_params_  # 最好的超参数
grid_search.best_score_  # 最高准确度
knn_clf = grid_search.best_estimator_  # 最佳模型

归一化

把数据弄到一定范围内

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randint(1, 100, 100)

# 最值归一化
x_scaler = x - np.min(x) / (np.max(x) - np.min(x))
print(x_scaler)

# 向量最值归一化
X = np.random.randint(1, 100, 200)
X = np.array(X, dtype='float')
X = X.reshape(100, 2)

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]))

plt.scatter(X[:, 0], X[:, 1])
plt.show()

sklearn中的归一化

from sklearn import datasets

iris = datasets.load_iris()
x = iris.data
y = iris.target

# sklearn中的均方差归一化
from sklearn.preprocessing import StandardScaler

stsr = StandardScaler()

# 数据集分割
from sklearn.model_selection import train_test_split

train_data, test_data, train_label, test_lable = train_test_split(x, y, test_size=0.2, random_state=666)

from sklearn.neighbors import KNeighborsClassifier

knnc = KNeighborsClassifier()

# 归一化
stsr.fit(train_data)
std_train_data = stsr.transform(train_data)
std_test_data = stsr.transform(test_data)

knnc.fit(std_train_data, train_label)
print(knnc.score(std_test_data, test_lable))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值