经典机器学习模型(一)感知机模型

经典机器学习模型(一)感知机模型

感知机可以说是一个相当重要的机器学习基础模型,是神经网络和支持向量机的基础。

感知机是一个二分类的线性分类模型,之所以说是线性,是因为它的模型是线性形式的。

从《统计学习方法》中,我们知道学习方法的三要素为模型、策略、算法,我们就从三要素来了解下感知机。

1 感知机模型的三要素

1.1 模型

1.1.1 感知机模型

在这里插入图片描述

  • 输入空间

    • 这里 χ \chi χ代表 n n n维实数空间的一个子集
    • 输入的每一个实例 x x x,用一个 n n n维的特征向量表示,它是属于输入空间 χ \chi χ的。
    • 实例 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) T x=(x^{(1)},x^{(2)},...,x^{(n)})^T x=(x(1),x(2),...,x(n))T
  • 输出空间

    • 由于这是一个二分类模型,所以这里输出空间是一个只包含+1和-1的一个集合。

    • 1 代表的是正类,-1 代表的是负类,具体的输出则是代表实例 x x x所对应的类别。

  • 感知机

    • 我们定义一个从输入空间到输出空间的函数,这个函数就称作感知机。

    • 这个函数 s i g n ( x ) sign(x) sign(x)叫做符号函数

    • w ⋅ x = ( w ( 1 ) x ( 1 ) , w ( 2 ) x ( 2 ) , . . . , w ( n ) x ( n ) ) T w\cdot x=(w^{(1)}x^{(1)},w^{(2)}x^{(2)},...,w^{(n)}x^{(n)})^T wx=(w(1)x(1),w(2)x(2),...,w(n)x(n))T

  • 假设空间

    • 特征空间里面所有可能的线性函数就称为假设空间。
  • 参数空间

    • 参数 w w w b b b的所有组合,就得到一个 n n n维的空间,也就是参数空间。

1.1.2 感知机模型的几何意义

我们从几何角度来解释一下感知器,如下图所示:

  • 线性方程 w ⋅ x + b = 0 w\cdot x +b = 0 wx+b=0代表着 n n n维特征空间里面的一个超平面 S S S

  • w w w是法向量,垂直于超平面 S S S b b b是相应的截距项。

  • 通过超平面 S S S我们就可以将整个特征空间分为两部分

    • 一部分是正类,其中的实例所对应的输出为 +1;
    • 一部分为负类,它里面的实例所对应的输出为 -1。所以这个超平面被称为分离超平面。
  • 超平面的理解。

    • 如果我们现在的特征空间是一维的,那么想区分正负类实例点,用实数轴上的一个点就可以了,比如零点。
    • 如果特征空间是两维的,实例应该就是二维空间中的一个点,要区分正负类,它的分离超平面对应的应该是一条直线(如下图)。
    • 如果可能空间是三维的,分离超平面应该就是一个二维平面了。
    • 依此类推,如果环境空间是 n n n维的,那么它所对应的超平面其实就是一个 n − 1 n-1 n1维的子空间。
  • 原点到超平面的距离为 − b ∣ ∣ w ∣ ∣ -\frac{b}{||w||} ∣∣w∣∣b

在这里插入图片描述

1.2 策略

如果假设训练数据集线性可分,我们的目标则是希望寻求到一个的分离超平面,把这些实例点完全划分为正负类

但是,要求得这样一个超平面,就需要确定模型的参数,即w和b,这就需要制定一定的学习策略。换而言之,就是要合理地定义感知机相应的损失函数

1.2.1 线性可分数据集

感知机模型,有一个比较严苛的条件,就是要求数据集必须是线性可分的。

线性可分的意思如下:

对于给定的数据集,如果存在某个超平面,使得这个数据集的所有实例点可以完全划分到超平面的两侧,也就是正类和负类。我们就称这个数据集是线性可分的,否则线性不可分。

1.2.2 感知机的损失函数

特征空间中的任意一点到超平面的距离公式如下:
1 ∣ ∣ w ∣ ∣ ∣ w ⋅ x 0 + b ∣ \frac{1}{||w||}|w\cdot x_0+b| ∣∣w∣∣1wx0+b
如果 x 0 x_0 x0是错误的分类点,那么容易得到下式:
1 ∣ ∣ w ∣ ∣ ∣ w ⋅ x 0 + b ∣ = { − w ⋅ x 0 + b ∣ ∣ w ∣ ∣ , y 0 = 1 w ⋅ x 0 + b ∣ ∣ w ∣ ∣ , y 0 = − 1 = − ( w ⋅ x 0 + b ) y 0 ∣ ∣ w ∣ ∣ \frac{1}{||w||}|w\cdot x_0+b|=\begin{cases} -\frac{w\cdot x_0+b}{||w||}, & y_0 = 1\\ \\ \frac{w\cdot x_0+b}{||w||}, & y_0 = -1 \end{cases}=-\frac{(w\cdot x_0+b)y_0}{||w||} ∣∣w∣∣1wx0+b= ∣∣w∣∣wx0+b,∣∣w∣∣wx0+b,y0=1y0=1=∣∣w∣∣(wx0+b)y0
现在我们要关注的就是这里的错误分类点,设误分类点为 x i x_i xi,那么 x i x_i xi到超平面 S S S的距离为:
− ( w ⋅ x i + b ) y i ∣ ∣ w ∣ ∣ -\frac{(w\cdot x_i+b)y_i}{||w||} ∣∣w∣∣(wxi+b)yi
如果用 M M M代表所有误分类点的集合,我们可以写出所有误分类点到超平面 S S S的距离的总和:
− 1 ∣ ∣ w ∣ ∣ ∑ x i ∈ M ( w ⋅ x i + b ) y i -\frac{1}{||w||}\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i ∣∣w∣∣1xiM(wxi+b)yi
很明显, M M M中所含有的误分类点越少的时候,总距离和应该越小。在没有误分类点的时候, 这个距离和应该为 0。我们希望通过最小化总距离和来求参数。

因此,我们就得到了感知机模型的损失函数如下:
L ( w , b ) = − ∑ x i ∈ M ( w ⋅ x i + b ) y i , M 为误分类点的集合 L(w,b)=-\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i,M为误分类点的集合 L(w,b)=xiM(wxi+b)yiM为误分类点的集合

1.3 算法(原始形式)

  • 假如给定训练数据集,我们通过最小化损失函数,就可以估计得到模型参数。

  • 如何求参数 w w w b b b呢?这就是一个优化问题,寻找使损失函数最小的参数

在这里插入图片描述

想求这个损失函数的极小值,可以先求梯度,即分别求偏导数,得到梯度向量,然后用梯度下降法对参数更新。

需要注意的是,梯度下降法用的是负梯度,所以我们求梯度的时候得到的负号就抵消掉了

  • 如果是批量更新,就需要每次使用所有的误分类点,这会致使每一轮的迭代都需要大量的时间。

  • 随机梯度下降法,每一轮随机选择一个误分类点,迭代的速度会快一些。

    • 这是因为,如果通过这个误分类点进行参数的更新,有可能误分类点就会减少,那么下一步我们可用来选择更新参数的实例点就会减少,这在一定程度上简化计算,节约了时间。
  • 小批量梯度下降法既不是像批量梯度下降法中那样选择了所有的样本点,也不是像随机梯度下降法中随机选取了一个样本点,而是选择部分样本点进行参数更新。

    • 但是,小批量梯度下降法,也面临许多问题,比如每次需要选择多少个样本点?选择哪些样本才合适呢?

损失函数 L ( w , b ) = − ∑ x i ∈ M ( w ⋅ x i + b ) y i , M 为误分类点的集合 对 w 和 b 分别求偏导数,可得梯度为: ∇ w L ( w , b ) = − ∑ x i ∈ M x i y i ∇ b L ( w , b ) = − ∑ x i ∈ M y i 批量梯度下降法: w ← w + η ∑ x i ∈ M x i y i , b ← b + η ∑ x i ∈ M y i 随机梯度下降法 : w ← w + η x i y i , b ← b + η y i 其中, η ( 0 < η < = 1 ) 为步长 损失函数L(w,b)=-\sum\limits_{x_i\in M}(w\cdot x_i+b)y_i,M为误分类点的集合 \\ 对w和b分别求偏导数,可得梯度为: \\ \nabla_w L(w,b)=-\sum\limits_{x_i\in M}x_iy_i \\ \nabla_b L(w,b)=-\sum\limits_{x_i\in M}y_i \\ 批量梯度下降法:w\leftarrow w + \eta\sum\limits_{x_i\in M}x_iy_i,b\leftarrow b + \eta\sum\limits_{x_i\in M}y_i \\ 随机梯度下降法: w\leftarrow w + \eta x_iy_i,b\leftarrow b + \eta y_i\\ 其中,\eta(0<\eta<=1)为步长 \\ 损失函数L(w,b)=xiM(wxi+b)yiM为误分类点的集合wb分别求偏导数,可得梯度为:wL(w,b)=xiMxiyibL(w,b)=xiMyi批量梯度下降法:ww+ηxiMxiyi,bb+ηxiMyi随机梯度下降法:ww+ηxiyi,bb+ηyi其中,η(0<η<=1)为步长

1.3.1 随机梯度下降法

现在我们以随机梯度下降法来讲解感知机的算法,如下:

在这里插入图片描述

  • 首先选择初始值。
  • 接下来,在训练集中随机选取一个实例点,用 y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)来判断这个点被分离超平面正确分类还是错误分类。
    • 如果被正确分类, y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就是大于零的,我们不用管这个实例点了;
    • 如果被错误分类, y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就是小于零的,我们可以把这个实例点拿来更新参数。
    • 最麻烦的就是,如果这个实例点恰好位于分离超平面上,那么 y i ( w x i + b ) y_i(wx_i+b) yi(wxi+b)就直接等于零,无法知道此时这个实例点到底是被正确分类还是错误分类。所以,本着宁肯错杀也不能放过的原则,我们把这个实例点拿来更新参数。
  • 这样第三步就完成了。
  • 接着就是步骤的重复,直到所有的实例点都确定被正确分类。

1.3.2 感知机算法例题

在这里插入图片描述

我们这里使用python代码求解该例题:

完整代码可参考:Statistical_Learning_Methods_Impl: 《统计学习方法》第二版 python代码实现

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
%matplotlib inline# 1、加载数据
data = np.array([[3, 3, 1],[4, 3, 1],[1, 1, -1]
])
# 获取X和y
X, y = data[:,:-1], data[:,-1]# 2、画图
plt.scatter(X[:2][0], X[:2][1], label='1')
plt.scatter(X[2:][0], X[2:][0], label='-1')
plt.xlabel('x0')
plt.ylabel('x1')
# 设置x轴和y轴范围
plt.xlim(0, 7)
plt.ylim(0, 7)
plt.legend()

在这里插入图片描述

# 3、创建模型
class Perceptron(object):def __init__(self, num_features, l_rate=1, w='0'):# 初始化参数w、b以及学习率l_rateif w == '0':self.w = np.zeros(num_features, dtype=np.float32)elif w == '1':self.w = np.ones(num_features, dtype=np.float32)else:raise Exception('Unsupported parameter w')self.b = 0self.l_rate = l_ratedef sign(self, x, w, b):# 计算:xw + breturn np.dot(x, w) + bdef fit(self, X_train, y_train):# 随机梯度下降法is_wrong = Falsewhile not is_wrong:# 误分类点的个数wrong_count = 0for index in range(len(X_train)):# 取出一个点X = X_train[index]y = y_train[index]# 如果该点为误分类点,就进行迭代if y * self.sign(X, self.w, self.b) <= 0:# 更新wself.w += self.l_rate * np.dot(y, X)# 更新bself.b += self.l_rate * y# 误分类点+1wrong_count += 1print(f'取出的误分类点为x{index + 1}, 更新后w = {self.w}, b = {self.b},  wx+b = {self.w[0]}x1 + {self.w[1]}x2 + {self.b}')# 一次循环迭代结束后,如果没有误分类点,就结束if wrong_count == 0:is_wrong = Truereturn 'Perceptron Model'def predict(self,X_predict):y = np.dot(X_predict, self.w) + self.breturn np.sign(y)def score(self):pass
# 进行训练
num = len(X[0])
net1 = Perceptron(num_features=num)
net1.fit(X, y)
取出的误分类点为x1, 更新后w = [3. 3.], b = 1,   wx+b = 3.0x1 + 3.0x2 + 1
取出的误分类点为x3, 更新后w = [2. 2.], b = 0,   wx+b = 2.0x1 + 2.0x2 + 0
取出的误分类点为x3, 更新后w = [1. 1.], b = -1,  wx+b = 1.0x1 + 1.0x2 + -1
取出的误分类点为x3, 更新后w = [0. 0.], b = -2,  wx+b = 0.0x1 + 0.0x2 + -2
取出的误分类点为x1, 更新后w = [3. 3.], b = -1,  wx+b = 3.0x1 + 3.0x2 + -1
取出的误分类点为x3, 更新后w = [2. 2.], b = -2,  wx+b = 2.0x1 + 2.0x2 + -2
取出的误分类点为x3, 更新后w = [1. 1.], b = -3,  wx+b = 1.0x1 + 1.0x2 + -3

可以看到和书籍上迭代过程一样:

在这里插入图片描述

经过上述迭代,我们就得到最终模型:
f ( x ) = s i g n ( x ( 1 ) + x ( 2 ) − 3 ) f(x)=sign(x^{(1)}+x^{(2)}-3) f(x)=sign(x(1)+x(2)3)
需要注意的是,感知机模型并不唯一,不同的初值或者说不同的误分类点的顺序,可以得到不同的分离超平面。

我们可以实验下,将w的初始值设置为1,就得到了另一个超平面。

# 进行训练
num = len(X[0])
net2 = Perceptron(num_features=num, w='1')
net2.fit(X, y)
取出的误分类点为x3, 更新后w = [0. 0.], b = -1,  wx+b = 0.0x1 + 0.0x2 + -1
取出的误分类点为x1, 更新后w = [3. 3.], b = 0,  wx+b = 3.0x1 + 3.0x2 + 0
取出的误分类点为x3, 更新后w = [2. 2.], b = -1,  wx+b = 2.0x1 + 2.0x2 + -1
取出的误分类点为x3, 更新后w = [1. 1.], b = -2,  wx+b = 1.0x1 + 1.0x2 + -2
取出的误分类点为x3, 更新后w = [0. 0.], b = -3,  wx+b = 0.0x1 + 0.0x2 + -3
取出的误分类点为x1, 更新后w = [3. 3.], b = -2,  wx+b = 3.0x1 + 3.0x2 + -2
取出的误分类点为x3, 更新后w = [2. 2.], b = -3,  wx+b = 2.0x1 + 2.0x2 + -3
取出的误分类点为x3, 更新后w = [1. 1.], b = -4,  wx+b = 1.0x1 + 1.0x2 + -4

在这里插入图片描述

2 感知机的对偶形式算法

2.1 理解对偶算法

在之前讲解的原始形式的学习算法中,如果实例点 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,可以用它更新参数,即
w ← w + η x i y i b ← b + η y i w\leftarrow w + \eta x_iy_i \\ b\leftarrow b + \eta y_i\\ ww+ηxiyibb+ηyi
假如,每一个实例点对于参数更新,做了 n i n_i ni次贡献,那么每个实例点作用到初始参数 w 0 、 b 0 w_0、b_0 w0b0上的增量分别为 a i y i x i a_iy_ix_i aiyixi a i y i a_iy_i aiyi,其中 a i = n i η a_i=n_i\eta ai=niη

还是之前的例子:

在这里插入图片描述

  • 在这个过程中,实例 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)作为误分类点出现两次,所以 n 1 = 2 n_1=2 n1=2,即第一个实例点在迭代中贡献了 2 次。

  • ( x 2 , y 2 ) (x_2,y_2) (x2,y2)并没有出现,所以 n 2 = 0 n_2=0 n2=0,即第二个实例点在迭代中没有贡献。

  • ( x 3 , y 3 ) (x_3,y_3) (x3,y3)出现了5次,所以 n 3 = 5 n_3=5 n3=5,即第三个实例点在迭代中贡献了 5 次。

  • 恰好 n 1 + n 3 = 7 n_1 + n_3=7 n1+n3=7,就是实际迭代的次数。综合所有贡献的增量,就得到最终参数了,与原始算法的结果是相同的。

  • 对偶形式,基本思想就是通过实例点的线性组合来更新参数,其权重由贡献的大小决定的

根据以上的例子,很容易得出下面式子:

在这里插入图片描述

2.2 对偶算法

下面是感觉机学习算法对偶形式的具体步骤,可以看到把 w w w换为了 ∑ j = 1 N a i y i x j \sum\limits_{j=1}^N a_iy_ix_j j=1Naiyixj,梯度下降时候也变成了更新 a i a_i ai

在这里插入图片描述

与原始形式相比,对偶形式有什么优势呢? 这需要,仔细分析对偶形式的迭代条件。

在这里插入图片描述

  • 将迭代条件展开,我们发现,如果训练数据集固定,那么有些值是不需要重复计算的,也就是我们红框里的这 N N N个内积。

  • 如果 ( x i , y i ) (x_i, y_i) (xi,yi)是误分类点,只要读取Gram矩阵第 i i i行的值即可。

  • 我们要做的,就是在得到训练数据集之后,把这 N × N N×N N×N个内积计算出来储存到Gram矩阵,之后每次更新参数的时候读取就可以,这能节省许多计算量。

2.3 对偶算法的案例

还是之前的案例,我们使用对偶算法进行求解。

在这里插入图片描述

  • 先设置初始值,不妨还是取零向量,然后计算Gram矩阵,把9个内积的值都储存下来。

  • 接下来就是判断误分类点,可以选取 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)带入迭代条件中,计算得到零,可以用来更新参数,得到一个新的分离超平面。

在这里插入图片描述

  • 用这个新得到的分离超平面,对三个实例点分类,选取错误分类点,继续进行更新。
    在这里插入图片描述

  • 之后,重复步骤,直到没有误分类点,停止迭代。

在这里插入图片描述

2.4 上述过程的代码实现

Statistical_Learning_Methods_Impl: 《统计学习方法》第二版 python代码实现

import numpy as npclass PerceptronDuality(object):def __init__(self, num_features, eta=1):# 初始化参数G、α、w、bself.G = np.zeros([num_features, num_features], dtype=np.float32)self.α = np.zeros(num_features)self.b = 0self.eta = eta# w[0] * x + w[1] * y + b = 0self.w = [0., 0.]def fit(self, data, label):# 1、计算 Gram 矩阵for i in range(0, len(data)):for j in range(0, len(data)):self.G[i][j] = data[i][0] * data[j][0] + data[i][1] * data[j][1]print('Gram矩阵:\n', self.G)separated = False  # 标记是否完全分离while not separated:separated = True# 遍历训练集,每次取出点 (data[i][0], data[i][1])for i in range(0, len(data)):sum = 0for j in range(0, len(data)):# 计算 ∑(α*yj*xj)x的值,相当于原始形式中的 wxsum += self.α[j] * label[j] * self.G[j][i]# 判断是否为误分类点if (sum + self.b) * label[i] <= 0:self.α[i] += self.eta          # 更新 α 的值self.b += self.eta * label[i]  # 更新 b 的值print(f'误分类点为x{i + 1},α = {self.α}, b = {self.b}')separated = False  # 置回标记# 求出 w 的值for i in range(0, len(self.α)):self.w[0] += self.α[i] * label[i] * data[i][0]self.w[1] += self.α[i] * label[i] * data[i][1]return 'PerceptronDuality Model'if __name__ == '__main__':data = np.array([[3, 3, 1],[4, 3, 1],[1, 1, -1]])X, y = data[:, :-1], data[:, -1]# 进行训练num = len(X)net = PerceptronDuality(num_features=num)net.fit(X, y)

可以看到和之前手动计算的一致。

Gram矩阵:[[18. 21.  6.][21. 25.  7.][ 6.  7.  2.]]
误分类点为x1,α = [1. 0. 0.], b = 1
误分类点为x3,α = [1. 0. 1.], b = 0
误分类点为x3,α = [1. 0. 2.], b = -1
误分类点为x3,α = [1. 0. 3.], b = -2
误分类点为x1,α = [2. 0. 3.], b = -1
误分类点为x3,α = [2. 0. 4.], b = -2
误分类点为x3,α = [2. 0. 5.], b = -3

参考书籍:
李航老师《统计学习方法》第二版

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯】线段树

一.线段树 1.定义&#xff1a; 线段树是算法竞赛中常用的用来维护 区间信息 的数据结构。 线段树可以在O(logN) 的时间复杂度内实现单点修改、区间修改、区间查询&#xff08;区间求和&#xff0c;求区间最大值&#xff0c;求区间最小值&#xff09;等操作。 2.结构&#x…

【论文阅读】Improved Denoising Diffusion Probabilistic Models

Improved Denoising Diffusion Probabilistic Models 文章目录 Improved Denoising Diffusion Probabilistic Models概述Improving the Log-likelihoodLearning ∑ θ ( x t , t ) \sum_{\theta}(x_{t}, t) ∑θ​(xt​,t)Improving the Noise ScheduleReducing Gradient Nois…

基于Pnpm + Turborepo + QianKun的微前端+Monorepo实践

基于Pnpm Turborepo QianKun的微前端Monorepo实践 背景 微前端一般都会涉及多个代码库&#xff0c;很多时候要一个一个代码库地去开发维护和运行&#xff0c;很不方便&#xff0c;这种时候引入Monorepo搭配微前端就能很好地解决这种问题&#xff0c;一个代码库就可以完成整…

Spring Cloud Alibaba微服务从入门到进阶(三)(Spring Cloud Alibaba)

Spring Cloud Alibaba是spring Cloud的子项目 Spring Cloud Alibaba的主要组件&#xff08;红框内是开源的&#xff09; Spring Cloud是快速构建分布式系统的工具集&#xff0c; Spring Cloud提供了很多分布式功能 Spring Cloud常用子项目 项目整合 Spring Cloud Alibaba …

友塔游戏测试开发笔面经验

题目一 给定任意非负整数M&#xff0c;判断其能否表达为 M 2 ^a 2 ^b(a和b为非负整数)&#xff0c;若可以输出a和b&#xff0c;若不能输出-1&#xff1b; 例如&#xff1a; 输入&#xff1a;6 输出: “1 2” 分析&#xff1a; void findAB(int M){} 为解决问题的主函数 …

优选算法[1]

目录 1.双指针&#xff1b; 2.滑动窗口&#xff1b; 3.二分查找&#xff1b; 4.前缀和&#xff1b; 1.双指针&#xff1b; 包括对撞指针和快慢指针(一般用来循环&#xff09;&#xff1b; 题目类型&#xff1a;移动零&#xff0c;复写零&#xff0c;快乐数&#xff0c;盛…

【每日力扣】235. 二叉搜索树的最近公共祖先与39. 组合总和问题描述

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害。 235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义…

Python中类方法和静态方法的区别你知道吗?

​1.类方法 通过 classmethod 装饰器修饰的方法就是类方法 类方法可以通过类名或对象名调用&#xff0c;但是一般情况下使用类名调用&#xff08;节省内存&#xff09; 类方法中没有self.在类方法中不可以使用其它对象的属性和方法 类方法中一般会有一个参数cls&#xff0c;…

Crc冗余校验码设计

串行电路的位置&#xff0c;有异或门的地方是1&#xff08;生成多项式&#xff09; 简单的来说&#xff0c;如果最高位Q4 为0 的话&#xff0c;那么直接和 0 进行异或的话&#xff0c;实现的也是自己本身&#xff0c;直接左移就可以了 如果最高是1的话&#xff0c;那么就要和生…

【数据结构与算法】:选择排序与快速排序

&#x1f525;个人主页&#xff1a; Quitecoder &#x1f525;专栏&#xff1a;数据结构与算法 我的博客即将同步至腾讯云开发者社区&#xff0c;邀请大家一同入驻&#xff1a;腾讯云 欢迎来到排序的第二个部分&#xff1a;选择排序与快速排序&#xff01; 目录 1.选择排序1.…

如何export windows中的环境变量

在大语言模型&#xff08;LLM&#xff09;学习过程中&#xff0c; 利用 jupyter 导入环境变量时出现以下问题&#xff0c; C:\Users\zhangxuantao>export SENSENOVA_SKxxxxxx export 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 原因是学习教程中用…

VTK安装(C++)并配置vs

准备工作&#xff1a; 1.VTK下载包(此教程使用VTK8.2.0) 2.CMAKE(此教程使用3.29.0) 在此不过多赘述&#xff0c;可在网上搜索cmake安装 3.visual studio(此教程使用vs2019) VTK下载及编译&#xff1a; 1、找到自己适合的VTK版本,我选择的是VTK8.2.0。 1.1 官网下载&#xff…