基于jupyter的多分类问题练习

news2024/12/26 16:01:58

文章目录

  • 练习3:多分类问题
    • 介绍
    • 1 多分类
      • 1.1 数据集
      • 1.2 数据可视化
      • 1.3 逻辑回归的向量化
        • 1.3.1 代价函数的向量化
        • 1.3.2 梯度的向量化
        • 1.3.3 正则化逻辑回归的向量化
      • 1.4 多分类-分类器
      • 1.5 使用分类器进行预测
  • 总结

练习3:多分类问题


介绍

在本练习中,我们将使用逻辑回归来识别手写数字(0到9)。我们将扩展在练习2中对逻辑回归的实现,并将其应用于一对多的分类问题。

在开始练习前,需要下载如下的文件进行数据上传

  • ex3data1.mat -手写数字训练集
    在这里插入图片描述

在整个练习中,涉及如下的必做作业

  • 实现逻辑回归向量化----(40分)
  • 训练一对多的多分类器----(40分)
  • 使用多分类器进行预测----(20分)

1 多分类

在本部分练习中,你需要扩展之前实现的逻辑回归算法,将其应用于多分类问题

1.1 数据集

文件ex3data1.mat中的数据包含5000个手写数字的训练集。其中每个样本是20像素x20像素的灰度图像,每个像素由一个浮点数表示,代表该位置的灰度强度。
将20x20的像素网格展开成400维向量,则每个训练样本变成了数据矩阵中的一行向量。如下图所示,该文件给了我们一个5000x400的矩阵,其中每行都是手写数字图像的样本。

在这里插入图片描述

训练集的第二部分是包含训练集标签的5000维向量 y y y

1.2 数据可视化

在这里插入图片描述

图像在矩阵X中表示为400维向量(其中有5,000个)。 400维“特征”是原始20 x 20图像中每个像素的灰度强度。类标签在向量y中作为表示图像中数字的数字类。

接下来,我们需要加载数据。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmat

data = loadmat('/home/jovyan/work/ex3data1.mat')
data
{'__header__': b'MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Oct 16 13:09:09 2011',
 '__version__': '1.0',
 '__globals__': [],
 'X': array([[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]]),
 'y': array([[10],
        [10],
        [10],
        ...,
        [ 9],
        [ 9],
        [ 9]], dtype=uint8)}

并使用shape内置函数检查数据矩阵 X X X, y y y的形状:

data['X'].shape, data['y'].shape
((5000, 400), (5000, 1))

1.3 逻辑回归的向量化

在该部分练习中,你需要将逻辑回归的实现修改为完全向量化(即没有可替换的 f o r for for循环)。这是因为向量化代码除了简洁外,还能够利用线性代数优化,并且通常比迭代代码快得多。但是,如果从练习2中看到我们的代价函数已经完全向量化实现了,所以我们可以在这里重复使用相同的实现。

1.3.1 代价函数的向量化

你需要编写代码实现代价函数的向量化。我们已经知道,代价函数是:

J ( θ ) = 1 m ∑ i = 1 m [ − y ( i ) log ⁡ ( h θ ( x ( i ) ) ) − ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ] J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{{y}^{(i)}}\log \left( {{h}_{\theta }}\left( {{x}^{(i)}} \right) \right)-\left( 1-{{y}^{(i)}} \right)\log \left( 1-{{h}_{\theta }}\left( {{x}^{(i)}} \right) \right)]} J(θ)=m1i=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]
为了计算求和中的每个元素,我们需要计算对于每个样本 i i i
h θ ( x ( i ) ) {{h}_{\theta }}\left( {{x}^{(i)}} \right) hθ(x(i))。其中,
h θ ( x ) = g ( θ T X ) {{h}_{\theta }}\left( x \right)=g\left({{{\theta }^{T}}X} \right)\\ hθ(x)=g(θTX)
并且 sigmoid函数为:
g ( z ) = 1 1 + e − z g\left( z \right)=\frac{1}{1+{{e}^{-z}}}\\ g(z)=1+ez1
事实证明,对于所有例子,我们都可以通过矩阵乘法来快速计算。我们定义 X X X θ \theta θ为:
在这里插入图片描述

然后,进行矩阵乘法 X θ X\theta ,计算得到:
在这里插入图片描述

在最后一个等式中,如果 a a a b b b都是向量,我们就可以利用 a T b = b T a a^Tb=b^Ta aTb=bTa
的事实,并且可以在一行代码中计算所有例子的乘积 θ T x ( i ) \theta^Tx^{(i)} θTx(i)

###在这里填入代码###
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def cost(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T))) 
    return np.sum(first - second) / len(X)

1.3.2 梯度的向量化

我们知道,要使用梯度下降法令这个代价函数最小化。回顾一下,逻辑回归代价函数的梯度是一个向量,其第 j j j个元素定义为
∂ J ∂ θ j = 1 m ∑ i = 1 m [ h θ ( x ( i ) ) − y ( i ) ] x j ( i ) \frac{\partial J}{\partial \theta_j} = \frac{1}{m}\sum\limits_{i=1}^{m}{[{{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}]x_{_{j}}^{(i)}} θjJ=m1i=1m[hθ(x(i))y(i)]xj(i)
为了对该操作进行向量化,我们需要把所有 θ j \theta_j θj的偏导都写出来:

在这里插入图片描述
其中:
在这里插入图片描述

注意 x ( i ) x^{(i)} x(i)是一个向量,而 ( h θ ( x ( i ) ) − y ( i ) ) (h_\theta(x^{(i)})-y^{(i)}) (hθ(x(i))y(i))是一个标量(数字)。
β i = ( h θ ( x ( i ) ) − y ( i ) ) \beta_i = ({{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}) βi=(hθ(x(i))y(i))可以这么理解:
在这里插入图片描述

在对操作进行向量化之后,我们知道可以不需要使用LOOP循环就可以进行偏导的计算。接下来你需要编写代码实现上述代码的向量化形式

###在这里填入代码###
def gradient(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    error = sigmoid(X * theta.T) - y
    
    grad = ((X.T * error) / len(X)).T
    
    return grad

1.3.3 正则化逻辑回归的向量化

在练习2中,我们实现正则化逻辑回归算法的代价函数和梯度计算函数。其代价函数为:

J ( θ ) = 1 m ∑ i = 1 m [ − y ( i ) log ⁡ ( h θ ( x ( i ) ) ) − ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ] + λ 2 m ∑ j = 1 n θ j 2 J\left( \theta \right)=\frac{1}{m}\sum\limits_{i=1}^{m}{[-{{y}^{(i)}}\log \left( {{h}_{\theta }}\left( {{x}^{(i)}} \right) \right)-\left( 1-{{y}^{(i)}} \right)\log \left( 1-{{h}_{\theta }}\left( {{x}^{(i)}} \right) \right)]}+\frac{\lambda }{2m}\sum\limits_{j=1}^{n}{\theta _{j}^{2}} J(θ)=m1i=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]+2mλj=1nθj2
注意不需要对 θ o \theta_o θo进行正则化,其用于偏差的计算。
对应地,其梯度的计算公式如下:
R e p e a t   u n t i l   c o n v e r g e n c e    ⁣ ⁣ {  ⁣ ⁣     θ 0 : = θ 0 − a 1 m ∑ i = 1 m [ h θ ( x ( i ) ) − y ( i ) ] x 0 ( i )   θ j : = θ j − a 1 m ∑ i = 1 m [ h θ ( x ( i ) ) − y ( i ) ] x j ( i ) + λ m θ j    ⁣ ⁣ }  ⁣ ⁣   R e p e a t \begin{align} & Repeat\text{ }until\text{ }convergence\text{ }\!\!\{\!\!\text{ } \\ & \text{ }{{\theta }_{0}}:={{\theta }_{0}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}]x_{_{0}}^{(i)}} \\ & \text{ }{{\theta }_{j}}:={{\theta }_{j}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}]x_{j}^{(i)}}+\frac{\lambda }{m}{{\theta }_{j}} \\ & \text{ }\!\!\}\!\!\text{ } \\ & Repeat \\ \end{align} Repeat until convergence {  θ0:=θ0am1i=1m[hθ(x(i))y(i)]x0(i) θj:=θjam1i=1m[hθ(x(i))y(i)]xj(i)+mλθj } Repeat
接下来,你需要编写代码实现正则化逻辑回归算法的代价函数和梯度的向量化实现

###在这里填入代码###
def costReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
    reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
    return np.sum(first - second) / len(X) + reg

def gradientReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    error = sigmoid(X * theta.T) - y
    
    grad = ((X.T * error) / len(X)).T + ((learningRate / len(X)) * theta)
    
    # intercept gradient is not regularized
    grad[0, 0] = np.sum(np.multiply(error, X[:,0])) / len(X)
    
    return np.array(grad).ravel()

1.4 多分类-分类器

现在我们已经定义了代价函数和梯度函数,现在我们需要构建一个分类器。对于手写字识别,我们有10个可能的类(0-9),但逻辑回归是一个二分类问题。

在本练习中,你的任务是实现一对一全分类方法,其中具有 k k k个不同类的标签就有 k k k个分类器,每个分类器在“类别 i i i”和“不是 i i i”之间决定。我们将把分类器训练包含在一个函数中,该函数计算10个分类器中的每个分类器的最终权重,并将权重返回为 [ k , n + 1 ] [k,n+1] [k,n+1]的数组,其中 n n n是参数数量。

需要注意的是

  • 需要添加 θ 0 \theta_0 θ0以计算截距项。
  • 将$ y$从类标签转换为每个分类器的二进制(要么是类i,要么不是类i)。
  • 使用scipy库的优化类的minimize函数来最小化每个分类器的代价函数。
  • 将寻找到的最优参数分配给参数数组,并返回形状为 [ k , n + 1 ] [k,n+1] [k,n+1] 的参数数组。

其中,实现向量化代码最重要的地方是要保证正确地写入所有的矩阵,保证其维度正确。

###在这里填入代码###
from scipy.optimize import minimize

def one_vs_all(X, y, num_labels, learning_rate):
    rows = X.shape[0]
    params = X.shape[1]
    
    # k个分类器的参数,形状为(k,n+1)
    all_theta = np.zeros((num_labels, params + 1))
    
    # 插入值为1的列,用于计算截距项
    X = np.insert(X, 0, values=np.ones(rows), axis=1)
    
    # 将分类标签转换为0-1标识
    for i in range(1, num_labels + 1):
        theta = np.zeros(params + 1)
        y_i = np.array([1 if label == i else 0 for label in y])
        y_i = np.reshape(y_i, (rows, 1))
        
        # 使用minimize函数最小化代价函数
        fmin = minimize(fun=costReg, x0=theta, args=(X, y_i, learning_rate), method='TNC', jac=gradientReg)
        all_theta[i-1,:] = fmin.x
    
    return all_theta

我们来检查下需要初始化的变量,以及变量的形状:

rows = data['X'].shape[0]
params = data['X'].shape[1]

all_theta = np.zeros((10, params + 1))

X = np.insert(data['X'], 0, values=np.ones(rows), axis=1)

theta = np.zeros(params + 1)

y_0 = np.array([1 if label == 0 else 0 for label in data['y']])
y_0 = np.reshape(y_0, (rows, 1))

X.shape, y_0.shape, theta.shape, all_theta.shape
((5000, 401), (5000, 1), (401,), (10, 401))

其中, t h e t a theta theta是一维数组,因此当它被转换为计算梯度代码中的矩阵时,它变成了形状为 ( 1 , 401 ) (1,401) (1,401)的矩阵。同时,我们需要检查 y y y中的类标签。

np.unique(data['y'])#看下有几类标签
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10], dtype=uint8)

接下来,为了确保训练函数正确运行,运行以下代码查看是否得到合理的输出。

###请运行并测试你的代码###
all_theta = one_vs_all(data['X'], data['y'], 10, 1)
all_theta
array([[-2.38373823e+00,  0.00000000e+00,  0.00000000e+00, ...,
         1.30440684e-03, -7.49607957e-10,  0.00000000e+00],
       [-3.18277385e+00,  0.00000000e+00,  0.00000000e+00, ...,
         4.46416745e-03, -5.08967467e-04,  0.00000000e+00],
       [-4.79656036e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -2.87471064e-05, -2.47976297e-07,  0.00000000e+00],
       ...,
       [-7.98398219e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -8.95642491e-05,  7.22603652e-06,  0.00000000e+00],
       [-4.57124969e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -1.33504169e-03,  9.98035730e-05,  0.00000000e+00],
       [-5.40535662e+00,  0.00000000e+00,  0.00000000e+00, ...,
        -1.16457336e-04,  7.86968213e-06,  0.00000000e+00]])

1.5 使用分类器进行预测

我们现在准备好最后一步,你需要使用训练完毕的分类器预测每个图像的标签

对于这一步,我们将计算每个类的类概率,对于每个训练样本(使用向量化代码),并将输出类标签为具有最高概率的类。

###在这里填入代码###
def predict_all(X, all_theta):
    rows = X.shape[0]
    params = X.shape[1]
    num_labels = all_theta.shape[0]
    
    # 与之前一样,需要插入一列确保矩阵形状
    X = np.insert(X, 0, values=np.ones(rows), axis=1)
    
    # 将其转换为矩阵
    X = np.matrix(X)
    all_theta = np.matrix(all_theta)
    
    # 计算每个训练样本所属每个类别的概率
    h = sigmoid(X * all_theta.T)
    
    # 创建具有最大概率的索引数组
    h_argmax = np.argmax(h, axis=1)
    
    # 因为我们的数组是零索引的,所以我们需要为真正的标签预测+1
    h_argmax = h_argmax + 1
    
    return h_argmax

现在我们可以使用predict_all函数为每个实例生成类预测,看看我们的分类器是如何工作的。

###请运行并测试你的代码###
y_pred = predict_all(data['X'], all_theta)
correct = [1 if a == b else 0 for (a, b) in zip(y_pred, data['y'])]
accuracy = (sum(map(int, correct)) / float(len(correct)))
print ('accuracy = {0}%'.format(accuracy * 100))
accuracy = 94.46%

总结

多分类问题是机器学习中的一个重要任务,通常需要使用分类算法来对不同类别的数据进行预测和分类。在练习中,我们可以使用各种不同的多分类算法,如决策树、神经网络、支持向量机等,来解决实际问题。同时,还需要注意数据预处理、特征选择和模型评估等方面的问题,以提高算法的准确性和可靠性。最后,为了更好地应用多分类算法,还需要不断学习和探索新的算法和技术,以应对不断变化的数据和需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Leetcode周赛348

第一题:最小化字符串长度 思路分析 通过分析我们可以发现,只要存在重复的元素就可以继续进行操作所以这里本质上是一道去重的题目去重我们可以使用双指针算法和Set;我们选择使用Set进行去重 class Solution {public int minimizedStringLengt…

Vue2 vue-cli

安装与卸载vue脚手架 npm i -g vue/cli vue --version 查看vue脚手架版本 vue -V 查看vue脚手架版本 npm uninstall -g vue/cli 卸载 创建项目 vue create 项目名 选择项目 (Default 为快速创建项目) 选择最后一下,回车 上下键选择 Rou…

shell脚本:函数

shell脚本-函数 一、函数:1.定义:2.作用:3.格式: 二、函数传参:1.定义:2.函数变量:3.递归:4.函数库: 一、函数: 1.定义: (1&#xf…

Internal error. Please report to https://jb.gg/ide/critical-startup-errors

大佬的解决方式:PyCharm 2023 启动报错的处理 部分同学,发现在安装 PyCharm 2023.1.2 以及 PyCharm 2023.2 的抢先体验版之后,运行的时候愣是直接弹出了类似上面的报错。 反正,别慌! 是的,他们有 bug。 …

呈现视觉妙技:使用Python将MP4视频转化为迷人的GIF图像

前言 GIF图片对于我来说是一个很好的展示方式,GIF 图片能够展示动态的图像效果,对于展示计算机视觉算法或结果非常有用。例如,我可以使用 GIF 图片来展示运动跟踪、姿势识别、图像分割、目标检测等任务的结果,以更生动和直观的方…

基于midiepipe、opencv的家庭健身智能推荐与姿态监测系统

目录 0. 前言1. opencv简介2. midiepipe简介3. yolo5简介4. 虚拟环境搭建以及工程目录设置5. 部分代码展示6. 项目成果7. 说明 0. 前言 本项目由我与gay友以及三位21级学弟历时一年共同合作完成 为了给运动者提供一种更加科学、更加精准的个性化运动方案,设计实现…

【SpinalHDL快速入门】6.2、SpinalHDL语法之When/Switch/Mux

文章目录 1.1、When1.2、Switch1.2.1、实例1.2.2、附加选项 1.3、本地声明1.4、Mux1.5、位选择1.5.1、实例 1.1、When 与VHDL和Verilog一样,当满足指定条件时可以对信号进行有条件的赋值: when(cond1) {// Execute when cond1 is true }.elsewhen(cond…

直播问答功能(互动功能接收端JS-SDK)

功能概述 本模块主要用于展示问答模块。 初始化及销毁 在实例化该模块并进行使用之前&#xff0c;需要对SDK进行初始化配置&#xff0c;详细见参考文档。 在线文件引入方式 // script 标签引入&#xff0c;根据版本号引入JS版本。 <script src"https://websdk.vi…

【Maven】Maven入门,Java界的Anaconda!

1 Maven介绍 官方文档&#xff1a;Apache Maven 的本质是一个软件项目管理和理解工具。基于项目对象模型 (Project Object Model&#xff0c;POM) 的概念&#xff0c;Maven 可以从一条中心信息管理项目的构建、报告和文档。 就像Python和Anaconda的关系&#x1f92d; 可以帮助…

java设计模式(十三)解释器模式

目录 定义模式结构角色职责代码实现场景适用优缺点 定义 解释器模式&#xff08;Interpreter Pattern&#xff09; 提供了评估语言的语法或表达式的方式&#xff0c;它属于行为型模式。这种模式实现了一个表达式接口&#xff0c;该接口解释一个特定的上下文。这种模式被用在 S…

Linux 内存管理6——slab内存池的创建初始化过程

在上篇文章 中&#xff0c;笔者带大家从一个最简单的物理内存页开始&#xff0c;一步一步演进 slab cache 的架构&#xff0c;最终得到了一副 slab cache 完整的架构图&#xff1a; 在本文的内容中&#xff0c;笔者会带大家到内核源码实现中&#xff0c;来看一下 slab cache 在…

第三章:基本的SELECT语句

第三章&#xff1a;基本的SELECT语句 3.1&#xff1a;SQL概述 SQL背景知识 1946年&#xff0c;世界上第一台电脑诞生&#xff0c;如今&#xff0c;借由这台电脑发展起来的互联网已经自成江湖。在这几十年里&#xff0c;无数的技术、产业在这片江湖里沉浮&#xff0c;有的方兴未…

HTTP和HTTPS

目录 HTTP 告知服务器意图的HTTP方法 状态码告知从服务器端返回的请求结果 2XX 成功 3XX 重定向 4XX客户端错误 5XX服务器错误 使用Cookie的状态管理 HTTP 的缺点 HTTPS HTTP 当我们在网页浏览器的地址栏输入URL时&#xff0c;Web页面是如何呈现的吗&#xff1f; …

Linux 面试题-(腾讯,百度,美团,滴滴)

Linux 面试题-(腾讯,百度,美团,滴滴) 分析日志t.log(访问量)&#xff0c;将各个ip 地址截取&#xff0c;并统计出现次数,并按从大到小排序(腾讯) http://192.168.200.10/index1.html http://192.168.200.10/index2.html http://192.168.200.20/index1.html http://192.168.20…

Python 类和对象

一、什么是类和对象 Python和Java一样&#xff0c;都是面向对象的编程语言&#xff0c;面向对象编程其实是一种封装代码的方法&#xff0c;把一些公共的属性或者方法封装到一个类中&#xff0c;然后再通过这个类可以创建多个对象&#xff0c;最后使用这些对象去调用这些封装起…

【教程】两种免费更新iOS17测试版的方法

苹果iOS17系统已经发布&#xff0c;目前所有用户都可以免费注册成为开发者&#xff0c;升级iOS17开发者测试版 注意&#xff0c;现在不是通过描述文件来更新系统了&#xff0c;给大家带来两种更新升级方法&#xff0c;看下文操作 方法一 苹果官网注册 按照下图发消息“更新” …

java设计模式(十六)命令模式

目录 定义模式结构角色职责代码实现适用场景优缺点 定义 命令模式&#xff08;Command Pattern&#xff09; 又叫动作模式或事务模式。指的是将一个请求封装成一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开&#xff0c;然后可以使用不同的请求把客户端参数化&a…

数据库篇——锁

目录 引文A——活锁 引文B——死锁 1、表锁 1.1 关于 S 锁 1.2 关于 X 锁 1.3 关于意向锁 2、行锁 2.1 关于记录锁 2.2 关于间隙锁 2.3 关于临键锁 2.4 关于插入意向锁 3、页锁 我们在谈表锁、行锁以及页锁之前&#xff0c;先聊一聊 活锁&#x1f512;与 死锁&#x1f512;的…

RabbitMQ安装、端口修改、简单的角色介绍

前提 本文介绍RabbitMQ安装的环境是CentOS7版本的Linux云服务器。 官网&#xff1a;https://www.rabbitmq.com/ RabbitMQ的安装 由于RabbitMQ是使用Erlang语言开发的&#xff0c;所以我们在安装RabbitMQ之前需要在服务器中安装Erlang语言的环境。在Linux中执行下面命令&…

Day_43插入排序

目录 一. 关于插入排序 1. 排序的定义 2. 插入排序 二. 插入排序的实现过程 三. 代码实现过程 1. 插入排序核心代码 四. 代码展示 五. 数据测试 六. 总结 一. 关于插入排序 1. 排序的定义 排序&#xff0c;就是重新排列表中的元素&#xff0c;使表中的元素满足按关键字有序…