进化算法是一类算法簇,这类算法模拟的是自然界当中生物种群的进化机制。进化算法在解决最优化问题或者机器学习问题的时候,通常会维护一个解的集合 X = { x 1 , x 2 , … , x N } X=\{x_1,x_2,\dots,x_N\} X={ x1,x2,…,xN},称之为种群, N N N称为种群规模。算法运行的机制,是在每一轮迭代当中,对种群进行变异、交叉等操作,形成新的个体添加到种群当中,然后对种群进行筛选,使得种群的规模始终维持在 N N N. 筛选的规则是根据种群个体的适应度 f ( x i ) f(x_i) f(xi)设计的,理想的筛选规则应当保留适应度高的个体,淘汰适应度低的个体。
我们这里介绍的进化算法,主要是三种:遗传算法、粒子群算法和标准差分算法。
首先我们先定义基本的问题背景:在一个环境 env \text{env} env(可能是一个最优化问题、一个强化学习场景、一个实际的工程模拟)当中,每一个解都表示为向量 x i ∈ R d x_i\in\R^d xi∈Rd. 存在一个适应度函数 f ( x i ) f(x_i) f(xi)能够评价每一个解的适应性,函数评分越高,说明解越适应于该环境。
我们接下来分别介绍三种算法解决该问题的流程。
遗传算法模拟的是自然界中生物种群的繁衍以及自然选择机制。一个遗传算法的流程可以表示为:
需要注意的是,遗传算法同样是一个算法簇,而不是某一具体算法。对于具体的实现,筛选、交叉、变异算子在算法流程中的顺序,以及它们对当前种群的更新机制会有一定的差异。
在这个流程当中,最为关键的是三个遗传算子: select ( ⋅ ) , crossover ( ⋅ ) , mutation ( ⋅ ) \text{select}(\cdot),\text{crossover}(\cdot),\text{mutation}(\cdot) select(⋅),crossover(⋅),mutation(⋅),还有一个非关键的更新算子 Reproduction \text{Reproduction} Reproduction.
假设每一个个体的适应度 f ( x i ) f(x_i) f(xi)都是非负的,那么进行变换
p i = f ( x i ) ∑ j = 1 N f ( x j ) p_i=\frac{f(x_i)}{\sum_{j=1}^Nf(x_j)} pi=∑j=1Nf(xj)f(xi)
在选择过程中,每个个体被选中加入交叉种群 X c X_c Xc的概率是 p i p_i pi. 实现这种选择的方法,可以采用轮盘抽奖的算法。假设我们在面积为 1 1 1的抽奖圆盘上,为每一个个体分配面积为 p i p_i pi的扇面,然后转动圆盘,当圆盘停止时,指针指向第 i i i个个体的扇面的概率恰好是 p i p_i pi. 如图:
从计算机程序实现角度来说,我们可以规定一个起始坐标 q 0 = 0 q_0=0 q0=0,然后用累加概率的方式找出剩下的各个分界点坐标
q i = ∑ j = 1 i p i q_i=\sum_{j=1}^ip_i qi=j=1∑ipi
随机取一个 [ q 0 , q N ] [q_0,q_N] [q0,qN]之间的点 λ \lambda λ,如果 λ ∈ [ q i − 1 , q i ] \lambda\in[q_{i-1},q_i] λ∈[qi−1,qi],那就意味着指针落在了 x i x_i xi对应的圆盘扇面内, x i x_i xi被选中加入 X c X_c Xc。把这个过程重复 N N N次,就会选择出期望为 N p c Np_c Npc个的种群个体。
这种采样过程产生的交叉种群数 N c N_c Nc是不固定的,而且比原始种群数 N N N要少,需要一定的机制,例如将交叉运算后的个体添加回原种群当中,才能保证种群的数目不会随着迭代次数增加而减少。
最优选择算子:这种算子通常指定一个数量 c < N c<N c<N,在每一轮迭代当中,它用当前种群里适应度最高的 c c c个个体,替换掉适应度最低的 c c c个个体,然后直接用得到的新种群作为 X c X_c Xc。更新后的种群继续进行交叉、变异算子的操作。
最优保存算子:这种算子不对种群进行筛选, X c = X X_c=X Xc=X. 只是记录下当前适应度最高的个体。最后在进行交叉、变异结束之后的种群 X ′ X' X′中,将最优个体插入其中。使得最优个体保持到下一轮迭代。
生存数目算子:计算每一个个体适应度与平均适应度的比值,并且下取整:
N i = ⌊ N f ( x i ) ∑ j = 1 N f ( x j ) ⌋ N_i=\lfloor\frac{Nf(x_i)}{\sum_{j=1}^Nf(x_j)}\rfloor Ni=⌊∑j=1Nf(xj)Nf(xi)⌋
将原种群当中的每一个个体 x i x_i xi,复制 N i N_i Ni次,加入到交叉种群 X c X_c Xc当中。按照适应度对于 X c X_c Xc排序,截取其前 N N N个个体。
一般来说,交叉算子总是规定了交叉概率 P c P_c Pc,并且希望交叉运算产生的子代数目期望为 N c P c N_cP_c NcPc. 交叉算子有一个重要的问题是,交叉的两个父本如何选择。这个问题没有固定解法。有的算法当中,会将交叉种群 X c X_c Xc打乱顺序,之后按顺序两两匹配,对于每一个匹配都以 P c P_c Pc的概率进行交叉或不交叉;有的算法会随机抽取 n n n轮,每轮抽取一对父本以 P c P_c Pc的概率进行交叉或不交叉;有的算法会随机产生一个 ( 0 , 1 ) (0,1) (0,1)之间的随机数 λ \lambda λ,如果 λ < P c \lambda<P_c λ<Pc,就对整个 N c N_c Nc进行打乱、按顺序两两匹配、交叉运算,否则就完全不进行交叉运算。
交叉算子最常用的是单点交叉算子,即随机地在个体向量上取一个点位 min \text{min} min. 对于配对的两个向量 x i , x j x_i,x_j xi,xj,将它们从点位 min \text{min} min开始直到结束的片段交换:
x ‾ i , n = x j , n , n ≥ min x ‾ j , n = x i , n , n ≥ min \overline x_{i,n}=x_{j,n},\ n\geq\text{min}\\ \overline x_{j,n}=x_{i,n},\ n\geq\text{min} xi,n=xj,n, n≥minxj,n=xi,n, n≥min
其次还有双点位交叉,即选择两个点位 min , max \text{min},\text{max} min,max,交换父本在这两个点位之间的片段。
有的时候,还会使用凸组合交叉算子,即随机采样一个 a ∈ ( 0 , 1 ) a\in(0,1) a∈(0,1),令
x ‾ i = a x i + ( 1 − a ) x j x ‾ j = ( 1 − a ) x i + a x j \overline x_i=ax_i+(1-a)x_j\\ \overline x_j=(1-a)x_i+ax_j xi=axi+(1−a)xjxj=(1−a)xi+axj
这种算子适用于解空间是高维凸域的情形。
最后一个问题是,交叉算子产生的子代和父代如何进行取舍。有的算法是将子代添加到种群 X c X_c Xc中组合形成 X ′ X' X′,然后通过更新算子 Reproduction ( X ′ ) \text{Reproduction}(X') Reproduction(X′)进行取舍(例如选择出适应度前 N N N个个体)。有的算法会比较子代与父代的适应度,然后选择保留适应度强的子代。
变异算子同样指定一个变异概率 P m P_m Pm,并且试图使变异的个体数期望为 N m P m N_mP_m NmPm. 而实现的方法,可以是对于 X m X_m Xm的每一个个体都进行二分决策,以 P m P_m Pm的概率进行突变,也可以是对整个 X m X_m Xm进行二分决策,突变或者不突变。
对于每一个突变的个体,如果是二进制串(二进制的向量),可以直接进行位反转。
对于一般的向量,还可以随机选取一个片段进行倒置(顺序颠倒),或者选择两个点位互换数值。
和交叉算子类似,变异算子也可以采用线性组合的方式进行变异:随机选取一个 v ∈ R d v\in\R^d v∈Rd和一个 λ ∈ ( 0 , 1 ) \lambda\in(0,1) λ∈(0,1),令
x ^ i = x i + λ v \hat x_i=x_i+\lambda v x^i=xi+λv
更新算子的实现很简单,如果选择、交叉、变异算子最终产生的种群 X ′ X' X′规模是 N N N,可以直接将其更新到 X X X上. 如果数目超过 N N N,那么可以选择保留适应度最高的 N N N个个体。(也就是需要再次遍历并且进行适应度评价)
粒子群算法和遗传算法的区别在于,粒子群算法没有交叉、变异的相关概念,而是会在每一轮迭代当中,更新每一个个体的值。在粒子群算法当中,种群当中的个体称为粒子,由两个 d d d维的向量 x i ∈ R d , v i ∈ R d x_i\in\R^d,v_i\in\R^d xi∈Rd,vi∈Rd表示, x i x_i xi称为粒子的位置, v i v_i vi称为粒子的速度。一个种群可以表示为 E = ( X , V ) E=(X,V) E=(X,V),其中 X = ( x 1 , x 2 , … , x N ) X=(x_1,x_2,\dots,x_N) X=(x1,x2,…,xN), V = ( v 1 , v 2 , … , v N ) V=(v_1,v_2,\dots,v_N) V=(v1,v2,…,vN). 环境中的适应性函数仅仅取决于位置 f ( x i ) f(x_i) f(xi).
粒子群算法当中,每一个粒子都需要维护两个变量 p i ∈ R , P i ∈ R d p_i\in\R, P_i\in\R^d pi∈R,Pi∈Rd,其中 p i p_i pi是在以往迭代轮数当中,粒子 i i i所取得的最大适应度,而 P i P_i Pi是取得该适应度时的位置。
同时在每一轮迭代当中,还要找出两个变量 s ∈ R , S ∈ R d s\in\R,S\in\R^d s∈R,S∈Rd,分别是当前种群当中,适应度的最大值,以及适应度最大的粒子所处位置。
标准粒子群算法的参数包括:
标准粒子群算法的流程可以描述为:
1 初始化
随机生成(或按照一定分布)粒子群 X ( t = 1 ) , V ( t = 1 ) X^{(t=1)},V^{(t=1)} X(t=1),V(t=1),根据初始化条件计算 p i ( 0 ) , P i ( 0 ) p_i^{(0)},P_i^{(0)} pi(0),Pi(0),迭代轮数置为 t = 1 t=1 t=1
2 计算适应度
计算每一个粒子的适应度 f ( x i ) f(x_i) f(xi),若 f ( x i ) > p i ( t − 1 ) f(x_i)>p_i^{(t-1)} f(xi)>pi(t−1),则更新 p i ( t ) = f ( x i ) , P i ( t ) = x i p_i^{(t)}=f(x_i),P_i^{(t)}=x_i pi(t)=f(xi),Pi(t)=xi,否则 p i ( t ) = p i ( t − 1 ) , P i ( t ) = P i ( t − 1 ) p_i^{(t)}=p_i^{(t-1)}, P_i^{(t)}=P_i^{(t-1)} pi(t)=pi(t−1),Pi(t)=Pi(t−1)
计算出当前种群最优: s ( t ) , S ( t ) s^{(t)}, S^{(t)} s(t),S(t)
3 更新粒子
按照如下公式更新粒子的速度和位置:
v i ( t + 1 ) = ω ( t ) v i ( t ) + c 1 r 1 ( P i ( t ) − x i ( t ) ) + c 2 r 2 ( S ( t ) − x i ( t ) ) x i ( t + 1 ) = x i ( t ) + v i ( t ) \begin{align*} &v_i^{(t+1)}=\omega(t)v_i^{(t)}+c_1r_1(P_i^{(t)}-x_i^{(t)})+c_2r_2(S^{(t)}-x_i^{(t)})\\ &x_i^{(t+1)}=x_i^{(t)}+v_i^{(t)} \end{align*} vi(t+1)=ω(t)vi(t)+c1r1(Pi(t)−xi(t))+c2r2(S(t)−xi(t))xi(t+1)=xi(t)+vi(t)
其中 ω ( t ) \omega(t) ω(t)是随迭代轮数自适应的惯性因子,而 r 1 r_1 r1和 r 2 r_2 r2是两个 ( 0 , 1 ) (0,1) (0,1)间的随机数.
4 检查结束条件
如果满足结束条件或 t > G t>G t>G,则算法终止,否则返回到2,并且设置 t = t + 1 t=t+1 t=t+1.
粒子群算法当中的位置和速度更新公式
v i ( t + 1 ) = ω ( t ) v i ( t ) + c 1 r 1 ( P i ( t ) − x i ( t ) ) + c 2 r 2 ( S ( t ) − x i ( t ) ) x i ( t + 1 ) = x i ( t ) + v i ( t ) \begin{align*} &v_i^{(t+1)}=\omega(t)v_i^{(t)}+c_1r_1(P_i^{(t)}-x_i^{(t)})+c_2r_2(S^{(t)}-x_i^{(t)})\\ &x_i^{(t+1)}=x_i^{(t)}+v_i^{(t)} \end{align*} vi(t+1)=ω(t)vi(t)+c1r1(Pi(t)−xi(t))+c2r2(S(t)−xi(t))xi(t+1)=xi(t)+vi(t)
模拟的是单个智能体的决策过程。每个智能体都有回到其历史最优值的趋势 P i ( t ) − x i ( t ) P_i^{(t)}-x_i^{(t)} Pi(t)−xi(t),前往种群最优值的趋势 S ( t ) − x i ( t ) S^{(t)}-x_i^{(t)} S(t)−xi(t),智能体通过一个随机权值组合 ( c 1 r 1 , c 2 r 2 ) (c_1r_1,c_2r_2) (c1r1,c2r2)来将这两个趋势结合起来。同时,智能体由于先前的速度,在物理空间中存在惯性 ω ( t ) v i ( t ) \omega(t)v_i^{(t)} ω(t)vi(t). 这三个部分组合在一起,就构成了对速度的改变量。而位置的改变,就是速度,这是符合物理直觉的。
为了增加更多的随机性,避免算法陷入局部最优值,我们还可以对标准粒子群算法进行修改,得到局部粒子群算法。局部粒子群算法相比较于标准粒子群算法的改动在于:当前迭代轮次当中,每个粒子都计算一个局部适应度最优值 s i ( t ) s_i^{(t)} si(t)和局部最优位置 S i ( t ) S_i^{(t)} Si(t). 局部 s i ( t ) s_i^{(t)} si(t)和 S i ( t ) S_i^{(t)} Si(t)的选择范围,通常是编号与 i i i相近的个体。例如我们可以取
s i ( t ) = Best ( f ( x i − 1 ( t ) ) , f ( x i ( t ) ) , f ( x i + 1 ( t ) ) ) S i ( t ) = BestX ( f ( x i − 1 ( t ) ) , f ( x i ( t ) ) , f ( x i + 1 ( t ) ) ) s_i^{(t)}=\text{Best}(f(x_{i-1}^{(t)}),f(x_i^{(t)}),f(x_{i+1}^{(t)}))\\ S_i^{(t)}=\text{BestX}(f(x_{i-1}^{(t)}),f(x_i^{(t)}),f(x_{i+1}^{(t)})) si(t)=Best(f(xi−1(t)),f(xi(t)),f(xi+1(t)))Si(t)=BestX(f(xi−1(t)),f(xi(t)),f(xi+1(t)))
相应的,粒子的更新算法也要修改为
v i ( t + 1 ) = ω ( t ) v i ( t ) + c 1 r 1 ( P i ( t ) − x i ( t ) ) + c 2 r 2 ( S i ( t ) − x i ( t ) ) x i ( t + 1 ) = x i ( t ) + v i ( t ) \begin{align*} &v_i^{(t+1)}=\omega(t)v_i^{(t)}+c_1r_1(P_i^{(t)}-x_i^{(t)})+c_2r_2(S_i^{(t)}-x_i^{(t)})\\ &x_i^{(t+1)}=x_i^{(t)}+v_i^{(t)} \end{align*} vi(t+1)=ω(t)vi(t)+c1r1(Pi(t)−xi(t))+c2r2(Si(t)−xi(t))xi(t+1)=xi(t)+vi(t)
差分算法类似于遗传算法,具有选择、交叉、变异三个流程。
标准的差分算法可以表述为:
1 初始化
随机初始化一个由 N N N个 d d d维行向量组成的集合: X ( 0 ) = { x i ( 0 ) ∈ R d ∣ i = 1 , 2 , … , N } X^{(0)}=\{x_i^{(0)}\in\R^d|i=1,2,\dots,N\} X(0)={ xi(0)∈Rd∣i=1,2,…,N},称为种群
初始化变异矩阵 H ( 0 ) = 0 ∈ R N × d H^{(0)}=\bm 0\in \R^{N\times d} H(0)=0∈RN×d
初始化子代矩阵 V ( 0 ) = 0 ∈ R N × d V^{(0)}=\bm 0\in \R^{N\times d} V(0)=0∈RN×d
初始化进化代数 t = 0 t=0 t=0
2 差分变异
对于每一个个体 x i ( t ) x_{i}^{(t)} xi(t),随机选择三个各不相同的个体 x p 1 ( t ) , x p 2 ( t ) , x p 3 ( t ) , ( i ≠ p 1 ≠ p 2 ≠ p 3 ) x_{p_1}^{(t)},x_{p_2}^{(t)},x_{p_3}^{(t)},\ (i\neq p_1\neq p_2\neq p_3) xp1(t),xp2(t),xp3(t), (i=p1=p2=p3). 计算出变异向量:
h i ( t + 1 ) = x p 1 ( t ) + F ( x p 2 ( t ) − x p 3 ( t ) ) h_i^{(t+1)}=x_{p_1}^{(t)}+F(x_{p_2}^{(t)}-x_{p_3}^{(t)}) hi(t+1)=xp1(t)+F(xp2(t)−xp3(t))
如果不存在局部最优问题,也就是环境当中的局部最优适应度等价于整体最优适应度,那么可以把 x p 1 ( t ) x_{p_1}^{(t)} xp1(t)替换为当前种群中适应度最高的个体 x b t x_b^{t} xbt,即
h i ( t + 1 ) = x b ( t ) + F ( x p 2 ( t ) − x p 3 ( t ) ) h_i^{(t+1)}=x_{b}^{(t)}+F(x_{p_2}^{(t)}-x_{p_3}^{(t)}) hi(t+1)=xb(t)+F(xp2(t)−xp3(t))
这样会使得收敛更快
3 交叉操作
对于每一个个体 i , j i,j i,j,随机采样一个 λ ∈ ( 0 , 1 ) \lambda\in(0,1) λ∈(0,1),计算子代单点位值:
v i j ( t + 1 ) = { h i j ( t + 1 ) , λ < c x i j ( t ) , λ ≥ c v_{ij}^{(t+1)}=\begin{cases} h_{ij}^{(t+1)},&\lambda<c\\ x_{ij}{(t)},&\lambda\geq c \end{cases} vij(t+1)={ hij(t+1),xij(t),λ<cλ≥c
4 选择操作
对于每一个个体编号 i i i,判断子代向量 v i ( t + 1 ) v_i^{(t+1)} vi(t+1)和父代 x i ( t ) x_i^{(t)} xi(t)的适应度,保留适应度更大的一个:
x i ( t + 1 ) = { x i ( t ) , f ( x i ( t ) ) ≥ f ( v i ( t + 1 ) ) v i ( t + 1 ) , f ( x i ( t ) ) < f ( v i ( t + 1 ) ) x_i^{(t+1)}=\begin{cases} x_i^{(t)},&f(x_i^{(t)})\geq f(v_i^{(t+1)})\\ v_i^{(t+1)},&f(x_i^{(t)})<f(v_i^{(t+1)}) \end{cases} xi(t+1)={ xi(t),vi(t+1),f(xi(t))≥f(vi(t+1))f(xi(t))<f(vi(t+1))
Rosenbrock函数的定义式为:
{ f ( x 1 , x 2 ) = 100 ( x 1 2 − x 2 2 ) + ( 1 − x 1 ) 2 − 2.048 ≤ x i ≤ 2.048 , i = 1 , 2 \begin{cases} f(x_1,x_2)=100(x_1^2-x_2^2)+(1-x_1)^2\\ -2.048\leq x_i\leq 2.048,&i=1,2 \end{cases} { f(x1,x2)=100(x12−x22)+(1−x1)2−2.048≤xi≤2.048,i=1,2
我们想要求解如下最优化问题
max x 1 , x 2 f ( x 1 , x 2 ) s.t. − 2.048 ≤ x i ≤ 2.048 , i = 1 , 2 \begin{align*} \mathop\text{max}\limits_{x_1,x_2}\ &f(x_1,x_2)\\ \text{s.t.}\ &-2.048\leq x_i\leq 2.048,&i=1,2 \end{align*} x1,x2max s.t. f(x1,x2)−2.048≤xi≤2.048,i=1,2
Rosenbrock最优化的可行解空间是 [ − 2.048 , 2.048 ] 2 ⊂ R 2 [-2.048,2.048]^2\sub\R^2 [−2.048,2.048]2⊂R2,我们可以把这个空间离散化,在 x 1 , x 2 x_1,x_2 x1,x2轴上,分别以长度 0.004 0.004 0.004为单位,划分成离散的区间片段。以区间 [ − 2.048 , − 2.044 ) [-2.048,-2.044) [−2.048,−2.044)编号为 0 0 0,沿着实数轴的正向递增地编号为 0 , 1 , … , 1023 0,1,\dots,1023 0,1,…,1023.
在两个轴上分别取一个区间,编号组合为 ( i , j ) (i,j) (i,j),它们的交叉部分就是一个可行解空间上的矩形区域。把 i , j i,j i,j都转换成10位的二进制串,再首位拼接为20位的二进制串 x x x,就把这个二进制串视为区间 [ 0.004 i − 2.048 , 0.004 i − 2.044 ] × [ 0.004 j − 2.048 , 0.004 j − 2.044 ] [0.004i-2.048,0.004i-2.044]\times[0.004j-2.048,0.004j-2.044] [0.004i−2.048,0.004i−2.044]×[0.004j−2.048,0.004j−2.044]内任何一个点的编码,而反过来,用点 ( 0.004 i − 2.048 , 0.004 j − 2.048 ) (0.004i-2.048,0.004j-2.048) (0.004i−2.048,0.004j−2.048)作为 x x x的解码值。
把编码和解码的流程写作算子 encode ( ⋅ ) \text{encode}(\cdot) encode(⋅), decode ( ⋅ ) \text{decode}(\cdot) decode(⋅)
参数:
流程:
E c = Select ( E ) E_c=\text{Select}(E) Ec=Select(E)是这样计算的:
E m = Crossover ( E c ) E_m=\text{Crossover}(E_c) Em=Crossover(Ec)的计算规则是这样的:
E = Mutation ( E m ) E=\text{Mutation}(E_m) E=Mutation(Em)是这样计算的:
参数:
算法流程:
参数:
流程:
h i = x r 1 + F ( x r 2 − x r 3 ) h_i=x_{r_1}+F(x_{r_2}-x_{r_3}) hi=xr1+F(xr2−xr3)
v i j = { h i j , λ < c x i j , λ ≥ c v_{ij}=\begin{cases} h_{ij},&\lambda<c\\ x_{ij},&\lambda\geq c \end{cases} vij={ hij,xij,λ<cλ≥c
x i = { x i , f ( x i ) ≥ f ( v i ) v i , f ( x i ) < f ( v i ) x_i=\begin{cases} x_i,&f(x_i)\geq f(v_i)\\ v_i,&f(x_i)<f(v_i) \end{cases} xi={ xi,vi,f(xi)≥f(vi)f(xi)<f(vi)
文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别
文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具
文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量
文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置
文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖
文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...
文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序
文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码
文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型
文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件
文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令
文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线