本文概述
- 介绍
- 什么是k最近邻?
- 加载虹膜数据
- 分析你的数据
- 预处理数据
- KNN模型
- 评估模型
- 走得更远!
注意:你可能需要考虑学习使用Python进行机器学习的课程, 或者想了解ML的发展背景, 更多的读者可以考虑阅读本文。
介绍 机器学习源于计算机科学, 它主要研究可以从经验中学到的算法的设计。要学习, 他们需要具有某些属性的数据, 算法会根据这些属性尝试找到一些有意义的预测模式。机器学习任务主要可以归类为概念学习, 聚类, 预测建模等。机器学习算法的最终目标是能够在没有任何人工干预的情况下做出决策。预测库存或天气是机器学习算法的两个应用。
有各种机器学习算法, 例如决策树, 朴素贝叶斯, 随机森林, 支持向量机, K最近邻, K均值聚类等。
从机器学习算法的类别来看, 你今天要使用的是k近邻算法。
现在, 问题是什么是K最邻近算法, 所以让我们找出答案!
什么是k最近邻? KNN或K最邻近算法是一种有监督的学习算法, 通过监督, 它意味着在学习阶段它利用了训练数据的类别标签。它是一种基于实例的机器学习算法, 其中, 新数据点基于已存储的标记实例(数据点)进行分类。 KNN可用于分类和回归;但是, 它更广泛地用于分类目的。
KNN中的k是关键变量, 也称为超参数, 可帮助准确分类数据点。更准确地说, k是分类新数据点时希望从其投票的最近邻的数量。
文章图片
文章图片
图1. KNN源的可视化
你可以看到, 随着k的值从1增加到7, 具有某些数据点的两个类之间的决策边界变得更加平滑。
现在的问题是, 所有这些魔术是如何发生的, 每当新数据点进入时, 都会根据存储的数据点对其进行分类?
因此, 让我们通过以下方式快速了解它:
- 首先, 你加载所有数据并初始化k的值,
- 然后, 使用各种相似度或距离度量标准(例如曼哈顿距离(L1), 欧几里得距离(L2), 余弦相似度, 巴氏距离, 切比雪夫距离等)来计算存储的数据点与要分类的新数据点之间的距离。 。
- 接下来, 以降序或升序对距离值进行排序, 并确定前k个或下k个最近邻。
- 收集k个最近邻的标签, 并使用多数票或加权票对新数据点进行分类。根据在所有已存储数据点中得分最高的某个数据点, 为新数据点分配一个类别标签。
- 最后, 返回新实例的预测类。
KNN的缺点:首先, 为每个新数据点搜索最近邻的复杂性。其次, 确定k的值有时变得繁琐。最后, 也不清楚在计算最近邻时应使用哪种类型的距离度量。
理论足够了吗?因此, 让我们加载, 分析和了解你将在今天的小型教程中使用的数据。
加载虹膜数据 Iris数据集由150个样本组成, 具有三个类别, 即Iris-Setosa, Iris-Versicolor和Iris-Virginica。四个特征/属性有助于唯一地识别, 因为萼片长度, 萼片宽度, 花瓣长度和花瓣宽度是三类之一。
随意使用其他一些公共数据集或你的私有数据集。
Sklearn是一个机器学习python库, 广泛用于与数据科学相关的任务。它具有各种分类, 回归和聚类算法, 包括支持向量机, 随机森林, 梯度提升, k均值, KNN等。在sklearn下, 你有一个称为数据集的库, 其中有多个可用于不同任务的数据集包括Iris数据集, 所有这些数据集都可以直接安装。这是非常直观和直接的。因此, 让我们快速加载虹膜数据集。
from sklearn.datasets import load_iris
load_iris同时具有每个样本的数据和类标签。让我们快速提取所有内容。
data = http://www.srcmini.com/load_iris().data
数据变量将是形状为(150, 4)的numpy数组, 其中包含150个样本, 每个样本具有四个不同的属性。每个类别每个都有50个样本。
data.shape
(150, 4)
让我们提取类标签。
labels = load_iris().target
labels.shape
(150, )
接下来, 你必须结合数据和类标签, 为此, 你将使用一个名为NumPy的出色python库。 NumPy增加了对大型多维数组和矩阵的支持, 以及用于在这些数组上进行操作的大量高级数学函数的集合。因此, 让我们快速导入它!
import numpy as np
由于数据是二维数组, 因此你还必须将标签的形状重新调整为二维数组。
labels = np.reshape(labels, (150, 1))
现在, 你将使用numpy库中可用的连接函数, 并将使用axis = -1, 它将基于第二维进行连接。
data = http://www.srcmini.com/np.concatenate([data, labels], axis=-1)
data.shape
(150, 5)
接下来, 你将导入python的名为pandas的数据分析库, 当你希望以表格形式排列数据并对数据执行一些操作和操作时, 该库很有用。特别是, 它提供了用于操纵数值表和时间序列的数据结构和操作。
在今天的教程中, 你将广泛使用熊猫。
import pandas as pd
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'species']
dataset = pd.DataFrame(data, columns=names)
现在, 你将拥有同时具有所需数据和类标签的数据集数据框!
在进一步潜水之前, 请记住, labels变量将类标签作为数字值, 但是你将把这些数字值转换为花朵名称或种类。
为此, 你将仅选择类列, 并将三个数值中的每一个替换为相应的种类。你将使用inplace = True, 它将修改数据框数据集。
dataset['species'].replace(0, 'Iris-setosa', inplace=True)
dataset['species'].replace(1, 'Iris-versicolor', inplace=True)
dataset['species'].replace(2, 'Iris-virginica', inplace=True)
让我们打印数据集的前五行, 看看它是什么样子!
dataset.head(5)
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | 种类 | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 虹膜柔滑 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 虹膜柔滑 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 虹膜柔滑 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 虹膜柔滑 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 虹膜柔滑 |
文章图片
(资源)
让我们使用散点图可视化上面加载的数据, 以找出一个变量受另一变量影响的程度, 或者说两个变量之间有多少相关性。
你将使用matplotlib库使用散点图可视化数据。
import matplotlib.pyplot as plt
提示:你是否热衷于学习以不同方式显示python中数据的方式?然后查看python课程的数据可视化简介。
plt.figure(4, figsize=(10, 8))plt.scatter(data[:50, 0], data[:50, 1], c='r', label='Iris-setosa')plt.scatter(data[50:100, 0], data[50:100, 1], c='g', label='Iris-versicolor')plt.scatter(data[100:, 0], data[100:, 1], c='b', label='Iris-virginica')plt.xlabel('Sepal length', fontsize=20)
plt.ylabel('Sepal width', fontsize=20)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.title('Sepal length vs. Sepal width', fontsize=20)
plt.legend(prop={'size': 18})
plt.show()
文章图片
从上面的图中可以看出, 鸢尾花与萼片长度和萼片宽度之间存在高度相关性。另一方面, 鸢尾鸢尾和弗吉尼亚鸢尾之间的相关性较小。与密集的setosa相比, versicolor和virginica中的数据点分布更广。
让我们快速地绘制花瓣长度和花瓣宽度的图表。
plt.figure(4, figsize=(8, 8))plt.scatter(data[:50, 2], data[:50, 3], c='r', label='Iris-setosa')plt.scatter(data[50:100, 2], data[50:100, 3], c='g', label='Iris-versicolor')plt.scatter(data[100:, 2], data[100:, 3], c='b', label='Iris-virginica')
plt.xlabel('Petal length', fontsize=15)
plt.ylabel('Petal width', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.title('Petal length vs. Petal width', fontsize=15)
plt.legend(prop={'size': 20})
plt.show()
文章图片
即使谈到花瓣的长度和花瓣的宽度, 上图也显示了密集簇生的刚毛花的强相关性。
接下来, 为进一步验证关于花瓣长度和花瓣宽度如何相关的主张, 让我们为所有三种物种绘制一个相关矩阵。
dataset.iloc[:, 2:].corr()
花瓣长度 | 花瓣宽度 | |
---|---|---|
花瓣长度 | 1.000000 | 0.962865 |
花瓣宽度 | 0.962865 | 1.000000 |
我们还分别分析所有三个物种之间的相关性。
dataset.iloc[:50, :].corr() #setosa
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | |
---|---|---|---|---|
萼片长度 | 1.000000 | 0.742547 | 0.267176 | 0.278098 |
萼片宽度 | 0.742547 | 1.000000 | 0.177700 | 0.232752 |
花瓣长度 | 0.267176 | 0.177700 | 1.000000 | 0.331630 |
花瓣宽度 | 0.278098 | 0.232752 | 0.331630 | 1.000000 |
dataset.iloc[50:100, :].corr() #versicolor
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | |
---|---|---|---|---|
萼片长度 | 1.000000 | 0.525911 | 0.754049 | 0.546461 |
萼片宽度 | 0.525911 | 1.000000 | 0.560522 | 0.663999 |
花瓣长度 | 0.754049 | 0.560522 | 1.000000 | 0.786668 |
花瓣宽度 | 0.546461 | 0.663999 | 0.786668 | 1.000000 |
dataset.iloc[100:, :].corr() #virginica
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | |
---|---|---|---|---|
萼片长度 | 1.000000 | 0.457228 | 0.864225 | 0.281108 |
萼片宽度 | 0.457228 | 1.000000 | 0.401045 | 0.537728 |
花瓣长度 | 0.864225 | 0.401045 | 1.000000 | 0.322108 |
花瓣宽度 | 0.281108 | 0.537728 | 0.322108 | 1.000000 |
接下来, 让我们通过绘制直方图来可视化特征分布:
fig = plt.figure(figsize = (8, 8))
ax = fig.gca()
dataset.hist(ax=ax)
plt.show()
文章图片
花瓣长度, 花瓣宽度和萼片长度显示为单峰分布, 而萼片宽度显示为高斯分布。所有这些都是有用的分析, 因为这样你就可以考虑使用一种适用于这种分布的算法。
接下来, 你将分析所有四个属性是否都在同一范围内。这是ML的重要方面。熊猫数据框具有一个称为describe的内置函数, 该函数以表格格式为你提供数据的计数, 平均值, 最大值, 最小值。
dataset.describe()
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | |
---|---|---|---|---|
计数 | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
意思 | 5.843333 | 3.057333 | 3.758000 | 1.199333 |
小时 | 0.828066 | 0.435866 | 1.765298 | 0.762238 |
我 | 4.300000 | 2.000000 | 1.000000 | 0.100000 |
25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 |
50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 |
75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 |
最大值 | 7.900000 | 4.400000 | 6.900000 | 2.500000 |
即使大家都知道每个类别有50个样本, 即约占总分布的33.3%, 但还是让我们重新检查一下!
print(dataset.groupby('species').size())
species
Iris-setosa50
Iris-versicolor50
Iris-virginica50
dtype: int64
预处理数据 在加载数据并进行了广泛分析之后, 是时候准备你的数据了, 你可以将其提供给ML模型。在本节中, 你将通过两种方式预处理数据:标准化数据以及将数据分为训练集和测试集。
规范化你的数据 你可以通过两种方式对数据进行规范化:
- 标准化示例, 其中你分别标准化每个样本,
- 特征归一化, 你可以在所有样本中以相同的方式归一化每个特征。
好吧, 答案几乎一直都是。归一化你的数据是个好习惯, 因为它将所有样本置于相同的比例和范围内。当你拥有的数据不一致时, 对数据进行规范化至关重要。你可以使用上面学习的describe()函数检查不一致之处, 该函数将为你提供最大值和最小值。如果一个要素的最大值和最小值明显大于另一要素, 则将两个要素规格化为相同比例非常重要。
假设X是一个具有较大范围的特征, Y是第二个具有较小范围的特征。然后, 特征Y的影响可以被特征X的影响所压倒。在这种情况下, 标准化特征X和Y变得很重要。
在虹膜数据中, 不需要标准化。
让我们再次打印describe()函数, 看看为什么不需要任何规范化。
dataset.describe()
萼片长度 | 萼片宽度 | 花瓣长度 | 花瓣宽度 | |
---|---|---|---|---|
计数 | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
意思 | 5.843333 | 3.057333 | 3.758000 | 1.199333 |
小时 | 0.828066 | 0.435866 | 1.765298 | 0.762238 |
我 | 4.300000 | 2.000000 | 1.000000 | 0.100000 |
25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 |
50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 |
75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 |
最大值 | 7.900000 | 4.400000 | 6.900000 | 2.500000 |
分割数据 这是机器学习的另一个重要方面, 因为你的目标是建立一个足以在没有任何人工干预的情况下在测试环境中做出决策或对数据进行分类的模型。因此, 在行业中部署ML模型之前, 你需要确保模型可以很好地概括测试数据。
【Python机器学习入门开发权威简介】为此, 你需要一个培训和测试集。回到Iris数据, 你有150个样本, 你将在80%的数据上训练ML模型, 其余20%的数据将用于测试。
在数据科学中, 你经常会遇到一个名为” 过度拟合” 的术语, 这意味着你的模型已经很好地学习了训练数据, 但是无法对测试数据执行操作。因此, 将数据分为训练和测试或验证集通常可以帮助你了解模型是否过度拟合。
对于训练和测试集合拆分, 你将使用sklearn库, 该库具有一个内置的拆分功能, 称为train_test_split。因此, 让我们分割数据。
from sklearn.model_selection import train_test_split
train_data, test_data, train_label, test_label = train_test_split(dataset.iloc[:, :3], dataset.iloc[:, 4], test_size=0.2, random_state=42)
请注意, random_state是一个种子, 如果你更改数据分割的数字, 该种子也将使用random_state作为输入。但是, 如果你保持random_state不变并多次运行单元, 则数据拆分将保持不变。
让我们快速打印训练和测试数据的形状及其标签。
train_data.shape, train_label.shape, test_data.shape, test_label.shape
((120, 3), (120, ), (30, 3), (30, ))
最后, 是时候将数据提供给k近邻算法了!
KNN模型 在完成所有数据的加载, 分析和预处理之后, 现在该将数据输入到KNN模型中了。为此, 你将使用sklearn的内置函数neighbor, 其中包含一个名为KNeigborsClassifier的类。
让我们从导入分类器开始。
from sklearn.neighbors import KNeighborsClassifier
注意:k(n_neighbors)参数通常是一个奇数, 以避免在投票分数中产生联系。
为了确定超参数k的最佳值, 你将执行称为网格搜索的操作。你将在10个不同的k值上训练和测试模型, 最后使用可为你提供最佳结果的模型。
让我们初始化一个变量neighbors(k), 该变量的取值范围为1-9, 以及两个numpy零矩阵, 分别是train_accuracy和test_accuracy, 用于训练和测试精度。你稍后将需要它们来绘制图形以选择最佳邻居值。
neighbors = np.arange(1, 9)
train_accuracy =np.zeros(len(neighbors))
test_accuracy = np.zeros(len(neighbors))
下一段代码是所有魔术发生的地方。你将枚举所有九个邻居值, 然后针对每个邻居对训练和测试数据进行预测。最后, 将精度存储在train_accuracy和test_accuracy numpy数组中。
for i, k in enumerate(neighbors):
knn = KNeighborsClassifier(n_neighbors=k)#Fit the model
knn.fit(train_data, train_label)#Compute accuracy on the training set
train_accuracy[i] = knn.score(train_data, train_label)#Compute accuracy on the test set
test_accuracy[i] = knn.score(test_data, test_label)
接下来, 你将使用matplotlib绘制训练和测试的准确性, 并通过准确性与变化的邻居数图来选择模型表现最佳的最佳k值。
plt.figure(figsize=(10, 6))
plt.title('KNN accuracy with varying number of neighbors', fontsize=20)
plt.plot(neighbors, test_accuracy, label='Testing Accuracy')
plt.plot(neighbors, train_accuracy, label='Training accuracy')
plt.legend(prop={'size': 20})
plt.xlabel('Number of neighbors', fontsize=20)
plt.ylabel('Accuracy', fontsize=20)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.show()
文章图片
好了, 通过查看上面的图, 看起来当n_neighbors = 3时, 两个模型都表现最佳。因此, 让我们坚持使用n_neighbors = 3并再次重新运行训练。
knn = KNeighborsClassifier(n_neighbors=3)#Fit the model
knn.fit(train_data, train_label)#Compute accuracy on the training set
train_accuracy = knn.score(train_data, train_label)#Compute accuracy on the test set
test_accuracy = knn.score(test_data, test_label)
评估模型 在本教程的最后一部分中, 你将使用诸如confusion_matrix和category_report之类的两种技术在测试数据上评估模型。
让我们首先在测试数据上检查模型的准确性。
test_accuracy
0.9666666666666667
中提琴!看起来该模型能够正确分类96.66%的测试数据。那不是很神奇吗?仅需几行代码, 你就可以训练一个ML模型, 该模型现在只需使用96.66%的准确性就可以告诉你花的名字。谁知道它的性能可能比人类更好。
混淆矩阵 混淆矩阵主要用于描述模型在已知真实值或标签的测试数据上的性能。
Scikit-learn提供了一个为你计算混淆矩阵的函数。
prediction = knn.predict(test_data)
下面的plot_confusion_matrix()函数已被修改并从此源获取。
import itertools
def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues):plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center", color="white" if cm[i, j] >
thresh else "black")plt.ylabel('True label', fontsize=30)
plt.xlabel('Predicted label', fontsize=30)
plt.tight_layout()
plt.xticks(fontsize=18)
plt.yticks(fontsize=18)
class_names = load_iris().target_names# Compute confusion matrix
cnf_matrix = confusion_matrix(test_label, prediction)
np.set_printoptions(precision=2)# Plot non-normalized confusion matrix
plt.figure(figsize=(10, 8))
plot_confusion_matrix(cnf_matrix, classes=class_names)
plt.title('Confusion Matrix', fontsize=30)
plt.show()
文章图片
从上面的confusion_matrix图中, 你可以看到该模型正确地对所有花朵进行了分类, 除了一朵杂色花被分类为维吉尼亚花。
分类报告 分类报告可通过提供每个类别的准确性, 召回率和F1分数来帮助你更详细地识别错误分类的类别。你将使用sklearn库来可视化分类报告。
from sklearn.metrics import classification_report
print(classification_report(test_label, prediction))
precisionrecallf1-scoresupportIris-setosa1.001.001.0010
Iris-versicolor0.901.000.959
Iris-virginica1.000.910.9511micro avg0.970.970.9730
macro avg0.970.970.9730
weighted avg0.970.970.9730
走得更远! 首先祝贺所有成功实现这一目标的人!但这仅仅是开始。还有很长的路要走!
本教程主要涉及机器学习的基础知识以及一种称为KNN和python的ML算法的实现。你使用的Iris数据集非常小而且有点简单。
如果本教程激发了你的兴趣以了解更多信息, 则可以尝试使用其他一些数据集或尝试学习更多的ML算法, 并可以将其应用于Iris数据集以观察对准确性的影响。通过这种方式, 你将学到更多, 而不仅仅是了解理论!
如果你对本教程中介绍的基础知识和其他机器学习算法进行了充分的实验, 则可能需要进一步进行python和数据分析。
推荐阅读
- BI和分析平台的比较
- 使用Auto-Keras进行自动化机器学习
- 在Python中使用Zip文件
- 使用Scikit-learn的朴素贝叶斯分类
- Python|清华教授用了36小时讲完的Python,整整632集,拿走提高工作效率
- Python|盲目自学python最大的谎言就是所谓的“好学”(含视频及书籍资源)
- Python|熬夜加班半个月整理的40道Python面试题集锦(附答案)
- Python|Pandas+Matplotlib,深入浅出Python数据分析
- Python|零基础Python入门必看——编程基础概念