机器学习之利用SMO算法求解支持向量机—基于python

news2024/12/23 5:22:01

      大家好,我是带我去滑雪!  

      本期将讨论支持向量机的实现问题,我们知道支持向量机的学习问题可以化为求解凸二次规划问题。这样的凸二次规划问题具有全局最优解,并且有许多最优化算法可以用于这一问题的求解。但是当训练样本容量很大时,这些算法往往变得非常低效,以致无法使用。所以,如何高效地实现支持向量机学习就成为一个重要的问题。目前人们已提出许多快速实现算法。本期讲述其中的序列最小最优化(sequential minimal optimization, SMO)算法。

目录

1、SMO理论推导

 2、python代码与实例

(1)使用线性可分样本,采用SMO算法求解支持向量机分类

(2)使用非线性数据(曲线),采用SMO算法求解支持向量机分类

(3)使用非线性数据(交叉),采用SMO算法求解支持向量机分类

4、参考文献


1、SMO理论推导

       SMO算法要求解如下凸二次规划对偶问题:

       选择两个变量\alpha _{1}\alpha _{2},其他变量固定,于是SMO算法的最优化子问题就变成如下:

       下面,首先求沿着约束方向未经剪辑即未考虑不等式约束时\alpha _{2}的最优解\alpha _{1}^{new.unc};然后再求剪辑后的解\alpha _{2}^{new}。我们用定理来叙述这个结果,为了叙述简单,引入记号记作:

      那么目标函数可写成如下形式:

       \alpha _{2}求导可得:

      令其为0,得到:

     因此,\alpha _{2}最终的解就是:

 2、python代码与实例

(1)使用线性可分样本,采用SMO算法求解支持向量机分类

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs,make_circles,make_moons
from sklearn.preprocessing import StandardScaler
 
    
    
class SMOStruct:
    """构造SMO的数据结构"""
    def __init__(self, X, y, C, kernel, alphas, b, errors, user_linear_optim):
        self.X = X              # 训练样本
        self.y = y              # 类别
        self.C = C              # 正则化常量,用于调整(过)拟合的程度
        self.kernel = kernel    # 核函数,实现了两个核函数,线性和高斯(RBF)
        self.alphas = alphas    # 拉格朗日乘子,与样本一一相对
        self.b = b              # 截距b
        self.errors = errors    # 差值矩阵,用于存储alpha值实际与预测值得差值,其数量与样本一一相对
        
        self.m, self.n = np.shape(self.X)    #m为训练样本的个数和n为样本的维度
                                             
 
        self.user_linear_optim = user_linear_optim    # 选择模型核函数,选择是,则使用线性核函数,否则使用RBF核函数(高斯核函数)
        self.w = np.zeros(self.n)     # 初始化权重w的值,主要用于线性核函数
        #self.b = 0               
 
 
   
 
def linear_kernel(x,y,b=1):
    #线性核函数
    """ returns the linear combination of arrays 'x' and 'y' with
    the optional bias term 'b' (set to 1 by default). """
    result = x @ y.T + b
    return result # 注意矩阵乘法的@运算符
 
    
    
def gaussian_kernel(x,y, sigma=1):
    #高斯核函数
    """设置默认sigma=1 """
 
    if np.ndim(x) == 1 and np.ndim(y) == 1:
        result = np.exp(-(np.linalg.norm(x-y,2))**2/(2*sigma**2))
    elif(np.ndim(x)>1 and np.ndim(y) == 1) or (np.ndim(x) == 1 and np.ndim(y)>1):
        result = np.exp(-(np.linalg.norm(x-y, 2, axis=1)**2)/(2*sigma**2))
    elif np.ndim(x) > 1 and np.ndim(y) > 1 :
        result = np.exp(-(np.linalg.norm(x[:, np.newaxis]- y[np.newaxis, :], 2, axis = 2) ** 2)/(2*sigma**2))
    return result
 
 
 #判别函数1,用于单一样本
def decision_function_output(model,i):
    if model.user_linear_optim:
        #Equation (J1)
        #return float(np.dot(model.w.T, model.X[i])) - model.b
        return float(model.w.T @ model.X[i]) - model.b
    else:
        #Equation (J10)
        return np.sum([model.alphas[j] * model.y[j] * model.kernel(model.X[j], model.X[i]) for j in range(model.m)]) - model.b
 
 
    
# 判别函数2,用于多个样本
def decision_function(alphas, target, kernel, X_train, x_test, b):
    """ Applies the SVM decision function to the input feature vectors in 'x_test'.
    """
    result = (alphas * target) @ kernel(X_train, x_test) - b   # *,@ 两个Operators的区别?
    
    return result
 
    
    
    
    
def plot_decision_boundary(model, ax, resolution = 100, colors=('b','k','r'), levels = (-1, 0, 1)):
    """
    画出分割平面及支持平面,
    用的是等高线的方法
 
    """
 
    #生成横坐标与纵坐标的网格[100x100]
    #随后评估整个空间的模型
    xrange = np.linspace(model.X[:,0].min(), model.X[:, 0].max(), resolution)#取样本当中横坐标x的最小值与最大值,均等分100份
    yrange = np.linspace(model.X[:,1].min(), model.X[:, 1].max(), resolution)#取纵坐标的最小值与最大值,均等分100份
    grid = [[decision_function(model.alphas,model.y, model.kernel, model.X,
                               np.array([xr,yr]), model.b) for xr in xrange] for yr in yrange]
   
    grid = np.array(grid).reshape(len(xrange), len(yrange))
 
 
 
   
    ax.contour(xrange, yrange, grid, levels=levels, linewidths = (1,1,1),
               linestyles = ('--', '-', '--'), colors=colors)   #绘制等高线,展示间隔
    ax.scatter(model.X[:,0], model.X[:, 1],
               c=model.y, cmap = plt.cm.viridis, lw=0, alpha =0.25) #绘制所有样本点的散点图
 
    #as circled points (linewidth >0)
    mask = np.round(model.alphas, decimals = 2) !=0.0
    ax.scatter(model.X[mask,0], model.X[mask,1],
               c=model.y[mask], cmap=plt.cm.viridis, lw=1, edgecolors='k')#画出支持向量(alpha不等于0的点)
 
    return grid, ax
 
    
    
    
    
# 选择了alpha2、 alpha1后,开始第一步优化,然后迭代, “第二层循环,内循环”
# 主要的优化步骤在这里发生
def take_step(i1, i2, model):
   
    #skip if chosen alphas are the same
    if i1 == i2:
        return 0, model
    # a1, a2 的原值,old value,优化在于产生优化后的值,新值 new value

    alph1 = model.alphas[i1]
    alph2 = model.alphas[i2]
   
    y1 = model.y[i1]
    y2 = model.y[i2]
 
    E1 = get_error(model, i1)
    E2 = get_error(model, i2)
    s = y1 * y2
 
    # 计算alpha的边界,L, H
    # compute L & H, the bounds on new possible alpha values
    if(y1 != y2):   
        #y1,y2 异号,使用 Equation (J13)
        L = max(0, alph2 - alph1)
        H = min(model.C, model.C + alph2 - alph1)
    elif (y1 == y2):
        #y1,y2 同号,使用 Equation (J14)
        L = max(0, alph1+alph2 - model.C)
        H = min(model.C, alph1 + alph2)
    if (L==H):
        return 0, model
 
    #分别计算样本1, 2对应的核函数组合,目的在于计算eta
    #也就是求一阶导数后的值,目的在于计算a2new
    k11 = model.kernel(model.X[i1], model.X[i1])
    k12 = model.kernel(model.X[i1], model.X[i2])
    k22 = model.kernel(model.X[i2], model.X[i2])
    #计算 eta,equation (J15)
    eta = k11 + k22 - 2*k12
    
    #如论文中所述,分两种情况根据eta为正positive 还是为负或0来计算计算a2 new
    
    if(eta>0): 
        #equation (J16) 计算alpha2
        a2 = alph2 + y2 * (E1 - E2)/eta
        #clip a2 based on bounds L & H
        #把a2夹到限定区间 equation (J17)
        if L < a2 < H:
            a2 = a2
        elif (a2 <= L):
            a2 = L
        elif (a2 >= H):
            a2 = H
    #如果eta不为正(为负或0)
    #if eta is non-positive, move new a2 to bound with greater objective function value
    else:
        # Equation (J19)
        # 在特殊情况下,eta可能不为正not be positive
        f1 = y1*(E1 + model.b) - alph1*k11 - s*alph2*k12
        f2 = y2 * (E2 + model.b) - s* alph1 * k12 - alph2 * k22
 
        L1 = alph1 + s*(alph2 - L)
        H1 = alph1 + s*(alph2 - H)
 
        Lobj = L1 * f1 + L * f2 + 0.5 * (L1 ** 2) * k11 \
               + 0.5 * (L**2) * k22 + s * L * L1 * k12
               
        Hobj = H1 * f1 + H * f2 + 0.5 * (H1**2) * k11 \
               + 0.5 * (H**2) * k22 + s * H * H1 * k12
               
        if Lobj < Hobj - eps:
            a2 = L
        elif Lobj > Hobj + eps:
            a2 = H
        else:
            a2 = alph2
 
    #当new a2 千万分之一接近C或0是,就让它等于C或0
    if a2 <1e-8:
        a2 = 0.0
    elif a2 > (model.C - 1e-8):
        a2 = model.C
    #超过容差仍不能优化时,跳过
    #If examples can't be optimized within epsilon(eps), skip this pair
    if (np.abs(a2 - alph2) < eps * (a2 + alph2 + eps)):
        return 0, model
    a1 = alph1 + s * (alph2 - a2)    #根据新 a2计算 新 a1 Equation(J18)
    b1 = E1 + y1*(a1 - alph1) * k11 + y2 * (a2 - alph2) * k12 + model.b   #更新截距b的值 Equation (J20)
    b2 = E2 + y1*(a1 - alph1) * k12 + y2 * (a2 - alph2) * k22 + model.b  #equation (J21)
    # Set new threshoold based on if a1 or a2 is bound by L and/or H
    if 0 < a1 and a1 < C:
        b_new =b1
    elif 0 < a2 and a2 < C:
        b_new = b2
    #Average thresholds if both are bound
    else:
        b_new = (b1 + b2) * 0.5
    #update model threshold
    model.b = b_new
    # 当所训练模型为线性核函数时
    #Equation (J22) 计算w的值
    if model.user_linear_optim:
         model.w = model.w + y1 * (a1 - alph1)*model.X[i1] + y2 * (a2 - alph2) * model.X[i2]
    #在alphas矩阵中分别更新a1, a2的值
    #Update model object with new alphas & threshold
    model.alphas[i1] = a1
    model.alphas[i2] = a2
    #优化完成,更新差值矩阵的对应值
    #同时更新差值矩阵其它值
    model.errors[i1] = 0
    model.errors[i2] = 0
    #更新差值 Equation (12)
    for i in range(model.m):
        if 0 < model.alphas[i] < model.C:
            model.errors[i] += y1*(a1 - alph1)*model.kernel(model.X[i1],model.X[i]) + \
                            y2*(a2 - alph2)*model.kernel(model.X[i2], model.X[i]) + model.b - b_new
    return 1, model

def get_error(model, i1):
    if 0< model.alphas[i1] <model.C:
        return model.errors[i1]
    else:
        return decision_function_output(model,i1) - model.y[i1]


    
    
def examine_example(i2, model):
    y2 = model.y[i2]
    alph2 = model.alphas[i2]
    E2 = get_error(model, i2)
    r2 = E2 * y2
    #重点:这一段的重点在于确定 alpha1, 也就是old a1,并送到take_step去analytically 优化
    # 下面条件之一满足,进入if开始找第二个alpha,送到take_step进行优化
    if ((r2 < -tol and alph2 < model.C) or (r2 > tol and alph2 > 0)):
        if len(model.alphas[(model.alphas != 0) & (model.alphas != model.C)]) > 1:#筛选器
            #选择Ei矩阵中差值最大的先进性优化
            # 要想|E1-E2|最大,只需要在E2为正时,选择最小的Ei作为E1
            # 在E2为负时选择最大的Ei作为E1
            if model.errors[i2] > 0:
                i1 = np.argmin(model.errors)
            elif model.errors[i2] <= 0:
                i1 = np.argmax(model.errors)
            step_result,model = take_step(i1,i2, model)
            if step_result:
                return 1, model
        # 循环所有非0 非C alphas值进行优化,随机选择起始点
        for i1 in np.roll(np.where((model.alphas != 0) & (model.alphas != model.C))[0],
                          np.random.choice(np.arange(model.m))):
            step_result, model = take_step(i1, i2, model)
            if step_result:
                return 1, model
        
        #alpha2确定的情况下,如何选择alpha1? 循环所有(m-1) alphas, 随机选择起始点
        for i1 in np.roll(np.arange(model.m), np.random.choice(np.arange(model.m))):
            #print("what is the first i1",i1)
            step_result, model = take_step(i1, i2, model)
           
            if step_result:
                return 1, model
    #先看最上面的if语句,如果if条件不满足,说明KKT条件已满足,找其它样本进行优化,则执行下面这句,退出
    return 0, model


#核心函数
def fit(model):
   
    numChanged = 0  #numChanged存放优化返回的结果,如果优化成功,则返回1,反之为0
    examineAll = 1  #examineAll表示从0号元素开始优化,如果所有都优化完成,则赋值为0
    #loop num record
    #计数器,记录优化时的循环次数
    loopnum = 0
    loopnum1 = 0
    loopnum2 = 0
    # 当numChanged = 0 and examineAll = 0时 循环退出
    # 实际是顺序地执行完所有的样本,也就是第一个if中的循环,
    # 并且 else中的循环没有可优化的alpha,目标函数收敛了: 在容差之内,并且满足KKT条件
    # 则循环退出,如果执行2000次循环仍未收敛,也退出
    # 重点:这段的重点在于确定 alpha2,也就是old a 2, 或者说alpha2的下标,old a2和old a1都是heuristically 选择
    while(numChanged > 0) or (examineAll): 
        numChanged = 0
        if loopnum == 2000:#设置循环次数
            break
        loopnum = loopnum + 1
        if examineAll:
            loopnum1 = loopnum1 + 1 # 记录顺序一个一个选择alpha2时的循环次数
            # # 从0,1,2,3,...,m顺序选择a2的,送给examine_example选择alpha1,总共m(m-1)种选法
            for i in range(model.alphas.shape[0]): 
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        else:  #上面if里m(m-1)执行完的后执行 
            loopnum2 = loopnum2 + 1
            # loop over examples where alphas are not already at their limits
            for i in np.where((model.alphas != 0) & (model.alphas != model.C))[0]:#筛选器,用于筛选alpha
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        if examineAll == 1:
            examineAll = 0
        elif numChanged == 0:
            examineAll = 1
    print("loopnum012",loopnum,":", loopnum1,":", loopnum2)   
    return model
# can be replaced as per different model u want to show

#主程序部分
# 生成测试数据,训练样本
X_train, y = make_blobs(n_samples = 1000, centers =2, n_features=2, random_state = 3)
#make_blobs表示是 sklearn.datasets中的一个函数,主要是产生聚类数据集,产生一个数据集和相应的标签
#random_state表示可以固定生成的数据,给定数之后,每次生成的数据集就是固定的
# center表示标签的种类数

scaler = StandardScaler()                            
X_train_scaled = scaler.fit_transform(X_train, y)# 标准化,训练样本异常大或异常小会影响样本的正确训练,如果数据的分布很分散也会影响 
y=2*y-1#按照支持向量机惯例,将响应变量的取值由{0,1}变换为{-1,1}
# set model parameters and initial values
C = 20.0 #为一个超参数,惩罚参数,自行设定
m = len(X_train_scaled)#计算标准化后训练集的个数
initial_alphas=np.zeros(m)#定义初始化alpha,返回一个元素全为0且长度等于训练集个数的数组,我们的目标就是找所有的alpha值,使目标函数最优,
                          #只有样本点在间隔内才不为0,其他均为0     
initial_b=0.0#初始化截距
tol = 0.01 # #软间隔优化目标的ε允许样本错误的参数
eps = 0.01 # 设置允许的终止判据(默认为0.001)
#初始化smo数据结构
model = SMOStruct(X_train_scaled, y, C, linear_kernel, initial_alphas, initial_b, np.zeros(m),user_linear_optim=True)
#print("model created ...")
#初始化差错矩阵,调用判别函数,差错矩阵为预测值与真实值的的差
initial_error = decision_function(model.alphas, model.y, model.kernel, model.X, model.X, model.b) - model.y
model.errors = initial_error
np.random.seed(0)
#主函数到此结束



 
# 初始化smo结构,使用高斯核函数
model = SMOStruct(X_train_scaled, y, C, lambda x, y: gaussian_kernel(x,y,sigma=0.5),
                  initial_alphas, initial_b, np.zeros(m), user_linear_optim=False)
 
#initialize error cache
initial_error = decision_function(model.alphas, model.y, model.kernel,
                                   model.X, model.X, model.b) - model.y
model.errors = initial_error  

print("开始拟合模型...")
#开始训练
output = fit(model)
#绘制训练完,找到分割平面的图
fig,ax = plt.subplots()
grid,ax = plot_decision_boundary(output, ax)
plt.savefig("squares1.png",
            bbox_inches ="tight",
            pad_inches = 1,
            transparent = True,
            facecolor ="w",
            edgecolor ='w',
            dpi=300,
            orientation ='landscape')

输出结果:

开始拟合模型...
loopnum012 2000 : 1 : 1999

(2)使用非线性数据(曲线),采用SMO算法求解支持向量机分类

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs,make_circles,make_moons
from sklearn.preprocessing import StandardScaler
 
    
    
class SMOStruct:
    """构造SMO的数据结构"""
    def __init__(self, X, y, C, kernel, alphas, b, errors, user_linear_optim):
        self.X = X              # 训练样本
        self.y = y              # 类别
        self.C = C              # 正则化常量,用于调整(过)拟合的程度
        self.kernel = kernel    # 核函数,实现了两个核函数,线性和高斯(RBF)
        self.alphas = alphas    # 拉格朗日乘子,与样本一一相对
        self.b = b              # 截距b
        self.errors = errors    # 差值矩阵,用于存储alpha值实际与预测值得差值,其数量与样本一一相对
        
        self.m, self.n = np.shape(self.X)    #m为训练样本的个数和n为样本的维度
                                             
 
        self.user_linear_optim = user_linear_optim    # 选择模型核函数,选择是,则使用线性核函数,否则使用RBF核函数(高斯核函数)
        self.w = np.zeros(self.n)     # 初始化权重w的值,主要用于线性核函数
        #self.b = 0               
 
 
   
 
def linear_kernel(x,y,b=1):
    #线性核函数
    """ returns the linear combination of arrays 'x' and 'y' with
    the optional bias term 'b' (set to 1 by default). """
    result = x @ y.T + b
    return result # 注意矩阵乘法的@运算符
 
  
    
def gaussian_kernel(x,y, sigma=1):
    #高斯核函数
    """设置默认sigma=1 """
 
    if np.ndim(x) == 1 and np.ndim(y) == 1:
        result = np.exp(-(np.linalg.norm(x-y,2))**2/(2*sigma**2))
    elif(np.ndim(x)>1 and np.ndim(y) == 1) or (np.ndim(x) == 1 and np.ndim(y)>1):
        result = np.exp(-(np.linalg.norm(x-y, 2, axis=1)**2)/(2*sigma**2))
    elif np.ndim(x) > 1 and np.ndim(y) > 1 :
        result = np.exp(-(np.linalg.norm(x[:, np.newaxis]- y[np.newaxis, :], 2, axis = 2) ** 2)/(2*sigma**2))
    return result
 
 
 #判别函数1,用于单一样本
def decision_function_output(model,i):
    if model.user_linear_optim:
        #Equation (J1)
        #return float(np.dot(model.w.T, model.X[i])) - model.b
        return float(model.w.T @ model.X[i]) - model.b
    else:
        #Equation (J10)
        return np.sum([model.alphas[j] * model.y[j] * model.kernel(model.X[j], model.X[i]) for j in range(model.m)]) - model.b
 
 
    
# 判别函数2,用于多个样本
def decision_function(alphas, target, kernel, X_train, x_test, b):
    """ Applies the SVM decision function to the input feature vectors in 'x_test'.
    """
    result = (alphas * target) @ kernel(X_train, x_test) - b   # *,@ 两个Operators的区别?
    
    return result
 
    
    
    
    
def plot_decision_boundary(model, ax, resolution = 100, colors=('b','k','r'), levels = (-1, 0, 1)):
    """
    画出分割平面及支持平面,
    用的是等高线的方法
 
    """

    #生成横坐标与纵坐标的网格[100x100]
    #随后评估整个空间的模型
    xrange = np.linspace(model.X[:,0].min(), model.X[:, 0].max(), resolution)#取样本当中横坐标x的最小值与最大值,均等分100份
    yrange = np.linspace(model.X[:,1].min(), model.X[:, 1].max(), resolution)#取纵坐标的最小值与最大值,均等分100份
    grid = [[decision_function(model.alphas,model.y, model.kernel, model.X,
                               np.array([xr,yr]), model.b) for xr in xrange] for yr in yrange]
   
    grid = np.array(grid).reshape(len(xrange), len(yrange))
 
 
 
   
    ax.contour(xrange, yrange, grid, levels=levels, linewidths = (1,1,1),
               linestyles = ('--', '-', '--'), colors=colors)   #绘制等高线,展示间隔
    ax.scatter(model.X[:,0], model.X[:, 1],
               c=model.y, cmap = plt.cm.viridis, lw=0, alpha =0.25) #绘制所有样本点的散点图
 
    #as circled points (linewidth >0)
    mask = np.round(model.alphas, decimals = 2) !=0.0
    ax.scatter(model.X[mask,0], model.X[mask,1],
               c=model.y[mask], cmap=plt.cm.viridis, lw=1, edgecolors='k')#画出支持向量(alpha不等于0的点)
 
    return grid, ax
 
    
   
    
# 选择了alpha2、 alpha1后,开始第一步优化,然后迭代, “第二层循环,内循环”
# 主要的优化步骤在这里发生
def take_step(i1, i2, model):
   
    #skip if chosen alphas are the same
    if i1 == i2:
        return 0, model
    # a1, a2 的原值,old value,优化在于产生优化后的值,新值 new value

    alph1 = model.alphas[i1]
    alph2 = model.alphas[i2]
   
    y1 = model.y[i1]
    y2 = model.y[i2]
 
    E1 = get_error(model, i1)
    E2 = get_error(model, i2)
    s = y1 * y2
 
    # 计算alpha的边界,L, H
    # compute L & H, the bounds on new possible alpha values
    if(y1 != y2):   
        #y1,y2 异号,使用 Equation (J13)
        L = max(0, alph2 - alph1)
        H = min(model.C, model.C + alph2 - alph1)
    elif (y1 == y2):
        #y1,y2 同号,使用 Equation (J14)
        L = max(0, alph1+alph2 - model.C)
        H = min(model.C, alph1 + alph2)
    if (L==H):
        return 0, model
 
    #分别计算样本1, 2对应的核函数组合,目的在于计算eta
    #也就是求一阶导数后的值,目的在于计算a2new
    k11 = model.kernel(model.X[i1], model.X[i1])
    k12 = model.kernel(model.X[i1], model.X[i2])
    k22 = model.kernel(model.X[i2], model.X[i2])
    #计算 eta,equation (J15)
    eta = k11 + k22 - 2*k12
    
    #如论文中所述,分两种情况根据eta为正positive 还是为负或0来计算计算a2 new
    
    if(eta>0): 
        #equation (J16) 计算alpha2
        a2 = alph2 + y2 * (E1 - E2)/eta
        #clip a2 based on bounds L & H
        #把a2夹到限定区间 equation (J17)
        if L < a2 < H:
            a2 = a2
        elif (a2 <= L):
            a2 = L
        elif (a2 >= H):
            a2 = H
    #如果eta不为正(为负或0)
    #if eta is non-positive, move new a2 to bound with greater objective function value
    else:
        # Equation (J19)
        # 在特殊情况下,eta可能不为正not be positive
        f1 = y1*(E1 + model.b) - alph1*k11 - s*alph2*k12
        f2 = y2 * (E2 + model.b) - s* alph1 * k12 - alph2 * k22
 
        L1 = alph1 + s*(alph2 - L)
        H1 = alph1 + s*(alph2 - H)
 
        Lobj = L1 * f1 + L * f2 + 0.5 * (L1 ** 2) * k11 \
               + 0.5 * (L**2) * k22 + s * L * L1 * k12
               
        Hobj = H1 * f1 + H * f2 + 0.5 * (H1**2) * k11 \
               + 0.5 * (H**2) * k22 + s * H * H1 * k12
               
        if Lobj < Hobj - eps:
            a2 = L
        elif Lobj > Hobj + eps:
            a2 = H
        else:
            a2 = alph2
 
    #当new a2 千万分之一接近C或0是,就让它等于C或0
    if a2 <1e-8:
        a2 = 0.0
    elif a2 > (model.C - 1e-8):
        a2 = model.C
    #超过容差仍不能优化时,跳过
    #If examples can't be optimized within epsilon(eps), skip this pair
    if (np.abs(a2 - alph2) < eps * (a2 + alph2 + eps)):
        return 0, model
    a1 = alph1 + s * (alph2 - a2)    #根据新 a2计算 新 a1 Equation(J18)
    b1 = E1 + y1*(a1 - alph1) * k11 + y2 * (a2 - alph2) * k12 + model.b   #更新截距b的值 Equation (J20)
    b2 = E2 + y1*(a1 - alph1) * k12 + y2 * (a2 - alph2) * k22 + model.b  #equation (J21)
    # Set new threshoold based on if a1 or a2 is bound by L and/or H
    if 0 < a1 and a1 < C:
        b_new =b1
    elif 0 < a2 and a2 < C:
        b_new = b2
    #Average thresholds if both are bound
    else:
        b_new = (b1 + b2) * 0.5
    #update model threshold
    model.b = b_new
    # 当所训练模型为线性核函数时
    #Equation (J22) 计算w的值
    if model.user_linear_optim:
         model.w = model.w + y1 * (a1 - alph1)*model.X[i1] + y2 * (a2 - alph2) * model.X[i2]
    #在alphas矩阵中分别更新a1, a2的值
    #Update model object with new alphas & threshold
    model.alphas[i1] = a1
    model.alphas[i2] = a2
    #优化完成,更新差值矩阵的对应值
    #同时更新差值矩阵其它值
    model.errors[i1] = 0
    model.errors[i2] = 0
    #更新差值 Equation (12)
    for i in range(model.m):
        if 0 < model.alphas[i] < model.C:
            model.errors[i] += y1*(a1 - alph1)*model.kernel(model.X[i1],model.X[i]) + \
                            y2*(a2 - alph2)*model.kernel(model.X[i2], model.X[i]) + model.b - b_new
    return 1, model

def get_error(model, i1):
    if 0< model.alphas[i1] <model.C:
        return model.errors[i1]
    else:
        return decision_function_output(model,i1) - model.y[i1]


    
    
def examine_example(i2, model):
    y2 = model.y[i2]
    alph2 = model.alphas[i2]
    E2 = get_error(model, i2)
    r2 = E2 * y2
    #重点:这一段的重点在于确定 alpha1, 也就是old a1,并送到take_step去analytically 优化
    # 下面条件之一满足,进入if开始找第二个alpha,送到take_step进行优化
    if ((r2 < -tol and alph2 < model.C) or (r2 > tol and alph2 > 0)):
        if len(model.alphas[(model.alphas != 0) & (model.alphas != model.C)]) > 1:#筛选器
            #选择Ei矩阵中差值最大的先进性优化
            # 要想|E1-E2|最大,只需要在E2为正时,选择最小的Ei作为E1
            # 在E2为负时选择最大的Ei作为E1
            if model.errors[i2] > 0:
                i1 = np.argmin(model.errors)
            elif model.errors[i2] <= 0:
                i1 = np.argmax(model.errors)
            step_result,model = take_step(i1,i2, model)
            if step_result:
                return 1, model
        # 循环所有非0 非C alphas值进行优化,随机选择起始点
        for i1 in np.roll(np.where((model.alphas != 0) & (model.alphas != model.C))[0],
                          np.random.choice(np.arange(model.m))):
            step_result, model = take_step(i1, i2, model)
            if step_result:
                return 1, model
        
        #alpha2确定的情况下,如何选择alpha1? 循环所有(m-1) alphas, 随机选择起始点
        for i1 in np.roll(np.arange(model.m), np.random.choice(np.arange(model.m))):
            #print("what is the first i1",i1)
            step_result, model = take_step(i1, i2, model)
           
            if step_result:
                return 1, model
    #先看最上面的if语句,如果if条件不满足,说明KKT条件已满足,找其它样本进行优化,则执行下面这句,退出
    return 0, model


#核心函数
def fit(model):
   
    numChanged = 0  #numChanged存放优化返回的结果,如果优化成功,则返回1,反之为0
    examineAll = 1  #examineAll表示从0号元素开始优化,如果所有都优化完成,则赋值为0
    #loop num record
    #计数器,记录优化时的循环次数
    loopnum = 0
    loopnum1 = 0
    loopnum2 = 0
    # 当numChanged = 0 and examineAll = 0时 循环退出
    # 实际是顺序地执行完所有的样本,也就是第一个if中的循环,
    # 并且 else中的循环没有可优化的alpha,目标函数收敛了: 在容差之内,并且满足KKT条件
    # 则循环退出,如果执行2000次循环仍未收敛,也退出
    # 重点:这段的重点在于确定 alpha2,也就是old a 2, 或者说alpha2的下标,old a2和old a1都是heuristically 选择
    while(numChanged > 0) or (examineAll): 
        numChanged = 0
        if loopnum == 2000:#设置循环次数
            break
        loopnum = loopnum + 1
        if examineAll:
            loopnum1 = loopnum1 + 1 # 记录顺序一个一个选择alpha2时的循环次数
            # # 从0,1,2,3,...,m顺序选择a2的,送给examine_example选择alpha1,总共m(m-1)种选法
            for i in range(model.alphas.shape[0]): 
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        else:  #上面if里m(m-1)执行完的后执行 
            loopnum2 = loopnum2 + 1
            # loop over examples where alphas are not already at their limits
            for i in np.where((model.alphas != 0) & (model.alphas != model.C))[0]:#筛选器,用于筛选alpha
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        if examineAll == 1:
            examineAll = 0
        elif numChanged == 0:
            examineAll = 1
    print("loopnum012",loopnum,":", loopnum1,":", loopnum2)   
    return model
# can be replaced as per different model u want to show


#产生非线性数据,交叉的
X_train,y = make_moons(n_samples = 500, noise=0.2,
                        random_state =1)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train, y)
y=2*y-1
 
#print('X_train',':', X_train)
# print('y',':',y)
 
#Set model parameters and initial values
C = 1.0
m = len(X_train_scaled)
initial_alphas = np.zeros(m)
initial_b = 0.0
 
# Set tolerances
tol = 0.01 # error tolerance
eps = 0.01 # alpha tolerance
 
# 初始化smo结构,使用高斯核函数
model = SMOStruct(X_train_scaled, y, C, lambda x, y: gaussian_kernel(x,y,sigma=0.5),
                  initial_alphas, initial_b, np.zeros(m), user_linear_optim=False)
 
#initialize error cache
#先把这个注释掉
initial_error = decision_function(model.alphas, model.y, model.kernel,
                                   model.X, model.X, model.b) - model.y
model.errors = initial_error 

 

print("开始拟合模型...")
#开始训练
output = fit(model)
#绘制训练完,找到分割平面的图
fig,ax = plt.subplots()
grid,ax = plot_decision_boundary(output, ax)

plt.savefig("squares1.png",
            bbox_inches ="tight",
            pad_inches = 1,
            transparent = True,
            facecolor ="w",
            edgecolor ='w',
            dpi=300,
            orientation ='landscape')

输出结果:

开始拟合模型...
loopnum012 2000 : 9 : 1991

(3)使用非线性数据(交叉),采用SMO算法求解支持向量机分类

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs,make_circles,make_moons
from sklearn.preprocessing import StandardScaler
 
    
    
class SMOStruct:
    """构造SMO的数据结构"""
    def __init__(self, X, y, C, kernel, alphas, b, errors, user_linear_optim):
        self.X = X              # 训练样本
        self.y = y              # 类别
        self.C = C              # 正则化常量,用于调整(过)拟合的程度
        self.kernel = kernel    # 核函数,实现了两个核函数,线性和高斯(RBF)
        self.alphas = alphas    # 拉格朗日乘子,与样本一一相对
        self.b = b              # 截距b
        self.errors = errors    # 差值矩阵,用于存储alpha值实际与预测值得差值,其数量与样本一一相对
        
        self.m, self.n = np.shape(self.X)    #m为训练样本的个数和n为样本的维度
                                             
 
        self.user_linear_optim = user_linear_optim    # 选择模型核函数,选择是,则使用线性核函数,否则使用RBF核函数(高斯核函数)
        self.w = np.zeros(self.n)     # 初始化权重w的值,主要用于线性核函数
        #self.b = 0               
 
 
   
 
def linear_kernel(x,y,b=1):
    #线性核函数
    """ returns the linear combination of arrays 'x' and 'y' with
    the optional bias term 'b' (set to 1 by default). """
    result = x @ y.T + b
    return result # 注意矩阵乘法的@运算符
 
    
    
def gaussian_kernel(x,y, sigma=1):
    #高斯核函数
    """设置默认sigma=1 """
 
    if np.ndim(x) == 1 and np.ndim(y) == 1:
        result = np.exp(-(np.linalg.norm(x-y,2))**2/(2*sigma**2))
    elif(np.ndim(x)>1 and np.ndim(y) == 1) or (np.ndim(x) == 1 and np.ndim(y)>1):
        result = np.exp(-(np.linalg.norm(x-y, 2, axis=1)**2)/(2*sigma**2))
    elif np.ndim(x) > 1 and np.ndim(y) > 1 :
        result = np.exp(-(np.linalg.norm(x[:, np.newaxis]- y[np.newaxis, :], 2, axis = 2) ** 2)/(2*sigma**2))
    return result
 
 
 #判别函数1,用于单一样本
def decision_function_output(model,i):
    if model.user_linear_optim:
        #Equation (J1)
        #return float(np.dot(model.w.T, model.X[i])) - model.b
        return float(model.w.T @ model.X[i]) - model.b
    else:
        #Equation (J10)
        return np.sum([model.alphas[j] * model.y[j] * model.kernel(model.X[j], model.X[i]) for j in range(model.m)]) - model.b
 
 
    
# 判别函数2,用于多个样本
def decision_function(alphas, target, kernel, X_train, x_test, b):
    """ Applies the SVM decision function to the input feature vectors in 'x_test'.
    """
    result = (alphas * target) @ kernel(X_train, x_test) - b   # *,@ 两个Operators的区别?
    
    return result
 
    
    
    
    
def plot_decision_boundary(model, ax, resolution = 100, colors=('b','k','r'), levels = (-1, 0, 1)):
    """
    画出分割平面及支持平面,
    用的是等高线的方法
 
    """
 
    #生成横坐标与纵坐标的网格[100x100]
    #随后评估整个空间的模型
    xrange = np.linspace(model.X[:,0].min(), model.X[:, 0].max(), resolution)#取样本当中横坐标x的最小值与最大值,均等分100份
    yrange = np.linspace(model.X[:,1].min(), model.X[:, 1].max(), resolution)#取纵坐标的最小值与最大值,均等分100份
    grid = [[decision_function(model.alphas,model.y, model.kernel, model.X,
                               np.array([xr,yr]), model.b) for xr in xrange] for yr in yrange]
   
    grid = np.array(grid).reshape(len(xrange), len(yrange))
 
 
 
   
    ax.contour(xrange, yrange, grid, levels=levels, linewidths = (1,1,1),
               linestyles = ('--', '-', '--'), colors=colors)   #绘制等高线,展示间隔
    ax.scatter(model.X[:,0], model.X[:, 1],
               c=model.y, cmap = plt.cm.viridis, lw=0, alpha =0.25) #绘制所有样本点的散点图
 
    #as circled points (linewidth >0)
    mask = np.round(model.alphas, decimals = 2) !=0.0
    ax.scatter(model.X[mask,0], model.X[mask,1],
               c=model.y[mask], cmap=plt.cm.viridis, lw=1, edgecolors='k')#画出支持向量(alpha不等于0的点)
 
    return grid, ax
 
    
    
    
    
# 选择了alpha2、 alpha1后,开始第一步优化,然后迭代, “第二层循环,内循环”
# 主要的优化步骤在这里发生
def take_step(i1, i2, model):
   
    #skip if chosen alphas are the same
    if i1 == i2:
        return 0, model
    # a1, a2 的原值,old value,优化在于产生优化后的值,新值 new value

    alph1 = model.alphas[i1]
    alph2 = model.alphas[i2]
   
    y1 = model.y[i1]
    y2 = model.y[i2]
 
    E1 = get_error(model, i1)
    E2 = get_error(model, i2)
    s = y1 * y2
 
    # 计算alpha的边界,L, H
    # compute L & H, the bounds on new possible alpha values
    if(y1 != y2):   
        #y1,y2 异号,使用 Equation (J13)
        L = max(0, alph2 - alph1)
        H = min(model.C, model.C + alph2 - alph1)
    elif (y1 == y2):
        #y1,y2 同号,使用 Equation (J14)
        L = max(0, alph1+alph2 - model.C)
        H = min(model.C, alph1 + alph2)
    if (L==H):
        return 0, model
 
    #分别计算样本1, 2对应的核函数组合,目的在于计算eta
    #也就是求一阶导数后的值,目的在于计算a2new
    k11 = model.kernel(model.X[i1], model.X[i1])
    k12 = model.kernel(model.X[i1], model.X[i2])
    k22 = model.kernel(model.X[i2], model.X[i2])
    #计算 eta,equation (J15)
    eta = k11 + k22 - 2*k12
    
    #如论文中所述,分两种情况根据eta为正positive 还是为负或0来计算计算a2 new
    
    if(eta>0): 
        #equation (J16) 计算alpha2
        a2 = alph2 + y2 * (E1 - E2)/eta
        #clip a2 based on bounds L & H
        #把a2夹到限定区间 equation (J17)
        if L < a2 < H:
            a2 = a2
        elif (a2 <= L):
            a2 = L
        elif (a2 >= H):
            a2 = H
    #如果eta不为正(为负或0)
    #if eta is non-positive, move new a2 to bound with greater objective function value
    else:
        # Equation (J19)
        # 在特殊情况下,eta可能不为正not be positive
        f1 = y1*(E1 + model.b) - alph1*k11 - s*alph2*k12
        f2 = y2 * (E2 + model.b) - s* alph1 * k12 - alph2 * k22
 
        L1 = alph1 + s*(alph2 - L)
        H1 = alph1 + s*(alph2 - H)
 
        Lobj = L1 * f1 + L * f2 + 0.5 * (L1 ** 2) * k11 \
               + 0.5 * (L**2) * k22 + s * L * L1 * k12
               
        Hobj = H1 * f1 + H * f2 + 0.5 * (H1**2) * k11 \
               + 0.5 * (H**2) * k22 + s * H * H1 * k12
               
        if Lobj < Hobj - eps:
            a2 = L
        elif Lobj > Hobj + eps:
            a2 = H
        else:
            a2 = alph2
 
    #当new a2 千万分之一接近C或0是,就让它等于C或0
    if a2 <1e-8:
        a2 = 0.0
    elif a2 > (model.C - 1e-8):
        a2 = model.C
    #超过容差仍不能优化时,跳过
    #If examples can't be optimized within epsilon(eps), skip this pair
    if (np.abs(a2 - alph2) < eps * (a2 + alph2 + eps)):
        return 0, model
    a1 = alph1 + s * (alph2 - a2)    #根据新 a2计算 新 a1 Equation(J18)
    b1 = E1 + y1*(a1 - alph1) * k11 + y2 * (a2 - alph2) * k12 + model.b   #更新截距b的值 Equation (J20)
    b2 = E2 + y1*(a1 - alph1) * k12 + y2 * (a2 - alph2) * k22 + model.b  #equation (J21)
    # Set new threshoold based on if a1 or a2 is bound by L and/or H
    if 0 < a1 and a1 < C:
        b_new =b1
    elif 0 < a2 and a2 < C:
        b_new = b2
    #Average thresholds if both are bound
    else:
        b_new = (b1 + b2) * 0.5
    #update model threshold
    model.b = b_new
    # 当所训练模型为线性核函数时
    #Equation (J22) 计算w的值
    if model.user_linear_optim:
         model.w = model.w + y1 * (a1 - alph1)*model.X[i1] + y2 * (a2 - alph2) * model.X[i2]
    #在alphas矩阵中分别更新a1, a2的值
    #Update model object with new alphas & threshold
    model.alphas[i1] = a1
    model.alphas[i2] = a2
    #优化完成,更新差值矩阵的对应值
    #同时更新差值矩阵其它值
    model.errors[i1] = 0
    model.errors[i2] = 0
    #更新差值 Equation (12)
    for i in range(model.m):
        if 0 < model.alphas[i] < model.C:
            model.errors[i] += y1*(a1 - alph1)*model.kernel(model.X[i1],model.X[i]) + \
                            y2*(a2 - alph2)*model.kernel(model.X[i2], model.X[i]) + model.b - b_new
    return 1, model

def get_error(model, i1):
    if 0< model.alphas[i1] <model.C:
        return model.errors[i1]
    else:
        return decision_function_output(model,i1) - model.y[i1]


    
    
def examine_example(i2, model):
    y2 = model.y[i2]
    alph2 = model.alphas[i2]
    E2 = get_error(model, i2)
    r2 = E2 * y2
    #重点:这一段的重点在于确定 alpha1, 也就是old a1,并送到take_step去analytically 优化
    # 下面条件之一满足,进入if开始找第二个alpha,送到take_step进行优化
    if ((r2 < -tol and alph2 < model.C) or (r2 > tol and alph2 > 0)):
        if len(model.alphas[(model.alphas != 0) & (model.alphas != model.C)]) > 1:#筛选器
            #选择Ei矩阵中差值最大的先进性优化
            # 要想|E1-E2|最大,只需要在E2为正时,选择最小的Ei作为E1
            # 在E2为负时选择最大的Ei作为E1
            if model.errors[i2] > 0:
                i1 = np.argmin(model.errors)
            elif model.errors[i2] <= 0:
                i1 = np.argmax(model.errors)
            step_result,model = take_step(i1,i2, model)
            if step_result:
                return 1, model
        # 循环所有非0 非C alphas值进行优化,随机选择起始点
        for i1 in np.roll(np.where((model.alphas != 0) & (model.alphas != model.C))[0],
                          np.random.choice(np.arange(model.m))):
            step_result, model = take_step(i1, i2, model)
            if step_result:
                return 1, model
        
        #alpha2确定的情况下,如何选择alpha1? 循环所有(m-1) alphas, 随机选择起始点
        for i1 in np.roll(np.arange(model.m), np.random.choice(np.arange(model.m))):
            #print("what is the first i1",i1)
            step_result, model = take_step(i1, i2, model)
           
            if step_result:
                return 1, model
    #先看最上面的if语句,如果if条件不满足,说明KKT条件已满足,找其它样本进行优化,则执行下面这句,退出
    return 0, model


#核心函数
def fit(model):
   
    numChanged = 0  #numChanged存放优化返回的结果,如果优化成功,则返回1,反之为0
    examineAll = 1  #examineAll表示从0号元素开始优化,如果所有都优化完成,则赋值为0
    #loop num record
    #计数器,记录优化时的循环次数
    loopnum = 0
    loopnum1 = 0
    loopnum2 = 0
    # 当numChanged = 0 and examineAll = 0时 循环退出
    # 实际是顺序地执行完所有的样本,也就是第一个if中的循环,
    # 并且 else中的循环没有可优化的alpha,目标函数收敛了: 在容差之内,并且满足KKT条件
    # 则循环退出,如果执行2000次循环仍未收敛,也退出
    # 重点:这段的重点在于确定 alpha2,也就是old a 2, 或者说alpha2的下标,old a2和old a1都是heuristically 选择
    while(numChanged > 0) or (examineAll): 
        numChanged = 0
        if loopnum == 2000:#设置循环次数
            break
        loopnum = loopnum + 1
        if examineAll:
            loopnum1 = loopnum1 + 1 # 记录顺序一个一个选择alpha2时的循环次数
            # # 从0,1,2,3,...,m顺序选择a2的,送给examine_example选择alpha1,总共m(m-1)种选法
            for i in range(model.alphas.shape[0]): 
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        else:  #上面if里m(m-1)执行完的后执行 
            loopnum2 = loopnum2 + 1
            # loop over examples where alphas are not already at their limits
            for i in np.where((model.alphas != 0) & (model.alphas != model.C))[0]:#筛选器,用于筛选alpha
                examine_result, model = examine_example(i, model)
                numChanged += examine_result
        if examineAll == 1:
            examineAll = 0
        elif numChanged == 0:
            examineAll = 1
    print("loopnum012",loopnum,":", loopnum1,":", loopnum2)   
    return model
# can be replaced as per different model u want to show



#产生非线性数据,曲线的
X_train, y = make_circles(n_samples=500, noise=0.2,factor=0.1,random_state=2)

#产生非线性数据,交叉的
#X_train,y = make_moons(n_samples = 500, noise=0.2,random_state =1)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train, y)
y=2*y-1
 
#print('X_train',':', X_train)
# print('y',':',y)
 
#Set model parameters and initial values
C = 1.0
m = len(X_train_scaled)
initial_alphas = np.zeros(m)
initial_b = 0.0
 
# Set tolerances
tol = 0.01 # error tolerance
eps = 0.01 # alpha tolerance
 
# 初始化smo结构,使用高斯核函数
model = SMOStruct(X_train_scaled, y, C, lambda x, y: gaussian_kernel(x,y,sigma=0.5),initial_alphas, initial_b, np.zeros(m), user_linear_optim=False)
 
#initialize error cache
#先把这个注释掉
initial_error = decision_function(model.alphas, model.y, model.kernel,
                                   model.X, model.X, model.b) - model.y
model.errors = initial_error 

 

print("开始拟合模型...")
#开始训练
output = fit(model)
#绘制训练完,找到分割平面的图
fig,ax = plt.subplots()
grid,ax = plot_decision_boundary(output, ax)

plt.savefig("squares3.png",
            bbox_inches ="tight",
            pad_inches = 1,
            transparent = True,
            facecolor ="w",
            edgecolor ='w',
            dpi=300,
            orientation ='landscape')

输出结果:

开始拟合模型...
loopnum012 2000 : 12 : 1988

4、参考文献

[1]J. Platt, “Sequential Minimal Optimization: A Fast Algorithm for Training Support Vector Machines,” Technical Report MSR-TR-98-14, Microsoft Research, 1998.


需要J. Platt 论文的家人们可以去百度网盘(永久有效)获取:

链接:https://pan.baidu.com/s/1qAu4ueR_ucJO_WbOKAYg2w?pwd=7woc 
提取码:7woc 
--来自百度网盘超级会员V5的分享


更多优质内容持续发布中,请移步主页查看。

   点赞+关注,下次不迷路!

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

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

相关文章

【C++】 探索程序 详细解读程序在运行过程中都发生了什么

目录 头文件-源代码 头文件重复包含 问题 解决方案 程序生成过程 预处理Preprocessi 编译Compilation 汇编Assembly 链接Linking 编译期-运行期 编译期确定 运行期确定 编译期错误 运行期错误 类和对象 宏 宏的其他用法 inline内联 头文件-源代码 头文件&…

Vue简介和常用指令

概述&#xff1a; MVVM思想&#xff1a;视图层数据和数据模型里面的数据发生变化都会影响到另一边的数据&#xff0c;通过ViewModel自动实现。 Vue入门案例 步骤&#xff1a; 上面提到了数据模型和试图层的数据是关联的&#xff0c;此处数据模型里面el的值就是选择了哪一个视…

jQuery引入----练习

jQuery引入----练习 html <!DOCTYPE html> <html><head><title>jQuery引入</title><!-- css样式引入 --><link rel"stylesheet" href"../css/a.css"><!-- jquery函数库引入 --><script type"tex…

Linux基础IO【深入理解文件系统】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、磁盘文件2、磁盘概念2.1、基本结构2.2、数据存储 3、磁盘信息3.1、分区意义…

【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载

一.拷贝构造函数 A.概念 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用。 B.特性 1. 拷贝构造函数是构造函数的一个重载形式&#xff1b; 2. 拷贝构造函…

shell的基础学习二

文章目录 一、Shell 数组二、Shell 基本运算符三、Shell echo命令四、Shell printf 命令五、Shell test 命令总结 一、Shell 数组 数组中可以存放多个值。Bash Shell 只支持一维数组&#xff08;不支持多维数组&#xff09;&#xff0c;初始化时不需要定义数组大小&#xff08…

【五一创作】【Simulink】基于FCS-MPC的三相并网逆变器控制(Stateflow)

上次写了一篇【Simulink】基于FCS-MPC的三相并网逆变器控制&#xff08;Matlab Function&#xff09;&#xff0c;控制部分用 Matlab Function 写的&#xff0c;因实验室一般用 Stateflow&#xff0c;所以这篇把 Matlab Function 改成 Stateflow. 原理 电路原理图&#xff1a;…

如何批量查询快递的签收状态?

如果一次性网购大量快递&#xff0c;我们就得经常进入快递或网购平台查询物流&#xff0c;随时查看快递单号的物流状态。如果快递公司少&#xff0c;查询起来比较容易&#xff0c;但是如果快递公司很多&#xff0c;每次都要人工查询就是一件很麻烦的事情了。今天&#xff0c;小…

数据库相关知识

一.1 数据库 与Sybase不同&#xff0c;一个用户就对应于一个数据库。 create user CBMAIN identified by "sunline" default tablespace CBMAIN_DATA  -- 表空间 temporary tablespace CBMAIN_TEMP; -- 临时表空间 一.2 表空间 表空间由一个或多个物理文件组成&…

js使用splice方法删除数组元素可能导致的问题

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组&#xff0c;并以数组形式返回被修改的内容。此方法会改变原数组。 JavaScript 遍历数组并通过 splice 方法删除该数组符合某些条件的元素将会导致哪些问题&#xff1f; 导致的问题 当使用 splice 方法从 …

QT 中的多线程之继承 Thread

文章目录 1. 概述2. UML 类的关系图3. 代码&#xff1a;4. 运行结果及说明5. 结语 1. 概述 任何继承于QThread的线程都是通过继承 QThread 的run函数来实现多线程的&#xff0c;因此&#xff0c;必须重写QThread的run函数&#xff0c;把复杂逻辑写在QThread的run函数中。然后在…

effective c++ item40-44

item40:谨慎的使用多重继承 多重继承带来的符号的歧义性 #include <iostream> #include <vector> using namespace std; class A { public:void f() { cout << "A" << endl; } }; class B { private:void f(); }; class C : public A, publ…

5.5.1哈夫曼树

知识总览&#xff1a; 概念&#xff1a; 结点的权&#xff1a;有某种现实含义的数值&#xff08;如&#xff1a;表示结点的重要性&#xff09; 结点的带权路径长度&#xff1a;从树的根到该结点的路径长度&#xff08;经过的边数&#xff09;与该结点上权值的乘积。 就比如说要…

ETL工具 - Kettle 案例,拉取网络列表数据

一、Kettle 实战案例 上篇文章对 Kettle 的查询、连接、统计、脚本算子进行了介绍&#xff0c;对 Kettle 的大部分算子都应该有了相应的了解&#xff0c;下面我们基于 Kettle 实战案例&#xff0c;拉取 CSDN 博客列表的全部数据&#xff0c;存放至 Excel 文件中。 实验之前先…

NECCS|全国大学生英语竞赛C类|词汇和语法|词汇题|21:03~21:53

词汇题 语法题 情景对话题 目录 一、词汇题 1. 基本词义辨析题 2. 同义词或近义词辨析题 3. 固定搭配 二、常见词组 一、词汇题 1. 基本词义辨析题 appropriate funds 拨款 slum- clearance programme 贫民窟清理计划 reject 拒绝接受&…

DAY 49 tomcat服务配置优化

什么是Tomcat Tomcat是Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的Web应用服务器&#xff0c;是Apache 软件基金会的 Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun和其他一些公司及人共同开发而成。 Tomcat属于轻量级应用服务器&#xff0…

外卖项目优化-02-

文章目录 瑞吉外卖项目优化-Day02课程内容前言1. MySQL主从复制1.1 介绍1.2 搭建1.2.1 准备工作1.2.2 主库配置1.2.3 从库配置 1.3 测试 2. 读写分离案例2.1 背景介绍2.2 ShardingJDBC介绍2.3 数据库环境2.4 初始工程导入2.5 读写分离配置2.6 测试 3. 项目实现读写分离3.1 数据…

深入解析PyTorch中的基本数据结构:张量的维度、形状和数据类型

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【LEAP模型】能源环境发展、碳排放建模预测及不确定性分析

本次内容突出与实例结合&#xff0c;紧密结合国家能源统计制度及《省级温室气体排放编制指南》&#xff0c;深入浅出地介绍针对不同级别研究对象时如何根据数据结构、可获取性、研究目的&#xff0c;构建合适的能源生产、转换、消费、温室气体排放&#xff08;以碳排放为主&…

【Spring框架全系列】Spring更简单的读取和存储对象

&#x1f4ec;&#x1f4ec;哈喽&#xff0c;大家好&#xff0c;我是小浪。上篇博客我们介绍了如何创建一个spring项目&#xff0c;并且如何的存、取对象&#xff0c;介绍了相关方法&#xff0c;那么本篇博客将接着上篇博客的内容介绍如何更加简单的读取和存储对象。 &#x1f…