2.1K-近邻算法概述
knn的基本思想:需要确定一个样本A的类别,可以计算出它与所有训练样本的距离,然后找出和该样本距离最小的k个样本,对这k个样本的类别进行统计,样本数最多的那个类别就是我们A的类别了。简单的说,K-近邻算法采用测量不同特征值之间的距离方法进行分类。
2.1.1K-近邻算法优缺点
优点:精度高、对异常值不敏感、无数据输入假定.
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
2.1.2K-近邻算法工作原理
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前K个最相似的数据,这就是K-近邻算法的K的出处,通常K是不大于20的整数。最后,选择K个最相似数据中出现次数最多的分类,作为新数据的分类。
2.1.3K-近邻算法的一般流程
(1)收集数据:可以使用任何方法。
(2)准备数据:距离计算机所需要的数值,最好是结构化的数据格式。
(3)分析数据:可以使用任何方法。
(4)训练算法:此步骤不适用于K-近邻算法。
(5)测试算法:计算错误率。
(6)使用算法:首先需要输入样本数据和结构化的输出结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算机的分类执行后续的处理
2.2预测算法流程
knn没有需要求解的参数,没有训练过程,参数k由人工指定。对于分类问题,给定n个训练样本(xi,yi),xi为特征向量,yi为标签值。设定合适的参数k,类别数为c,待分类的样本为x。算法的预测流程如下:
(1)在训练数据中找出离x最近的k个样本,假设这些样本的集合为N。
(2)统计集合N中每类样本的数量Ci,i=0,1,2…,c-1。
(3)最终分类结果为argmaxCi,即样本数最多的那个类别。
在实现的时候还可以考虑样本的权重,即每个样本带有不同的样本权重,比如说这个权重和每个类样本数在总样本数占比有关,这种方法成为带权重的k近邻算法。
2.3KNN算法的应用场景
KNN算法的优点包括简单易懂、无需训练过程、适用于多类别问题等。KNN算法在许多领域中都有广泛的应用,KNN算法常见的应用场景如下:
分类问题:KNN算法可以用于分类问题,如文本分类、图像分类、语音识别等。通过比较待分类数据点与已知数据点之间的相似性,KNN可以将新的数据点分配到最相似的类别中。
回归问题:KNN算法也可以用于回归问题,如房价预测、股票价格预测等。通过计算最近邻数据点的平均值或加权平均值,KNN可以预测待分类数据点的数值属性。
推荐系统:KNN算法可以应用于推荐系统,根据用户之间的相似性来推荐相似兴趣的物品。通过比较用户之间的行为模式或兴趣偏好,KNN可以找到与当前用户最相似的一组用户,并向其推荐相似的物品。
异常检测:KNN算法可以用于检测异常数据点,如信用卡欺诈、网络入侵等。通过计算数据点与其最近邻之间的距离,KNN可以识别与大多数数据点不同的异常数据点。
文本挖掘:KNN算法可以用于文本挖掘任务,如文本分类、情感分析等。通过比较文本之间的相似性,KNN可以将新的文本数据点归类到相应的类别中。
图像处理:KNN算法可以应用于图像处理领域,如图像识别、图像检索等。通过比较图像之间的像素值或特征向量,KNN可以识别和检索相似的图像。
2.4常用距离公式
2.4.1曼哈顿距离
2.4.2欧式距离
2.5电影分类的例子
2.5.1数据的读取
data = pd.read_csv(r"./files/FBlocation/train.csv")
print(data.head())
2.5.2处理数据
data.query("x > 1.0 & y < 1.25 & y > 2.5 & y < 2.75")
time_value = pd.to_datetime(data["time"],unit="s") #秒
print(time_value)
time_value = pd.DataFrame(time_value) #年月日时分秒等变为{"year":2019,"month":01} 这样的字典格式数据
data["day"] = time_value.day
data["hour"] = time_value.hour
data["weekday"] = time_value.weekday
#删除一些特征
data = data.drop(["time"],axis=1)
place_count = data.groupby("place_id").count() #根据place_id分组,统计次数
tf = place_count[place_count.row_id > 3].reset_index()
data = data[data["place_id"].isin(tf.place_id)] #如果place_id > 3的数据保存,小于则去掉
y = data["place_id"]
x = data.drop(["place_id"],axis=0.25)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
2.5.3我们先不对数进行标准化,直接进行算法预测
knn = KNeighborsClassifier(n_neighbors=5)
#fit,predict,score
knn.fit(x_train,y_train)
#得出预测结果
y_predict= knn.predict(x_test)
print("预测的目标签入位置为",y_predict)
#得出正确率
correctRate = knn.score(x_test,y_test)
print(correctRate)
签入位置和预测正确率:
很差
2.5.4标准化后再进行算法预测
std = StandardScaler()
x_train_std = std.fit_transform(x_train)
# y_train_std = std.fit_transform(y_train)#已经fit转换过了,可以直接transform()
y_train_std = std.transform(y_train)
knn = KNeighborsClassifier(n_neighbors=5)
#fit,predict,score
knn.fit(x_train_std,y_train_std)
y_predict= knn.predict(x_test)
print("预测的目标签入位置为",y_predict)
#得出正确率
correctRate = knn.score(x_test,y_test)
print(correctRate) #
签入位置和预测正确率:
正确率达到 40.5%
2.6基于pytorch在MNIST数据集上实现数据分类
2.6.1获取MNIST数据集
import operator
import matplotlib.pyplot as plt
import numpy as np
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
batch_size = 100
train_dataset = datasets.MNIST(root='data', # 选择数据的根目录
train=True, # 选择训练集
transform=None, # 不使用任何数据预处理
download=True) # 从网络上下载图片
test_dataset = datasets.MNIST(root='data', # 选择数据的根目录
train=False, # 选择测试集
transform=None, # 不适用任何数据预处理
download=True) # 从网络上下载图片
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
print("train_data:", train_dataset.data.size())
print("train_labels:", train_dataset.data.size())
print("test_data:", test_dataset.data.size())
print("test_labels:", test_dataset.data.size())
图片内容展示:
digit = train_loader.dataset.data[0]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
print(train_loader.dataset.targets[0])
2.6.2准备数据
# 欧式顿距离计算
def e_distance(dataset_a, data_b):
return np.sqrt(np.sum(((dataset_a - np.tile(data_b, (dataset_a.shape[0], 1))) ** 2), axis=1))
# 曼哈顿距离计算
def m_distance(dataset_a, data_b):
return np.sum(np.abs(train_data - np.tile(test_data[i], (train_data.shape[0], 1))), axis=1)
2.6.3分析数据
def KNN_classify(k, dis_func, train_data, train_label, test_data):
num_test = test_data.shape[0] # 测试样本的数量
label_list = []
for idx in range(num_test):
distances = dis_func(train_data, test_data[idx])
nearest_k = np.argsort(distances)
top_k = nearest_k[:k] # 选取前k个距离
class_count = {}
for j in top_k:
class_count[train_label[j]] = class_count.get(train_label[j], 0) + 1
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
label_list.append(sorted_class_count[0][0])
return np.array(label_list)
def get_mean(data):
data = np.reshape(data, (data.shape[0], -1))
mean_image = np.mean(data, axis=0)
return mean_image
def centralized(data, mean_image):
data = data.reshape((data.shape[0], -1))
data = data.astype(np.float64)
data -= mean_image # 减去图像均值,实现领均值化
return data
if __name__ == '__main__':
2.6.4训练数据
# 训练数据
train_data = train_loader.dataset.data.numpy()
train_data = train_data.reshape(train_data.shape[0], 28 * 28)
# 归一化处理
mean_image = get_mean(train_data) # 计算所有图像均值
train_data = centralized(train_data, mean_image)
print('train_data shape:', train_data.shape)
train_label = train_loader.dataset.targets.numpy()
print('train_lable shape', train_label.shape)
2.6.5测试数据
# 测试数据
test_data = test_loader.dataset.data[:1000].numpy()
test_data = centralized(test_data, mean_image)
test_data = test_data.reshape(test_data.shape[0], 28 * 28)
print('test_data shape', test_data.shape)
test_label = test_loader.dataset.targets[:1000].numpy()
print('test_label shape', test_label.shape)
2.6.6训练得到准确率
# 训练
test_label_pred = KNN_classify(5, e_distance, train_data, train_label, test_data)
# 得到训练准确率
num_test = test_data.shape[0]
num_correct = np.sum(test_label == test_label_pred)
print(num_correct)
accuracy = float(num_correct) / num_test
print('Got %d / %d correct => accuracy: %f' % (num_correct, num_test, accuracy))
输出:
train_data: torch.Size([60000, 28, 28])
train_labels: torch.Size([60000, 28, 28])
test_data: torch.Size([10000, 28, 28])
test_labels: torch.Size([10000, 28, 28])
train_data shape: (60000, 784)
train_lable shape (60000,)
test_data shape (1000, 784)
test_label shape (1000,)
963
Got 963 / 1000 correct => accuracy: 0.963000
这个例子没有调参,所以咱们再看一个例子
2.7对鸢尾花iris数据集的k近邻算法分类及预测
2.7.1数据集简单介绍
· Iris (/ˈaɪrɪs/) 数据集是机器学习任务中常用的分类实验数据集,由Fisher在1936年整理。
· Iris :Anderson’s Iris data set, 中文名称:安德森鸢尾花数据集
· Iris 数据集一共包含150个样本,分3类,每类50个数据,每个数据包含4个特征。4个特征分别为: Sepal.Length(花萼长度)、Sepal.Width(花萼宽度)、Petal.Length(花瓣长度)、Petal.Width(花瓣宽度),特征值都为正浮点数,单位为厘米。根据4个特征预测鸢尾花属于 Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),Iris Virginica(维吉尼亚鸢尾)
数据集结构与数据大致如下:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
iris = load_iris()
print(iris)
其中前部分为特征: Sepal.Length(花萼长度)、Sepal.Width(花萼宽度)、Petal.Length(花瓣长度)、Petal.Width(花瓣宽度)后部分为标签:Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),Iris Virginica(维吉尼亚鸢尾)(分别利用0,1,2代替原有标签名)。
2.7.2引入库,加载数据集,定义区分特征与标记
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
iris = load_iris()
#date为特征数据集
data = iris.get("data")
#target为标记数据集
target = iris.get("target")
2.7.3 划分测试集与训练集,定义k值
#划分测试集占20%
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0)
#定义k值
KNN = KNeighborsClassifier(n_neighbors=5)
2.7.4评价模型的准确率,使用模型预测未知种类样本
test_score = KNN.score(x_test, y_test)
print("模型的准确率:", test_score)
#定义三个测试数据
X1 = np.array([[1.9, 2.8, 4.7, 1.1], [5.8, 2.7, 4.1, 1.5], [3.6, 2.5, 3.1, 2.1]])
prediction = KNN.predict(X1)
#根据预测值找出对应花名
a = iris.get("target_names")[prediction]
print("第一朵花的种类为:", a[0])
print("第二朵花的种类为:", a[1])
print("第三朵花的种类为:", a[2])
结果:
*k近邻算法对样本的分类及其依赖于k的取值。k值不可取过大或过小。
- k值越大,模型的偏差越大,对噪声数据越不敏感,当k值很大时,可能造成欠拟合;
- k值越小,模型的方差就会越大,当k值太小,就会造成过拟合。
-
*k的取值因满足以下两个条件:
1.近邻点要有相同/相近的类别
2.特征维度的尺度(范围)要具备一致性
现在来调参,改变K的值:
当K=120时:
当K=100时:
当K=50时:
分析:
当k值越来越大至接近样本总数150时它的准确率越来越低,这是k值过大造成的欠拟合现象。
当k值越来越小至接近50时它的准确率越来越高,如果k值在继续变小的话可能会造成的过拟合现象。