adaboost-笔记(1)
1 - 加法模型
加法模型,就是通过训练集不断的得到不同的分类器(回归),然后将这些分类器组合成一个新的分类器的过程。
假设有\(N\)个样本,且我们的加法模型如下:
\]
其中\(x\)为自变量,即样本;\(\cal Y_m\)为第\(m\)个分类器的参数;\(b(x;\cal Y_m)\)为分类器,也就是基函数;\(\beta_m\)为该分类器的系数。
可以看出,在给定这样一个加法模型的思路以及固定的训练集后,我们要做的就是最小化该模型的损失,即:
\]
对于这样一个模型,训练的思路是:因为是个加法模型,所以可以从前向后,每一步只学习一个分类器(即基函数)和系数,让它逐步的逼近目标函数,直到达到我们能够接受的误差为止。该方法也叫做前向分步算法。
前向分布算法过程如下:
假设目前训练集\(T={(x_1,y_1),(x_2,y_2),...(x_N,y_N)}\);损失函数\(L(y,f(x))\);分类器\({b(x;\cal Y)}\)。目标是得到最后的加法模型\(f(x)\)。
1)得到第一个分类器\(f_0(x)=0\)
2)对于\(m=1,2,...M\)
i)如数学归纳法一样,假设目前已经得到了前\(m-1\)个分类器:
\]
那么,对于第\(m\)个分类器的参数及系数求法:
\]
这样就得到了第\(m\)个分类器的参数和系数;
ii)然后更新旧加法模型,得到新的加法模型:
\]
这样,就是将整个模型转换成了一步求得一个模型的参数和系数的优化问题上。
2 - adaboost
adaboost是加法模型的一个特例。假设目前有训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\), 其中样本都为\(n\)维向量\(x_i\in\bf R^n\), 标签\(y_i\in\{-1,+1\}\)
1)先设定初始时的训练样本的权值:
\]
2)对\(m=1,2,...,M\),即有\(M\)个分类器,则:
i)使用具有权值分布\(D_m\)的训练集学习,得到第\(m\)个基本分类器:
\]
ii)然后计算基于当前分类器\(G_m(x)\)在训练集上的分类误差率:
\]
ps:当然是选择当前权值基础上分类误差率最低的那个分类器作为当前分类器。所以其实是通过ii)来确定i)的分类器
iii)计算该分类器\(G_m(x)\)的系数:
\]
这里对数是自然对数。
ps:可以发现,当\(e_m\leq\frac{1}{2}\)时,\(\alpha_m\geq0\),并且\(\alpha_m\)随着\(e_m\)的减小而增大,也就是分类误差率越小的基本分类器在最终分类器中作用越大。
iv)更新训练集的权值为下一个分类器做准备:
\(D_{m+1}=(w_{m+1,1},...,w_{m+1,i},...,w_{m+1,N})\)
\(w_{m+1,i}=\frac{w_mi}{Z_m}exp(-\alpha_my_iG_m(x_i)),i=1,2,...N\)
这里\(Z_m\)是归一化因子:
\]
ps:权值更新的式子可以写成如下形式:
\begin{cases}
\frac{w_{mi}}{Z_m}e^{-\alpha_m},& G_m(x_i)=y_i\\
\frac{w_{mi}}{Z_m}e^{\alpha_m},& G_m(x_i)\neq y_i
\end{cases}\]
可以看出,当样本分类正确时,其权值在变小,而当样本分类错误时,其权值被放大,由此,误分类样本在下一轮学习中会起更大作用,也就是下一个分类器会更关注那些误分类的样本。
3)构建基本分类器的线性组合:
\]
得到最终分类器:
\]
2.1 这里举个例子:
假设分类器是一个阈值分类器,即\(x>v,y=1\)和\(x<v,y=-1\),训练集为简单的一维数据:
图2.1 李航书上表8.1
1)最开始每个样本的权重为相等,即:
\(D_1=(w_{11},w_{12},...w_{110})\)
\(w_{1i}=0.1,i=1,2,...,10\)
2)然后计算基于\(v=\{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5\}\)一共9个可选划分点基础上误差分类率最小的分类器:
\(e_{0.5}=0.5,错分类样本\{2,3,7,8,9\}\)
\(e_{1.5}=0.4,错分类样本\{3,7,8,9\}\)
\(e_{2.5}=0.3,错分类样本\{7,8,9\}\)
\(e_{3.5}=0.4,错分类样本\{4,7,8,9\}\)
\(e_{4.5}=0.5,错分类样本\{4,5,7,8,9\}\)
\(e_{5.5}=0.6,错分类样本\{4,5,6,7,8,9\}\)
\(e_{6.5}=0.5,错分类样本\{4,5,6,8,9\}\)
\(e_{7.5}=0.4,错分类样本\{4,5,6,9\}\)
\(e_{8.5}=0.3,错分类样本\{4,5,6\}\)
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
'''g1分类器,这里是划分点为2.5'''
def g1(x): return 1 if x < 2.5 else -1
y_prd = [g1(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1]
e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d1)] ) # 0.3
i)因为当2.5时,错误率最低,则第一个分类器:
\quad1,&x<2.5\\
-1,&x>2.5
\end{cases}\]
ii)当前误差率为0.3
iii)计算第一个分类器系数:
\]
iv)更新训练集的权值分布:
\(D_2=(w_{21},...,w_{2i},...w_{210})\)
\(w_{2i}=\frac{w_{1i}}{Z_1}exp(-\alpha_iy_iG_1(x_i)),i=1,2,...10\)
\(D_2=(0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715)\)
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
z = []
'''g1分类器,这里是划分点为2.5'''
def g1(x): return 1 if x < 2.5 else -1
for ind,(d1Item,yItem) in enumerate(zip(d1,y)):
w = d1Item*np.exp(-0.4236*yItem*g1(ind))
z.append(w)
d2 = [ zItem/sum(z) for zItem in z ]
\(f_1(x)=0.4236G_1(x)\)
此时分类器\(sign[f_1(x)]\)当前误分类3个\(\{7,8,9\}\);
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
'''g1分类器,这里是划分点为2.5'''
def g1(x): return 1 if x < 2.5 else -1
def f1(x): return 1 if 0.4236*g1(x) >0 else -1
y_prd = [ f1(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1]
3)接着处理\(m=2\)时。
同上述方法计算每个阈值\(v=\{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5\}\)下分类误差率
\(e_{0.5}=0.6428,错分类样本\{2,3,7,8,9\}\)
\(e_{1.5}=0.5713,错分类样本\{3,7,8,9\}\)
\(e_{2.5}=0.4998,错分类样本\{7,8,9\}\)
\(e_{3.5}=0.5713,错分类样本\{4,7,8,9\}\)
\(e_{4.5}=0.6428,错分类样本\{4,5,7,8,9\}\)
\(e_{5.5}=0.7143,错分类样本\{4,5,6,7,8,9\}\)
\(e_{6.5}=0.5477,错分类样本\{4,5,6,8,9\}\)
\(e_{7.5}=0.3811,错分类样本\{4,5,6,9\}\)
\(e_{8.5}=0.2145,错分类样本\{4,5,6\}\)
最低的分类器:
\quad1,&x<8.5\\
-1,&x>8.5
\end{cases}\]
i)此时误差率为0.2145
# 可以看出当前样本的权重值,其中经过第一次分类之后错误分类的权重变大
d2 = [0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715]
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
'''g2分类器,这里是划分点为8.5'''
def g2(x): return 1 if x < 8.5 else -1
y_prd = [ g2(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1]
# 计算预测值与实际值不相等的,即为误分类,将其乘以样本权重,得到误差率
e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d2)] ) # 0.2145
ii)系数为0.6496
iii)训练集权值分布:
\(D_3=\{0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455\}\)
\(f_2(x)=0.4236G_1(x)+0.6496G_2(x)\)
iv)此时分类器\(sign[f_2(x)]\)训练集上错分类样本还是3个\(\{4,5,6\}\)
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
d3 = [0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455]
def g1(x): return 1 if x<2.5 else -1
def g2(x): return 1 if x<8.5 else -1
def f2(x): return 1 if (0.4236*g1(x) + 0.6496*g2(x)) > 0 else -1
y_prd = [ f2(i) for i in x] # [1, 1, 1, 1, 1, 1, 1, 1, 1, -1]
isEqual = [1 if ypred == ygt else 0 for ypred,ygt in zip(y_prd, y)] # [1, 1, 1, 0, 0, 0, 1, 1, 1, 1]
4)如上述计算过程,第三轮得到的分类器:
\quad -1,&x<5.5\\
1,&x>5.5
\end{cases}\]
i)此时误差率为0.1820
d3 = [0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455]
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
'''g3分类器,这里是划分点为5.5'''
def g3(x): return -1 if x < 5.5 else 1
y_prd = [ g3(i) for i in x] # [-1, -1, -1, -1, -1, -1, 1, 1, 1, 1]
# 计算预测值与实际值不相等的,即为误分类,将其乘以样本权重,得到误差率
e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d3)] ) # 0.182
ii)系数为0.6496
iii)训练集权值分布:
\(D_4=\{0.125,0.125,0.125,0.102,0.102,0.102,0.065,0.065,0.065,0.125\}\)
\]
x = [0,1,2,3,4,5,6,7,8,9]
y = [1,1,1,-1,-1,-1,1,1,1,-1]
def g1(x): return 1 if x<2.5 else -1
def g2(x): return 1 if x<8.5 else -1
def g3(x): return -1 if x<5.5 else 1
def f3(x): return 1 if (0.4236*g1(x) + 0.6496*g2(x) + 0.7514*g3(x)) > 0 else -1
y_prd = [ f3(i) for i in x] # [1, 1, 1, -1, -1, -1, 1, 1, 1, -1]
isEqual = [1 if ypred == ygt else 0 for ypred,ygt in zip(y_prd, y)] # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
4)如上述计算过程,第三轮得到的分类器:
此时误分类样本为0个,所以无需训练所谓第四个基分类器。
最终分类器为:
\]
3 - boosting tree
提升树是以回归树或者分类树作为基本分类器的模型,被认为统计学习中性能最好的方法之一(当然还有svm了)。
该类方法是采用了加法模型(基函数的线性组合)和前向分布算法,用决策树为基函数的提升方法叫提升树,分类问题 时,可采用二叉分类树,回归问题时,可采用二叉回归树。提升树模型可以表示为决策树的加法模型:
\]
其中,\(T(x;\Theta_m)\)表示一棵决策树;\(\Theta_m\)表示第\(m\)棵决策树的参数;\(M\)为树的个数。
对于整个过程,如上面的加法模型一样,先确定初始提升树\(f_0(x)=0\),然后第\(m\)轮之后,整个的模型:
\]
其中\(f_{m-1}(x)\)是当前求得的模型,然后通过经验风险最小化确定下一棵决策树的参数\(\Theta_m\):
\]
ps:因为树的线性组合可以很好的拟合训练数据,即使数据中的输入与输出的关系很复杂也如此。所以提升树是一个高功能的学习算法
通常来说,不同的提升树学习算法,主要区别在于使用的损失函数:1)平方误差损失函数的回归问题;2)指数损失函数的分类问题;3)一般损失函数的一般决策问题。
对于二类分类问题,即将adaboost中的基本分类器限制为二类分类树(即树桩:一个根节点,两个叶子节点)。这里主要介绍回归问题的提升树。
假设训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\),且\(x_i\in \cal X \subseteq \bf R^n\),\(y_i\in \cal Y \subseteq \bf R\).对于一棵回归树,如果将输入空间划分成\(J\)个互不相交的区域\(R_1,R_2,...R_J\)并且在每个区域上确定输出常量\(c_j\),那么树可表示为:
\]
其中参数\(\Theta=\{(R_1,c_1),(R_2,c_2),...,(R_J,c_J)\}\)表示树的区域划分和各个区域上的常量输出\(J\)表示回归树的复杂度,即最终叶节点个数。
前向分步步骤:
假设训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\),且\(x_i\in \cal X \subseteq \bf R^n\),\(y_i\in \cal Y \subseteq \bf R\)
1)初始化\(f_0(x)=0\)
2)对于轮数\(m=1,2,...,M\)
i)当第\(m\)步时,已知前\(m-1\)轮结果,需要求解:
\]
得到的\(\hat\Theta_m\)即为第\(m\)棵树的参数。当采用平方误差损失函数时,:
\]
代入得:
L(y,f_{m-1}(x)+T(x:\Theta_m))
&=&[y-f_{m-1}(x)-T(x;\Theta_m)]^2\\
&=&[r-T(x;\Theta_m)]^2
\end{eqnarray}\]
其中\(r=y-f_{m-1}(x)\)是前\(m-1\)轮后得到的模型拟合数据的残差,所以对于回归问题的提升树来说,就是拟合当前模型的残差。
ii)对于每个样本\(i=1,...N\)
求得他们的残差:
\]
iii)拟合这轮得到的残差\(r_{mi}\),基于整个训练集学习一棵新的回归树,得到\(T(x;\Theta_m)\)
iv)更新\(f_m(x)=f_{m-1}(x)+T(x; \Theta_m)\)
3)得到最后结果模型:
\]
3.1 回归提升树例子
如下表数据:
图3.1.1 李航书上表8.2
\(x\)取值范围[0.5,10.5],\(y\)取值范围为[5.0,10.0]。为了简单起见,这里只采用树桩来生成每轮的回归树,且输入空间只划分成2个区域\(\{R_1,R_2\}\)。
这里略过了\(f_0(x)\).直接生成\(f_1(x)\):
通过优化下面的问题:
\]
来求解切分点\(s\),使得:
\(R_1=\{x|x\leq s\}\),\(R_2=\{x|x>s\}\)
从而计算在当前切分点基础上,在\(R_1\),\(R_2\)使平方损失误差达到最小值的\(c_1\),\(c_2\):
\]
1)上述训练集样本的切分点有\(\{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5\}\)
对应的最小误差值如下:
k发现当\(s=6.5\)时\(m(s)\)达到最小值。此时\(R_1=\{1,2,...,6\}\);\(R_2=\{7,8,9,10\}\).\(c_1=6.24;c_2=8.91\)。所以回归树\(T_1(x)\)为:
6.24,& x<6.5\\
8.91,&x\geq6.5
\end{cases}\]
从而\(f_1(x)=T_1(x)\)
X = [1,2,3,4,5,6,7,8,9,10]
Y0 = [5.56, 5.70, 5.91, 6.40, 6.80, 7.05, 8.90, 8.70, 9.00, 9.05]
X_splits = [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]
def cost_split_point(ind,xs,YT):
R1 = YT[:ind+1]
R2 = YT[ind+1:]
c1 = round(mean(R1),3)
c2 = round(mean(R2),3)
ans0 = [(x-c1)*(x-c1) for x in R1]
ans1 = [(x-c2)*(x-c2) for x in R2]
return [sum(ans0+ans1), c1, c2]
cost = [[xs]+cost_split_point(ind,xs,Y0) for ind,xs in enumerate(X_splits)]
#[[1.5, 15.723, 5.559, 7.501],
# [2.5, 12.083, 5.629, 7.726],
# [3.5, 8.365, 5.723, 7.985],
# [4.5, 5.775, 5.892, 8.25],
# [5.5, 3.911, 6.073, 8.540],
# [6.5, 1.930, 6.236, 8.912],
# [7.5, 8.009, 6.617, 8.916],
# [8.5, 11.735, 6.877, 9.025],
# [9.5, 15.738, 7.113, 9.050]]
2)计算\(f_1(x)\)拟合训练集的残差计算公式\(r_{2i}=y_i-f_1(x_i),i=1,2,...,10\)
图3.1.3
用\(f_1(x)\)拟合训练集后的平方损失为:
\]
r_2i = [-0.68, -0.54, -0.33, -0.16, 0.56, 0.81, -0.01, -0.21, 0.09, 0.14]
r_2i = np.array(r_2i)
loss = (r_2i*r_2i).sum()#1.9301
3)在计算新的回归树时,选择的训练集是图3.1.3 而不是原来的3.1.1,即是基于上一轮模型结果之后的残差。从而得到这一轮的回归树:
-0.52,& x<3.5\\
0.22,&x\geq3.5
\end{cases}\]
Y1 = [-0.68, -0.54, -0.33, 0.16, 0.56, 0.81, -0.01, -0.21, 0.09, 0.14]
cost = [[xs]+cost_split_point(ind,xs,Y1) for ind,xs in enumerate(X_splits)]
#[[1.5, 1.417, -0.680, 0.073],
# [2.5, 1.002, -0.609, 0.151],
# [3.5, 0.790, -0.517, 0.22],
# [4.5, 1.129, -0.347, 0.230],
# [5.5, 1.657, -0.166, 0.164],
# [6.5, 1.930, -0.003, 0.003],
# [7.5, 1.929, -0.004, 0.007],
# [8.5, 1.896, -0.029, 0.115],
# [9.5, 1.908, -0.017, 0.140]]
在得到这一轮的回归树之后,将前面得到的模型与当前模型相加,且重合区域需要注意相加减,如当\(x<3.5\)时,\(f_2(x)=-0.52+6.24=5.72\):
5.72,& x<3.5\\
6.46,& 3.5\leq x<6.5\\
9.13,& x\geq 6.5
\end{cases}\]
用\(f_2(x)\)拟合训练集损失为\(L(y,f_2(x))=\sum_{i=1}^{10}(y_i-f_2(x_i))^2=0.79\)
如此得到最后结果:
5.63,& x<2.5\\
5.82,& 2.5\leq x<3.5\\
6.56,& 3.5\leq x<4.5\\
6.83,& 4.5\leq x <6.5\\
8.95,&x \geq6.5
\end{cases}\]
当前模型拟合训练集平方损失为0.17.假设此时误差已经满足要求,那么就可以将\(f_6(x)\)作为整个训练集的提升树
3.2 gradient boosting tree
当提升树中选取的损失函数是平方损失和指数损失函数时,训练过程如上述所属,可是当一般损失函数而言,优化相对就较为麻烦了,这时候可以用freidma提出的gradient boosting算法,这是与最速下降法相似的方法,使用了损失函数的负梯度:
\]
将其作为3.1中每一轮计算的平方损失残差值,即这一轮所谓的"训练集"
其他部分的计算不变。
参考资料:
[] 李航,统计学习方法
2017/04/07 第一次修改!
adaboost-笔记(1)的更多相关文章
- AdaBoost笔记之通俗易懂原理介绍
转自:https://blog.csdn.net/px_528/article/details/72963977 写在前面 说到Adaboost,公式与代码网上到处都有,<统计学习方法>里 ...
- AdaBoost笔记之原理
转自:https://www.cnblogs.com/ScorpioLu/p/8295990.html 一.Boosting提升算法 AdaBoost是典型的Boosting算法,属于Boosting ...
- AdaBoost笔记之代码
最近要做二分类问题,先Mark一下知识点和代码,参考:Opencv2.4.9源码分析——Boosting 以下内容全部转自此文 一 原理 二 opencv源码 1.先看构建Boosting的参数: ...
- 机器学习实战 - 读书笔记(07) - 利用AdaBoost元算法提高分类性能
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习笔记,这次是第7章 - 利用AdaBoost元算法提高分类性能. 核心思想 在使用某个特定的算法是, ...
- 数据挖掘学习笔记--AdaBoost算法(一)
声明: 这篇笔记是自己对AdaBoost原理的一些理解,如果有错,还望指正,俯谢- 背景: AdaBoost算法,这个算法思路简单,但是论文真是各种晦涩啊-,以下是自己看了A Short Introd ...
- AdaBoost学习笔记
学习了李航<统计学习方法>第八章的提升方法,现在对常用的一种提升方法AdaBoost作一个小小的笔记,并用python实现书本上的例子,加深印象.提升方法(boosting)是一种常用的统 ...
- 机器学习实战笔记7(Adaboost)
1:简单概念描写叙述 Adaboost是一种弱学习算法到强学习算法,这里的弱和强学习算法,指的当然都是分类器,首先我们须要简介几个概念. 1:弱学习器:在二分情况下弱分类器的错误率会低于50%. 事实 ...
- 《机器学习实战》笔记——AdaBoost
笔记见备注 # _*_ coding:utf-8 _*_ from numpy import * # 简单数据集 def loadSimpData(): datMat = matrix([[1., 2 ...
- 【转载】 机器学习实战 - 读书笔记(07) - 利用AdaBoost元算法提高分类性能
原文地址: https://www.cnblogs.com/steven-yang/p/5686473.html ------------------------------------------- ...
- 【机器学习笔记之四】Adaboost 算法
本文结构: 什么是集成学习? 为什么集成的效果就会好于单个学习器? 如何生成个体学习器? 什么是 Boosting? Adaboost 算法? 什么是集成学习 集成学习就是将多个弱的学习器结合起来组成 ...
随机推荐
- 支持MPI的hdf5库的编译
作者:朱金灿 来源:http://blog.csdn.net/clever101 因为最近要研究并行I/O,据说hdf5文件格式可以支持并行I/O,深度学习框架Caffe用的是hdf格式,所以决定把h ...
- 二路归并算法的java实现
“归并”的含义是将两个或者两个以上的有序表组合成一个新的有序表. 假设待排序表含有n个元素,则可以看成是n个有序的子表,每个子表的长度为1,然后两两归并,得到(n/2)或者(n/2+1)个长度为2或1 ...
- JS 同步输入
var txtBigBalance; //金额同步输入 if ($.browser.msie)//IE { $("#txtBalanceP").get(0).onpropertyc ...
- UE3多参数函数实现
基础宏定义 #define VARARG_EXTRA(A) A, #define VARARG_NONE #define VARARG_PURE =0 static inline DWORD Chec ...
- mysql----JOIN Quiz
JOIN quiz game id mdate stadium team1 team2 1001 8 June 2012 National Stadium, Warsaw POL GRE 1002 8 ...
- cmd输出控制台传递的参数
public class Test2{ public static void main(String[] args){ System.out.println(args[0]); System.out. ...
- CentOS 6.5 安装mysql 过程记录
下载的时候一定选对应的版本, el6 还是el7 或者其他版本,不然会出现意向不到的惊喜 比如:我刚开始的时候下载的 el7 版本的 mysql , 然后安装的时候 就会出现: libc.so.(GL ...
- sqlserver备份
/// <summary> /// sqlserver备份 /// </summary> public class SqlserverBack : IBack { privat ...
- c/c++ const this指针
const this指针 方法列表后面的const是什么含义呢?答案:不可以在方法里修改成员变量 class Test{ public: void fun()const{ //data = 10;// ...
- NSMutableArray 增删操作测试
NSMutableArray *testArray = [NSMutableArray array]; [testArray addObject:"]; [testArray addObje ...