一、什么是机器学习

机器学习(Machine Learning)是人工智能(AI)的一个分支,它使计算机系统能够利用数据和算法自动学习和改进其性能。简单来说其实就三个步骤:

(1) 收集和准备数据

(2) 建立并优化模型

(3) 将模型运用到需求之中做出预测和辅助决策

二、十种常用的机器学习算法

本篇主要分享K近邻算法(K-Nearest Neighbors,简称 KNN)

2.1 什么是K近邻算法

K 近邻算法属于监督学习的一种,核心思想是通过计算待分类样本与训练集中各个样本的距离,找到距离最近的 K 个样本,然后根据这 K 个样本的类别或值来预测待分类样本的类别或值。

K近邻算法(K-Nearest Neighbors,简称 KNN)是机器学习中比较简单且常用的分类和回归算法。

2.2  KNN算法的基本原理

(1)计算距离:运用距离公式计算样本间的距离;

常用的距离公式有:

欧式距离:

现有样本a(x1,y1),b(x2,y2),故二维欧式距离公式为:

d = \sqrt{(x_{1} - x_{2})^{2} + (y_{1} - y_{2})^{2}}

n维欧式距离公式形式与二维差异不大,一一对应平方差求和即可。

曼哈顿距离是两点在坐标轴方向上距离的绝对值之和,现有样本a(x1,y1),b(x2,y2),故二维曼哈顿距离公式为:

d = \left | x_{1} - x_{2} \right | + \left | y_{1} - y_{2} \right |

n维曼哈顿距离公式形式与二维差异不大,一一对应求差的绝对值再求和即可。

(2)选择 K 个最近邻:根据计算出的距离,选择距离最近的 K 个样本。

(3)解决问题与需求:对于分类问题,K 个最近邻中出现次数最多的类别即为待分类样本的类别;对于回归问题,K 个最近邻的值的平均值即为待分类样本的值。

2.3 KNN算法实现

2.3.1 收集与准备数据

在机器学习中,数据越多,模型越优秀,得到的结果越准确。在拿到数据后要进行观察,浏览数据是什么样的,为接下来的数据处理做好准备,这里给出所用数据的片段。

这是一个为大一新生分宿舍的模型所用数据,第一列为旅行里程(km),第二列为每日游戏时长(h),第三列为每日学习时长(h),第四列为标签,用来区分不同类型的学生,1为不贪玩的学生,2为一般学生,3为贪玩学生。目标是将同一类型的学生分到一个宿舍,接下来我们来看看数据分布的可视化。

import matplotlib.pyplot as plt
import numpy as np

data = np.loadtxt('datingTestSet2.txt')
data_1 = data[data[:,-1] == 1]
data_2 = data[data[:,-1] == 2]
data_3 = data[data[:,-1] == 3]

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.scatter(data_1[:,0],data_1[:,1],zs=data_1[:,2],c='red',marker='o')
ax.scatter(data_2[:,0],data_2[:,1],zs=data_2[:,2],c='green',marker='^')
ax.scatter(data_3[:,0],data_3[:,1],zs=data_3[:,2],c='blue',marker='+')
ax.set(xlabel='x',ylabel='y',zlabel='z')
plt.show()

这是可视化的实现代码,其中使用matplotlib和numpy这两个python的第三方库进行实现,np.loadtxt()语句来读取txt类型的文件,在使用data[:,-1]对每一列数据进行提取,plt.figure()创建一个画板,ax = plt.axes(projection='3d')将二维图转变为三维图,ax.scatter()语句绘制自己需要的散点图(),ax.set()设置轴的名称,plt.show()展示图片。展示结果如下:

(2)建立模型

由于数据比较工整,没有奇怪字符,故简单处理即可,一般情况下需根据数据不同进行不同程度的清洗操作,比如数据标准化,数据归一化,去除特殊字符等。该数据已经准备完成,现在开始建立训练模型,首先判断问题类型,KNN算法常见的问题类型有分类问题和回归问题,该问题并不要求准确的值,而是把学生分到一个宿舍,显然属于分类问题。

scikit-learn实现了两个不同的最近邻分类器: KNeighborsClassifier 分类器根据每个查询点的k个最近邻实现学习,其中k是用户指定的整数值。 RadiusNeighborsClassifier分类器根据每个训练点的固定半径内的邻居数实现学习,其中r是用户指定的浮点值。KNeighborsClassifier 中的K近邻分类是最常用的分类方法。k值的最佳选择是高度依赖于数据的:一般来说,较大的  会抑制噪声的影响,但使分类边界不那么清晰。在数据不均匀采样的情况下, RadiusNeighborsClassifier中基于半径的近邻分类是更好的选择。用户指定一个固定的半径,以便在稀疏的邻居中使用更少的最近邻居来进行分类。详细参考官方文档:https://scikit-learn.org.cn/view/85.html#1.6.2%20%E6%9C%80%E8%BF%91%E9%82%BB%E5%88%86%E7%B1%BB

接下来是这个问题的简单模型代码实现(注:代码中的数据未进行标准化或归一化)

import numpy as np
from sklearn.neighbors import KNeighborsClassifier

data = np.loadtxt('datingTestSet2.txt')
x = data[:,:-1]
y = data[:,-1]
neigh = KNeighborsClassifier(n_neighbors=25)
neigh.fit(x,y)

print(neigh.predict([[63275,8.385879,1.669485]]))

predict_data = [[33553,12.591889,0.686581],
                [9744,11.470364,0.760461],
                [2355,6.539397,0.462065],
                [42403,11.293017,0.207976]]
print(neigh.predict(predict_data))

其中导入了 KNeighborsClassifier 分类器,然后读取数据,对数据进行切片,x表示取所有行和从第0列到倒数第2列的所有特征,y表示取所有行和最后一列的所有特征,然后使用分类器进行分类(注:25不是最优参数,还需调试,predict_data中的数据也不是标准测试集,是从训练集中随机取的数据,用来自测模型是否能够正确分类,仅作例子参考),使用切分好的特征(x)和标签数据(y)来训练KNN模型。

(3)解决问题与需求

在这个简单模型的预测下可以得知,这五位同学的类型,再按照类型进行宿舍分配即可。结果如下:

2.3.2 鸢尾花的识别

第一步,收集与准备数据

训练集(片段):

测试集:

观察数据可以看到,萼片长的数值要远大于花瓣宽和萼片宽,可能会对模型训练造成影响,故对每一列同类型的数据进行标准化(在上面的分宿舍案例中也应该进行数据标准化或者归一化,这里偷个小懒),在sklearn的processing包中,有一个scale模块就是专门对数据进行标准化,我们直接导入并引用即可。

import pandas as pd
from sklearn.preprocessing import scale
from sklearn.neighbors import KNeighborsClassifier

# 读取数据
train_data = pd.read_excel('鸢尾花训练数据.xlsx')
test_data = pd.read_excel('鸢尾花测试数据.xlsx')

# 数据处理
train_x = train_data[['萼片长(cm)','萼片宽(cm)','花瓣长(cm)','花瓣宽(cm)']]
train_y = train_data['类型_num']
test_x = test_data[['萼片长(cm)','萼片宽(cm)','花瓣长(cm)','花瓣宽(cm)']]
test_y = test_data['类型_num']

# 标准化
# 训练集
data_train = pd.DataFrame()
data_train['萼片长标准化(cm)'] = scale(train_data['萼片长(cm)'])
data_train['萼片宽标准化(cm)'] = scale(train_data['萼片宽(cm)'])
data_train['花瓣长标准化(cm)'] = scale(train_data['花瓣长(cm)'])
data_train['花瓣宽标准化(cm)'] = scale(train_data['花瓣宽(cm)'])

# 测试集
data_test = pd.DataFrame()
data_test['萼片长标准化(cm)'] = scale(test_data['萼片长(cm)'])
data_test['萼片宽标准化(cm)'] = scale(test_data['萼片宽(cm)'])
data_test['花瓣长标准化(cm)'] = scale(test_data['花瓣长(cm)'])
data_test['花瓣宽标准化(cm)'] = scale(test_data['花瓣宽(cm)'])

数据处理完成后就可以进行下一步操作。

第二步,建立并优化模型

使用KNeighborsClassifier分类器并设置参数,将处理好的数据和标签放入模型进行训练。这里需要进行模型优化也就是调整参数(调参),这里已经找到了最优参数,但是实际使用时需要自己调参找到最优参数,才能使模型性能更加优越。

# 训练模型(使用sklearn中的knn模块)
knn = KNeighborsClassifier(n_neighbors=8)    # 经调试,当k值为8时为最优
knn.fit(data_train,train_y)

到此模型训练已经结束,接下来就是测试模型。print()函数可打印出预测结果,knn.score()即可给出模型训练的准确率。

# 模型测试
train_pred = knn.predict(data_train)
train_score = knn.score(data_train,train_y)
# print(train_pred)
print(train_score)

自测模型未出现明显问题就可以使用测试集进行进一步测试与预测。

test_pred = knn.predict(data_test)
test_score = knn.score(data_test,test_y)
# print(test_pred)
print(test_score)

第三步,解决问题与需求

该问题需求为识别鸢尾花,根据花的数据进行识别即可,模型训练完成后在训练集上的准确率可达98.5%,在测试集上的准确率可达88.9%,可以见得模型训练比较成功,大部分鸢尾花识别都能保证准确识别。

完整代码如下:

import pandas as pd
from sklearn.preprocessing import scale
from sklearn.neighbors import KNeighborsClassifier

# 读取数据
train_data = pd.read_excel('鸢尾花训练数据.xlsx')
test_data = pd.read_excel('鸢尾花测试数据.xlsx')

# 数据处理
train_x = train_data[['萼片长(cm)','萼片宽(cm)','花瓣长(cm)','花瓣宽(cm)']]
train_y = train_data['类型_num']
test_x = test_data[['萼片长(cm)','萼片宽(cm)','花瓣长(cm)','花瓣宽(cm)']]
test_y = test_data['类型_num']

# 标准化
# 训练集
data_train = pd.DataFrame()
data_train['萼片长标准化(cm)'] = scale(train_data['萼片长(cm)'])
data_train['萼片宽标准化(cm)'] = scale(train_data['萼片宽(cm)'])
data_train['花瓣长标准化(cm)'] = scale(train_data['花瓣长(cm)'])
data_train['花瓣宽标准化(cm)'] = scale(train_data['花瓣宽(cm)'])

# 测试集
data_test = pd.DataFrame()
data_test['萼片长标准化(cm)'] = scale(test_data['萼片长(cm)'])
data_test['萼片宽标准化(cm)'] = scale(test_data['萼片宽(cm)'])
data_test['花瓣长标准化(cm)'] = scale(test_data['花瓣长(cm)'])
data_test['花瓣宽标准化(cm)'] = scale(test_data['花瓣宽(cm)'])

# 训练模型(使用sklearn中的knn模块)
knn = KNeighborsClassifier(n_neighbors=8)    # 经调试,当k值为8时为最优
knn.fit(data_train,train_y)

# 模型测试
train_pred = knn.predict(data_train)
train_score = knn.score(data_train,train_y)
# print(train_pred)
print(f'在训练集上的准确率为:{train_score}')

test_pred = knn.predict(data_test)
test_score = knn.score(data_test,test_y)
# print(test_pred)
print(f'在测试集上的准确率为:{test_score}')

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐