机器学习教程二:K近邻算法实现数据分类
scikit-learn中的KNN
scikit-learn是一个用于机器学习的Python库,它提供了丰富的工具和算法,用于数据预处理、特征工程、模型选择和评估等任务。
scikit-learn提供了包括分类、回归、聚类、降维、异常检测和模型选择等多种机器学习算法。其中包括常见的算法,如线性回归、逻辑回归、决策树、支持向量机、随机森林、K最近邻等。
安装方法
推荐安装在conda虚拟环境上,在windows电脑中,win键+r输入cmd打开终端,使用下面指令进行安装:
conda activate youEnvName
pip install scikit-learn
KNeighborsClassifier
sklearn.neighbors模块中的KNeighborsClassifier类实现了KNN算法。
参数说明:
- n_neighbors :int, default=5。默认情况下用于邻居查询的邻居数。
- weights:{‘uniform’, ‘distance’}, callable or None, default=’uniform。权重默认是uniform(统一),有三个选项,可以是uniform(统一)、distance(距离)或者用户自定义的函数。统一表示所有临近点的权重都是相同;距离表示距离近的临近点所占的权重更大,距离远的临近点所占的权重更;用户自定义的函数,它接受一个距离数组,并返回一个包含权重的相同形状的数组。
- algorithm:{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’。这个表示计算最近邻所使用的算法,默认是’auto’,表示根据数据选择最合适的算法;ball_tree将使用BallTree;kd_tree将使用KDTree;’brute’将使用蛮力搜索。
- leaf_size:int, default=30。传递给BallTree或KDTree的叶大小。这会影响构造和查询的速度,以及存储树所需的内存。最佳值取决于问题的性质。
- p:float,default=2。闵可夫斯基距离度量公式,当p=1时,这相当于使用曼哈顿距离;当p=2时,表示使用欧氏距离;对于任意p,使用minkowski_distance(p)。
- metric:str or callable, default=’minkowski’。用于距离计算的度量。默认值为“minkowski”。
- metric_params:dict,default=None。距离公式的其他参数。
- n_jobs:int , default=None。要为邻居搜索运行的并行作业数,默认为1。如果为-1,那么CPU的所有cores都用于并行工作。
函数说明:
fit(X, y)
: 从训练数据集中拟合K最近邻分类器。它接受特征矩阵X和目标向量y作为输入,并使用这些数据训练K最近邻模型。返回值是一个K近邻分类器。get_metadata_routing()
: 获取此对象的元数据路由。这个函数返回有关对象元数据的信息,例如对象在训练过程中使用的数据和配置。get_params(deep=True)
: 获取这个估计器的参数。它返回估计器的当前参数设置,可以选择是否返回深层嵌套的参数。kneighbors([X, n_neighbors, return_distance])
: 寻找一个点的K个最近邻居。它接受一个样本矩阵X、邻居数量n_neighbors和是否返回距离的参数,并返回与给定点最近的邻居的索引和(可选地)距离。kneighbors_graph([X, n_neighbors, mode])
: 计算X中点的K个(加权)邻居的图形。它接受一个样本矩阵X、邻居数量n_neighbors和模式参数,并返回一个表示点之间邻居关系的图形(稀疏矩阵)。predict(X)
: 预测提供数据的类标签。它接受一个数据集X,并使用已训练的K最近邻分类器对数据进行预测,并返回预测的类标签。predict_proba(X)
: 返回测试数据X的概率估计值。它接受一个数据集X,并使用已训练的模型对每个类别的概率进行估计,并返回这些概率。score(X, y ,sample_weight)
: 返回给定测试数据和标签的平均准确率。它接受测试数据X、标签y和(可选的)样本权重,并计算模型在给定数据上的平均准确率。set_params(**params)
: 设置这个估计器的参数。它接受参数字典params,并将估计器的参数设置为给定值。set_score_request(*[, sample_weight])
: 请求传递给score
方法的元数据。这个方法允许在评分过程中传递额外的元数据信息,例如样本权重。
其中fit()、predict()、predict_proda()和score()函数使用频繁,需要铭记。
正态分布数据分类
我们分为准备数据集,处理数据集,构建分类器,结果打分四个步骤来完成正态分布数据的分类。
准备数据集
使用numpy库来完成正态分布数据的创建,使用matplotlib库来完成数据的可视化。写出下面的代码。
import numpy as np
import matplotlib.pyplot as plt
# 创建数据
np.random.seed(0) # 设置随机种子,以便结果可复现
def createDatabase():
# 第一组数据,loc表示横坐标均值为5,纵坐标均值为2,scale表示标准差为0.5,szie表示生成100个样本,每个样本里面有两个维度,分别是横坐标和纵坐标。
data1 = np.random.normal(loc=[5, 2], scale=1, size=(100, 2))
data2 = np.random.normal(loc=[5, -2], scale=1, size=(100, 2))
data3 = np.random.normal(loc=[2, 0], scale=0.8, size=(100, 2))
data=np.concatenate((data1,data2,data3),axis=0)
labels = [1] * 100 + [2] * 100 + [3] * 100
return data,labels
def showDatabase(data1,data2,data3):
# 可视化数据
plt.scatter(data1[:, 0], data1[:, 1], color='red', label='Group 1')
plt.scatter(data2[:, 0], data2[:, 1], color='blue', label='Group 2')
plt.scatter(data3[:, 0], data3[:, 1], color='green', label='Group 3')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Data Visualization')
# 显示数据的标签
plt.legend()
plt.show()
if __name__=='__main__':
#创建训练集
data,labels=createDatabase()
#展示训练集
showDatabase(data[:100,:],data[100:200,:],data[200:300,:])
得到下面的结果。
处理数据集
处理数据集主要是最数据进行归一化处理,对数据进行归一化可以帮助K最近邻(KNN)算法更准确地计算样本之间的距离。这是因为KNN算法的核心思想是根据样本之间的距离来确定最近的邻居,从而进行分类或回归预测。对于上面的例子可能不是很明显,我们来举一个其他的例子。
假设有一个数据集包含两个特征:收入(范围从1万到100万)和年龄(范围从20到80)。现在我们要使用KNN算法对这个数据集进行分类,其中目标是根据收入和年龄预测一个人是否会购买某个产品(二分类问题)。
如果不对数据进行归一化,收入的范围远远超过年龄的范围。这意味着在计算样本之间的距离时,收入这个特征将对距离计算产生更大的影响。这可能会导致年龄这个特征在KNN算法中的权重较小,对分类结果的影响较小。
通过对数据进行归一化,将收入和年龄的特征范围缩放到相同的尺度,例如[0, 1]范围内。这样,收入和年龄将具有相似的权重,而不会被数据范围的差异所主导。这将有助于更准确地计算样本之间的距离,提高KNN算法的性能和准确度。
通常情况下,我们会把数据归一化为[0,1]区间内,使用下面的公式对数据进行归一化。
x表示的是一个维度的特征,类似于上面数据的横坐标或者纵坐标。使用下面的代码对数据做归一化处理。
def normalDatabase(data):
# 计算数据的最小值和最大值
data_min = np.min(data, axis=0)
data_max = np.max(data, axis=0)
print(data_max)
print(data_min)
# 对 x 维度进行归一化
xNormalized = (data[:, 0] - data_min[0]) / (data_max[0] - data_min[0])
# 对 y 维度进行归一化
yNormalized = (data[:, 1] - data_min[1]) / (data_max[1] - data_min[1])
# 将 x 和 y 归一化后的数据合并为一个数组
xyNormalized = np.array(list(zip(xNormalized, yNormalized)))
return xyNormalized,data_min,data_max
使用showDatabase函数展示归一化后的数据。
构建分类器
使用sklearn.neighbors.KNeighborsClassifier作为分类器,给出下面代码:
def knnClassify(data,labels):
knnModel=KNN(n_neighbors=10)
knnModel.fit(data,labels)
return knnModel
然后创建测试点(10,0),(2,2)进行分类,代码如下:
if __name__=='__main__':
#创建分类器
knnModel=knnClassify(data=noramlData,labels=labels)
#创建测试集(10,0),(2,2)并进行归一化
test=[(10,0),(2,2)]
normalTest=[((10-minData[0])/(maxData[0]-minData[0]),(0-minData[1])/(maxData[1]-minData[1])),((1-minData[0])/(maxData[0]-minData[0]),(1-minData[1])/(maxData[1]-minData[1]))]
#对测试集数据进行预测
prediction=knnModel.predict(test)
print(f"{test[0]}属于类别{prediction[0]};{test[1]}属于类别{prediction[1]}")
#展示预测结果所属类别
preProba=knnModel.predict_proba(test)
print(f"{test[0]}属于类别1的概率为{[prediction[0][0]]},属于类别2的概率为{[prediction[0][1]]},属于类别3的概率为{[prediction[0][2]]}")
print(f"{test[1]}属于类别1的概率为{[prediction[1][0]]},属于类别2的概率为{[prediction[1][1]]},属于类别3的概率为{[prediction[2][2]]}")
得到下面的结果
结果打分
首先创建测试集,为训练集的一半,然后对测试集做归一化,对测试集做预测,得到准确率。
#创建测试集,为训练集数据量的一半
testData,testLabels=createDatabase()
testCutData = np.concatenate((testData[:50, :], testData[100:150, :], testData[200:250, :]), axis=0)
testCutLabels=np.concatenate((testLabels[:50],testLabels[100:150],testLabels[200:250]),axis=0)
print(testCutData.shape)
#对测试集数据进行归一化处理
xNormal=(testCutData[:,0]-minData[0])/(maxData[0]-minData[0])
yNormal=(testCutData[:,1]-minData[1])/(maxData[1]-minData[1])
xyNormal=list(zip(xNormal,yNormal))
#对测试集数据进行预测
scores=knnModel.score(xyNormal,testCutLabels)
print(f"测试集的准确率为{scores}")
得到下面的结果
参考链接
1.sklearn中的KNN参考
2.正态分布数据集原创