EM算法(期望最大算法、Expectation Maximization Algorithm)

在这里插入图片描述

EM算法(期望最大算法、Expectation Maximization Algorithm)

引言

EM算法,全称为期望最大(Expectation Maximization)算法,是一种从不完全数据或有数据丢失的数据集(存在隐含变量)中求解概率模型参数的最大似然估计方法。
我们采用Nature Biotech中EM tutorial中掷硬币的例子来对EM算法进行一个具体化的解释。

我们假设有两枚硬币A与B,他们随机抛掷的结果如图,当我们知道了每次抛的是A还是B就可以直接进行估计。
在这里插入图片描述

那么根据图中的计算,我们可以得到,两枚硬币抛出正面的概率分别为 θ ^ A = 0.80 \hat \theta_A = 0.80 θ^A=0.80, θ ^ B = 0.45 \hat \theta_B = 0.45 θ^B=0.45
但如果此时不知道抛掷的硬币是A还是B,也就是隐藏了图中表格里的Coin ACoin B,将所有结果存到一列表格中。此时相当于添加了隐变量。只能观测到5轮循环,每轮循环10次,共计50次投币。这个时候就无法直接估计A和B的正面概率,因为不知道哪一轮循环是哪个硬币投掷的。最后,图中的表格就变为下面的形式:

CoinStatistics
Unknown5H,5T
Unknown9H,1T
Unknown8H,2T
Unknown4H,6T
Unknown7H,3T

此时我们的目标没有变,仍旧是估计A和B正面的概率。虽然此时我们失去了A和B的标号,但是我们多了一个硬币种类的隐变量,设为Z,Z是一个5维的向量,可以表示为:
Z = ( z 1 , z 2 , z 3 , z 4 , z 5 ) Z=(z_1,z_2,z_3,z_4,z_5) Z=(z1,z2,z3,z4,z5),代表每一轮所使用的硬币。但是,对于Z并不知晓,就无法去估计 θ A \theta_A θA θ B \theta_B θB,那么我们就必须先得出Z,然后才能进一步估计P(A)和P(B),要得出Z又必须先知道 θ A \theta_A θA θ B \theta_B θB,然后采用最大似然去预测,那么就会陷入一个死循环。

为了解决上述问题,我们可以先随机初始化 θ A \theta_A θA θ B \theta_B θB,然后去估计Z,基于估计出来的Z按照最大似然去估计新的 θ A \theta_A θA θ B \theta_B θB,直至最后收敛,这就是EM算法的思想,下图给出了E-step和M-step。
在这里插入图片描述

下面计算引用【机器学习】EM——期望最大(非常详细)

随机初始化 θ A = 0.6 \theta_A = 0.6 θA=0.6 θ B = 0.5 \theta_B = 0.5 θB=0.5,那么第一轮循环中,如果Unknown的硬币是A,得出5H5T的概率就是 0. 6 5 ∗ 0. 4 5 0.6^5*0.4^5 0.650.45;如果是B,概率为 0. 5 5 ∗ 0. 5 5 0.5^5*0.5^5 0.550.55。那么就有,Unknown为硬币A和B的概率分别是
P A = 0. 6 5 ∗ 0. 4 5 0. 6 5 ∗ 0. 4 5 + 0. 5 5 ∗ 0. 5 5 = 0.45 P B = 0. 5 5 ∗ 0. 5 5 0. 6 5 ∗ 0. 4 5 + 0. 5 5 ∗ 0. 5 5 = 0.55 P_A = \frac{0.6^5*0.4^5}{0.6^5*0.4^5+0.5^5*0.5^5} = 0.45\\ P_B = \frac{0.5^5*0.5^5}{0.6^5*0.4^5+0.5^5*0.5^5 } = 0.55 PA=0.650.45+0.550.550.650.45=0.45PB=0.650.45+0.550.550.550.55=0.55

5个轮次我们都依照上面进行计算,可以得到如下情况

Coin ACoin B
0.450.55
0.800.20
0.730.27
0.350.65
0.650.35

这一步对应了E-step

结合硬币A的概率和上面的投掷结果情况,我们可以利用期望求出硬币A和硬币B的贡献。

CoinStatistics
Unknown5H,5T
Unknown9H,1T
Unknown8H,2T
Unknown4H,6T
Unknown7H,3T
Coin ACoin B
0.450.55
0.800.20
0.730.27
0.350.65
0.650.35

以第一轮硬币A为例,计算方式为:
H : 0.45 ∗ 5 = 2.25 T : 0.45 ∗ 5 = 2.25 H:0.45*5 = 2.25 T:0.45*5 = 2.25 H:0.455=2.25T:0.455=2.25
上面的计算代表着,硬币A对于投掷结果是5H5T的贡献情况。于是可以得到下面的贡献分布情况。

Coin ACoin B
2.2H,2.2T2.8H,2.8T
7.2H,0.8T1.8H,0.2T
5.9H,1.5T2.1H,0.5T
1.4H,2.1T2.6H,3.9T
4.5H,1.9T2.5H,1.1T

总计有

21.3H,8.6T11.7H,8.4T

然后使用极大似然来估计 θ A \theta_A θA θ B \theta_B θB
θ A = 21.3 21.3 + 8.6 = 0.71 θ B = 11.7 11.7 + 8.4 = 0.58 \theta_A = \frac{21.3}{21.3+8.6} = 0.71 \\ \theta_B = \frac{11.7}{11.7+8.4} = 0.58 θA=21.3+8.621.3=0.71θB=11.7+8.411.7=0.58
这一步就是M-step,如此反复迭代,可以得到最终的 θ A \theta_A θA θ B \theta_B θB

原理

有一个样本集 { x 1 . . . , x m } \{x_1...,x_m\} {x1...,xm},我们假设样本间互相独立,想要拟合模型 p ( x ; θ ) p(x;\theta) p(x;θ)到数据的参数。想要找到每个样本隐含的类别z,使得p(x,z)最大,那么可以得到下面的极大似然估计:
L ( θ ) = ∑ i = 1 m log ⁡ p ( x i ; θ ) = ∑ i = 1 m l o g ∑ z p ( x i , z ; θ ) . L(\theta) = \sum_{i=1}^m \log p(x_i;\theta)\\ =\sum_{i=1}^m log \sum_z p(x_i,z;\theta). L(θ)=i=1mlogp(xi;θ)=i=1mlogzp(xi,z;θ).

第一步是对极大似然取对数,第二步是对每个样例的每个可能类别z求联合分布概率和。但是直接求一般比较困难,因为有隐藏变量z存在,但是一般确定了z后,求解就容易了。所以我们需要用EM算法来求z。对于参数估计,我们本质上还是想获得一个使似然函数最大化的那个参数θ,现在与极大似然不同的只是似然函数式中多了一个未知的变量z。

事实上,隐变量估计问题也可以通过梯度下降等优化算法,但事实由于求和项将随着隐变量的数目以指数级上升,会给梯度计算带来麻烦;而 EM 算法则可看作一种非梯度优化方法。

对于每个样本,我们使用 Q i ( z ) Q_i(z) Qi(z)表示样本i隐含变量z的某种分布,且 Q i ( z ) Q_i(z) Qi(z)满足: ∑ z Z Q i ( z ) = 1 , Q i ( z ) ≥ 0 \sum_z^Z Q_i(z) = 1,Q_i(z) \geq 0 zZQi(z)=1,Qi(z)0,那么我们的目标最后就变成了找到合适的 θ \theta θ和z使得 L ( θ ) L(\theta) L(θ)最大。

我们将式子做如下变换:
∑ i n log ⁡ p ( x i ; θ ) = ∑ i n log ⁡ ∑ z p ( x i , z ; θ ) = ∑ i n log ⁡ ∑ z Z Q i ( z ) p ( x i , z ; θ ) Q i ( z ) ≥ ∑ i n ∑ z Z Q i ( z ) log ⁡ p ( x i , z ; θ Q i ( z ) \sum_i^n \log p(x_i;\theta) = \sum_i^n \log \sum_z p(x_i,z;\theta)\\ = \sum_i^n \log \sum_z^Z Q_i(z)\frac{p(x_i,z;\theta)}{Q_i(z)}\\ \geq \sum_i^n \sum_z^Z Q_i(z) \log \frac{p(x_i,z;\theta}{Q_i(z)} inlogp(xi;θ)=inlogzp(xi,z;θ)=inlogzZQi(z)Qi(z)p(xi,z;θ)inzZQi(z)logQi(z)p(xi,z;θ

第一步是求和每个样本的所有可能的类别 z 的联合概率密度函数,但是这一步直接求导非常困难,所以将其分母都乘以函数 Q i ( z ) Q_i(z) Qi(z) ,转换到第二步。从第二步到第三步是利用 Jensen 不等式。

Jensen不等式:

  • 如果f是凸函数,X是随机变量,则 E [ f ( X ) ] ≥ f ( E [ X ] ) E[f(X)]\geq f(E[X]) E[f(X)]f(E[X]) ,当f是严格凸函数时,则 E [ f ( X ) ] > f ( E [ X ] ) E[f(X)] \gt f(E[X]) E[f(X)]>f(E[X])
  • 如果f是凹函数,X是随机变量,则 E [ f ( X ) ] ≤ f ( E [ X ] ) E[f(X)] \leq f(E[X]) E[f(X)]f(E[X]) ,当f是严格凹函数时,则 E [ f ( X ) ] < f ( E [ X ] ) E[f(X)] \lt f(E[X]) E[f(X)]<f(E[X])
  • X = E [ X ] X= E[X] X=E[X]时,即为常数时等式成立。
    在这里插入图片描述

我们把第一步中的 log ⁡ \log log函数看成一个整体,由于 log ⁡ ( x ) \log(x) log(x)的二阶导数小于0,所以原函数为凹函数。我们把 Q i ( z ) Q_i(z) Qi(z)看成一个概率 p z p_z pz,把 p ( x i , z ; θ ) Q i ( z ) \frac{p(x_i,z;\theta)}{Q_i(z)} Qi(z)p(xi,z;θ)看成 z的函数 g ( z ) g(z) g(z)。根据期望公式有:
E ( z ) = p z g ( z ) = ∑ z Z Q i ( z ) [ p ( x i , z ; θ ) Q i ( z ) ] E(z) = p_zg(z)= \sum_z^ZQ_i(z)[\frac{p(x_i,z;\theta)}{Q_i(z)}] E(z)=pzg(z)=zZQi(z)[Qi(z)p(xi,z;θ)]

根据Jensen不等式:
f ( ∑ z Z Q i ( z ) [ p ( x i , z ; θ ) Q i ( z ) ] = f ( E [ z ] ) ≥ E [ f ( z ) ] = ∑ z Z Q i ( z ) f ( [ p ( x i , z ; θ ) Q i ( z ) ] ) f(\sum_z^ZQ_i(z)[\frac{p(x_i,z;\theta)}{Q_i(z)}] = f(E[z])\geq E[f(z)]\\ =\sum_z^ZQ_i(z)f([\frac{p(x_i,z;\theta)}{Q_i(z)}]) f(zZQi(z)[Qi(z)p(xi,z;θ)]=f(E[z])E[f(z)]=zZQi(z)f([Qi(z)p(xi,z;θ)])

通过上面我们得到了: L ( θ ) ≥ J ( z , Q ) L(\theta) \geq J(z,Q) L(θ)J(z,Q) 的形式(z 为隐变量),那么我们就可以通过不断最大化 J ( z , Q ) J(z,Q) J(z,Q)的下界来使得 L ( θ ) L(\theta) L(θ)不断提高。

在这里插入图片描述

图片来自 【机器学习】EM——期望最大(非常详细)

或许我们可以直接分别对 θ \theta θ和z求偏导数,然后求得极值点,也就是最大化 L ( θ ) L(\theta) L(θ),但是式子中含有 log ⁡ ∑ z p \log\sum_z p logzp的形式,求导后就会变得非常复杂,因此很难求得我们需要的z和 θ \theta θ

也就是说,EM 算法通过引入隐含变量,使用 MLE(极大似然估计)进行迭代求解参数。通常引入隐含变量后会有两个参数,EM 算法首先会固定其中的第一个参数,然后使用 MLE 计算第二个变量值;接着通过固定第二个变量,再使用 MLE 估测第一个变量值,依次迭代,直至收敛到局部最优解。

最后可以总结一下EM算法的步骤:
第一步,初始化分布参数 θ \theta θ
第二步,重复E-step 和 M-step直到收敛:

  • E-step:根据参数的初始值或上一次迭代的模型参数来计算出的隐性变量的后验概率(条件概率),其实就是隐性变量的期望值。作为隐藏变量的现有估计值:
    Q i ( z j ) = p ( z j ∣ x i ; θ ) Q_i(z_j) = p(z_j|x_i;\theta) Qi(zj)=p(zjxi;θ)
  • M-step:最大化似然函数从而获得新的参数值:
    θ = a g r m a x θ ∑ i ∑ j Q i ( z j ) log ⁡ P ( x i , z j ; θ ) Q i ( z j ) \theta = {agrmax}_\theta \sum_i \sum_j Q_i(z_j)\log \frac{P(x_i,z_j;\theta)}{Q_i(z_j)} θ=agrmaxθijQi(zj)logQi(zj)P(xi,zj;θ)

代码

import numpy as np
from scipy.stats import multivariate_normal  #多元正态分布
from numpy import genfromtxt    #数据处理函数

def Estep(X, prior, mu, sigma):
    N, D = X.shape         #N表示数据的条数,D表示数据的维数
    K = len(prior)          #计算随机变量prior的长度
    gama_mat = np.zeros((N,K))       #初始化gama_mat为N行K列个0
    for i in range(0,N):        #遍历N条数据
        xi = X[i, :]        #对于每一行数据
        sum = 0
        for k in range(0, K):     #对K个prior求概率密度函数
            p = multivariate_normal.pdf(xi, mu[k,:], sigma[k,:,:])         #计算第k个prior的概率密度p
            sum += prior[k] * p      #求K个prior的总和
        for k in range(0,K):
            gama_mat[i, k] = prior[k] * multivariate_normal.pdf(xi, mu[k,:], sigma[k,:,:]) / sum   #求gama_mat概率矩阵
    return gama_mat   
       
def Mstep(X, gama_mat):        #将Estep得到的gama_mat,作为Mstep的输入参数
    (N, D) = X.shape
    K = np.size(gama_mat, 1)     #返回gama_mat的列数
    mu = np.zeros((K, D))        #给mu初始化为K行D列个0 
    sigma = np.zeros((K, D, D))   #给sigma初始化为K个D行D列的矩阵(方阵)
    prior = np.zeros(K)         #初始化prior为K个0
    for k in range(0, K):
        N_k = np.sum(gama_mat, 0)[k]    
        for i in range(0,N):
            mu[k] += gama_mat[i, k] * X[i]         
        mu[k] /= N_k             #得到均值矩阵
        for i in range(0, N):
            left = np.reshape((X[i] - mu[k]), (2,1))
            right = np.reshape((X[i] - mu[k]), (1,2))
            sigma[k] += gama_mat[i,k] * left * right     #得到sigma矩阵
        sigma[k] /= N_k
        prior[k] = N_k/N
    return mu, sigma, prior
    
def logLike(X, prior, Mu, Sigma):          #对数似然函数
    K = len(prior)                         
    N, M = np.shape(X)
    
    P = np.zeros([N, K])      # 初始化概率矩阵P
    for k in range(K):
        for i in range(N):
            P[i, k] = multivariate_normal.pdf(X[i], Mu[k, :], Sigma[k, :, :])  #P是一个NxK矩阵,其中(i,k)个元素表示第i个数据点在第j个簇中的可能性
    return np.sum(np.log(P.dot(prior)))     #返回似然函数值
    
def main():
    # Reading the data file
    X = genfromtxt('.\data\TrainingData_GMM.csv', delimiter=',')   #读取数据
    print('training data shape:', X.shape)    #打印数据的shape(5000,2)

    N, D = X.shape     #把5000、2分别赋予N,D表示有5000条数据,每条数据有两个特征
    K = 4       

    # initialization
    mu = np.zeros((K, D))      #给mu初始化为K行D列个0
    sigma = np.zeros((K, D, D))     #给sigma初始化为K个D行D列的矩阵(方阵)
     #mu[0] = [-0.5, -0.5]
     #mu[1] = [0.3, 0.3]
     #mu[2] = [-0.3, 0.3]
     #mu[3] = [1.3, -1.3]

    mu[0] = [1, 0]
    mu[1] = [0, 1]
    mu[2] = [0, 0]
    mu[3] = [1, 1]

    for k in range(0, K):            #K个二维单位矩阵作为sigma
        sigma[k] = [[1, 0], [0, 1]]

    prior = np.ones(K) / K        #先验概率为K个1/k
    iter = 0
    prevll = -999999
    ll_evol = []      #定义一个空数组ll_evol用于后面装log likelihood值

    print('initialization of the params:')
    print('mu:\n', mu)
    print('sigma:\n', sigma)
    print('prior:', prior)

    # Iterate with E-Step and M-step
    while (True):
        W = Estep(X, prior, mu, sigma)   #调用Estep
        mu, sigma, prior = Mstep(X, W)    #通过Mstep更新初始的参数mu、sigma、prior
        ll_train = logLike(X, prior, mu, sigma)   #调用对数似然函数
        print('iter:',iter, 'log likelihood:',ll_train)   #返回第几次迭代和对应的似然值
        ll_evol.append(ll_train)

        iter = iter + 1
        if (iter > 150 or abs(ll_train - prevll) < 0.01):   #当迭代次数大于150次或ll_train的值接近-999999时结束操作
            break

        abs(ll_train - prevll)   
        prevll = ll_train     #更新prevll的值
  
    import pickle    #pickle模块能将对象序列化
    with open('results.pkl', 'wb') as f:     
        pickle.dump([prior, mu, sigma, ll_evol], f)    #把prior, mu, sigma, ll_evol数据以二进制形式写入results.pkl文件中   
        
if __name__ == '__main__':
    main()
    
training data shape: (5000, 2)
initialization of the params:
mu:
 [[1. 0.]
 [0. 1.]
 [0. 0.]
 [1. 1.]]
sigma:
 [[[1. 0.]
  [0. 1.]]

 [[1. 0.]
  [0. 1.]]

 [[1. 0.]
  [0. 1.]]

 [[1. 0.]
  [0. 1.]]]
prior: [0.25 0.25 0.25 0.25]
iter: 0 log likelihood: -7758.98161924987
iter: 1 log likelihood: -6842.325796847348
iter: 2 log likelihood: -5877.092929285351
iter: 3 log likelihood: -5368.007026989181
iter: 4 log likelihood: -5158.951024247597
iter: 5 log likelihood: -4711.421034949499
iter: 6 log likelihood: -3814.307460091173
iter: 7 log likelihood: -2974.4639436766956
iter: 8 log likelihood: -2696.7255823784203
iter: 9 log likelihood: -2428.8597242586584
iter: 10 log likelihood: -2182.0334455177353
iter: 11 log likelihood: -2023.8042796345283
iter: 12 log likelihood: -1970.824061153165
iter: 13 log likelihood: -1956.739299533951
iter: 14 log likelihood: -1951.841638776625
iter: 15 log likelihood: -1949.6197599504249
iter: 16 log likelihood: -1948.411570496814
iter: 17 log likelihood: -1947.6739124172018
iter: 18 log likelihood: -1947.1944657348135
iter: 19 log likelihood: -1946.87392793565
iter: 20 log likelihood: -1946.6573830294146
iter: 21 log likelihood: -1946.5107251106433
iter: 22 log likelihood: -1946.4114561101228
iter: 23 log likelihood: -1946.3443661539402
iter: 24 log likelihood: -1946.299098150319
iter: 25 log likelihood: -1946.2685983080376
iter: 26 log likelihood: -1946.248073038022
iter: 27 log likelihood: -1946.2342732733175
iter: 28 log likelihood: -1946.225002083594
import numpy as np
from scipy.stats import multivariate_normal    #导入多元正太分布函数
from numpy import genfromtxt  
import matplotlib.pyplot as pyplot
import pickle 
with open('results.pkl', 'rb') as f:
    [prior, mu, sigma, ll_evol] = pickle.load(f)   #反序列化对象,将文件中的数据解析为python对象

pyplot.plot(ll_evol, 'o')  #画出29个训练数据的ll_evol值
pyplot.show() 

print('prior:',prior)       #进过训练后的prior
print('mu:', mu)            #进过训练后的mu
print('sigma:', sigma)      #进过训练后的sigma

X = genfromtxt('.\data\TrainingData_GMM.csv', delimiter=',')
print('data shape:', X.shape)

sel_num = 500
X_sel = []
sel_idxs = []
while len(sel_idxs) < sel_num:
    idx = np.random.randint(0, 5000, 1)    #如果len(sel_idxs)小于500,则从0到4999中返回一个随机整数给idx
    while idx in sel_idxs:                     #如果返回的idx在sel_idxs中已有,则继续从0到4999中返回一个随机整数给idx
        idx = np.random.randint(0, 5000, 1)
    sel_idxs.append(idx[0])            #把idx放入数组sel_idxs中
X_sel = X[sel_idxs]  

def get_label(x, prior, mu, sigma):
    K = len(prior)
    p = np.zeros(K)
    for k in range(0,K):
        p[k] = prior[k] * multivariate_normal.pdf(x, mu[k,:], sigma[k,:,:])     #求k的概率p
    label = np.argmax(p)      #输出最大p对应的索引值(即label)
    return label

lbs = []
for i in range(0, sel_num):
    lb = get_label(X_sel[i], prior, mu, sigma)      #调用get_label函数传参后,得到相应的分类标签
    lbs.append(lb)

# plot
pyplot.scatter(X_sel[:,0], X_sel[:,1], marker='o', c=lbs)      #做出lbs的散点图
pyplot.show()

在这里插入图片描述

prior: [0.23       0.27274177 0.26683872 0.23041951]
mu: [[ 1.20354296 -1.19685788]
 [ 0.14438214  0.14615911]
 [-0.44133345 -0.45061832]
 [-0.40658589  0.32258308]]
sigma: [[[ 0.02258855 -0.00761021]
  [-0.00761021  0.02361336]]

 [[ 0.00885564  0.00186778]
  [ 0.00186778  0.00880396]]

 [[ 0.07027983  0.0373684 ]
  [ 0.0373684   0.06508573]]

 [[ 0.03447208 -0.01299104]
  [-0.01299104  0.03454537]]]
data shape: (5000, 2)

在这里插入图片描述

参考

【机器学习】EM——期望最大(非常详细)

EM算法详解+通俗例子理解

(EM算法)The EM Algorithm

What is the expectation maximization
algorithm?

Python——EM(期望极大算法)实战(附详细代码与注解)(一)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Oracle单实例静默安装

oracle 11g单实例静默安装 在CentOS上静默安装Oracle数据库 引言 在企业环境中&#xff0c;自动化和标准化是提高效率的关键。静默安装&#xff08;也称为无人值守安装&#xff09;是一种无需人工干预的安装方法&#xff0c;适用于大规模部署或需要重复安装的场景。本文将介…

【redis】初识非关系型数据库——redis

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 初识 Redis Redis是⼀种基于键值对&#xff08;key-value&#xff09;的NoSQL数据库&#xff0c;与很多键值对数据库不同的是&#xff0c;Redis 中的值可以是由string&#xff08;字符串&#xff09;、hash&#xff0…

【Python爬虫实战】多进程结合 BeautifulSoup 与 Scrapy 构建爬虫项目

#1024程序员节&#xff5c;征文# &#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 前言 在大数据时代&#xff0c;爬虫技术是获取和处理网络数据的利器。面对需要处理大…

ChatGPT实现旅游推荐微信小程序

随着旅游行业的快速发展&#xff0c;个性化推荐已成为提升用户体验的重要手段。通过AI技术&#xff0c;提供一个智能旅游推荐小程序&#xff0c;使用户能够轻松获取定制化的旅行建议。 项目概述 项目目标 开发一个AI旅游推荐小程序&#xff0c;基于用户输入的旅行偏好&#…

Visual Studio安装图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 教程说明 本教程旨在详细介绍 Visual Studio 社区版的安装过程及其注意事项。 Visual Studio简介 Visual Studio 社区版功能完备且可扩展的免费 IDE&#xff0c;可用于创…

【WPF】中Dispatcher的DispatcherPriority参数使用

在 WPF 中&#xff0c;DispatcherPriority 参数用于指定通过 Dispatcher 调度的操作的执行优先级。加入 DispatcherPriority 参数的情况通常取决于你希望操作何时以及如何被执行。 1.Dispatcher的DispatcherPriority参数使用 以下是几种情况和示例说明&#xff1a; 1.1 需要…

【STM32 Blue Pill编程实例】-控制步进电机(ULN2003+28BYJ-48)

控制步进电机(ULN2003+28BYJ-48) 文章目录 控制步进电机(ULN2003+28BYJ-48)1、步进电机介绍2、ULN2003步进电机驱动模块3、硬件准备及接线4、模块配置3.1 定时器配置3.2 ULN2003输入引脚配置4、代码实现在本文中,我们将介使用 STM32Cube IDE 使用 ULN2003 电机驱动器来控制28B…

自由学习记录(14)

unity操作问题 位置&#xff1a;子物体的位置是相对于父物体的。如果你移动父物体&#xff0c;子物体会保持相对于父物体的相对位置&#xff0c;跟着一起移动。 旋转&#xff1a;子物体的旋转也是相对于父物体的。旋转父物体会导致子物体围绕父物体的原点旋转。 缩放&#xf…

【HarmonyOS NEXT】鸿蒙开发环境准备

0. 引言 看了发布会以后&#xff0c;热血澎湃啊&#xff0c;是时候学学把自己做的一些小工具搞成鸿蒙版了&#xff01;&#xff01;&#xff01; 1. 开发工具下载 下载地址&#xff1a;https://pan.quark.cn/s/08ddebdb7a20 工具版本会不定时更新&#xff0c;下载最新版即可…

【网络原理】——HTTP协议、fiddler抓包

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;认识HTTP 1&#xff1a;超文本传输 2&#xff1a;发展历史 3&#xff1a;HTML 4&am…

Axure树形菜单展开与折叠

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;Axure树形菜单展开与折叠 主要内容&#xff1a;树形菜单制作——层级关系——隐藏与显示——值的变化——多层交互 应用场景&#xff1a;关系树、菜…

R语言机器学习算法实战系列(十)自适应提升分类算法 (Adaptive Boosting)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理步骤教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模型总…

断点续传技术是什么?大型文件传输的新模式!

随着科技的不断进步&#xff0c;文件传输已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;传输大型文件时常常会遇到网络不稳定、传输中断等问题&#xff0c;导致传输失败或者重新传输。为解决这一问题&#xff0c;断点续传技术应运而生。 一、断点续传技术是什么…

3GPP协议解读_NTN系列(一)_38.811_非地面网络(NTN)的背景、应用场景和信道建模

非地面网络 1. Scope4. 非地面网络背景介绍4.1 5G中的非地面网络4.2 非地面网络在5G中的用例4.3 卫星和空中接入网的架构4.4 卫星和空中接入网终端的特点4.5 空气/星载飞行器特性4.6 NTN的覆盖模式4.7 NTN网络架构选项4.8 频谱 5. 非地面网络应用场景5.1 应用场景概览5.2 属性介…

STM32通信协议-I2C

目录 一&#xff0c;IC2的协议规则 I2C总线是PHILIPS公司开发的两线式串行总线&#xff0c;I2C总线主要解决了单片机一对多通信的问题 两根通信线&#xff1a;SCL,SDA&#xff0c;同步&#xff0c;半双工通信&#xff0c;支持数据应答机制&#xff0c;支持总线挂载多设备。 …

2024ideaUI切换和svn与git的切换,svn的安装和配置,idea集成svn ,2024-10-18日

2024-10-18日 2024的UI实在很不舒服&#xff0c;隐藏了很多按键&#xff1b; 第一步&#xff1a; 视图 -》 外观 -》 工具栏选出来&#xff1b; 结果出来&#xff1a; 运行的按键和设置的按钮 第二步 点击设置的按钮&#xff0c;选择最后一个&#xff0c;重启就行 结果 舒服&…

网站漏扫:守护网络安全的关键防线

网站漏洞扫描&#xff0c;简称漏扫&#xff0c;是一种针对网站进行漏洞检测的安全服务。网站漏洞扫描在网络安全中占据着至关重要的地位。 网站漏扫在及时发现和修复漏洞方面发挥着关键作用 通过对网站和系统的全面扫描&#xff0c;能够快速识别出各种潜在的漏洞&#xff0c;…

网络安全领域推荐证书介绍及备考指南

在网络安全领域&#xff0c;拥有专业认证不仅可以证明个人的专业能力&#xff0c;还能帮助在实际工作中应用先进的技术和知识。以下是几种热门的网络安全证书介绍及备考指南。 1. OSCP (Offensive Security Certified Professional) 证书简介 OSCP是针对渗透测试领域的入门级…

<项目代码>YOLOv8路面垃圾识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

实现简道云与企业微信的自动化数据集成

简道云入职新增企微成员西乡公司 在企业信息化管理中&#xff0c;数据的高效集成和实时同步是提升业务效率的重要环节。本文将分享一个具体的系统对接集成案例&#xff1a;如何通过轻易云数据集成平台&#xff0c;将简道云的数据无缝集成到企业微信&#xff0c;实现西乡公司新…