Boosting算法

提升算法是一种常见的统计学习方法,其作用为将弱的学习算法提升为强学习算法.其理论基础为:强可学习器与弱可学习器是等价的.即在在学习中发现了’弱学习算法’,则可以通过某些方法将它特生为强可学习器,这是数学可证明的.在分类学习中提升算法通过反复修改训练数据的权值分布,构建一系列的基本分类器(弱分类器),并将这些基本分类器线性组合,构成一个强学习器.代表算法为Adaboost算法,ada是自适应的Adaptive的缩写.

Adaboost

原理

Adaboost的核心思想是通过反复修改数据的权重,从而使一系列弱学习器成为强可学习器.其核心步骤如下:
- 权值调整,提升被错误分类的样本的权重,降低被正确分类的权重
- 基分类器组合,采用加权多数表决算法,加大分类误差率较小的弱分类器的权重,减小误差大的.

特性

  • Adaboost更加专注于偏差,他可以降低基学习器的偏差,对基学习器进行进一步的提升.
  • Adaboost的默认基学习器是决策树,我们也可以过会会使用其他基学习器证明其对降低偏差的影响.
  • Adaboost的训练误差分析表明,Adaboost每次迭代可以减少它在训练数据集上的分类误差率,这说明了它作为提升方法的有效性.但是在实际使用中要注意方差-偏差困境,避免泛化能力的降低.

sklearn实现

sklearn中的实现一共有两种,SAMME 与 SAMME.R:

  • SAMME使用预测错误的标签进行调整,而SAMME则使用预测类别的概率进行调整.
  • SAMME.R收敛速度快,实现较低的测试错误需要的迭代次数更少
  • SAMME.R必须需要基学习器实现了返回类别的预测概率.SAMME则不需要
  • SAMME.R在较大学习率时对原始数据的拟合能力会出现降低,而SAMME不会
  • 在这两个算法中都存在早停(early_stop)机制,当到达内部的停止条件时,就会自动停止提升,从而出现Adaboost实际上的n_estimators小于,我们自己设置的n_estimators,这样做有利于防止过拟合.

这些特性我们将会在后面进行相应的实验证明这些特性.

进行回归学习器的相关实验,验证理论特性

Adaboost可以对基学习器进行进一步提升

简介

我们可以将之前在回归决策树中的例子稍加改造,我们依旧利用numpy生成sin正弦函数的数据,然后添加噪音.
这样通过噪音我们就可以更加直观地看到算法的拟合能力(偏差)以及过拟合现象(方差).

在下面的例子中,我们一共定义了了三个估计器,绘制了三张图片.
其中前两个估计器为决策树,超参数使用了max_depth一个为2,一个为5,后两个为以决策树为基估计器的提升算法,max_depth都为2,但是控制超参数n_estimators不同也就是一个为10(提升了9次),另外一个为500(提升499次).

代码及绘图如下:

首先使用回归类别的学习器进行实验,在sklearn中的AdaBoostRegressor,并没有SAMME与SAMME.R的区别.

%matplotlib inline
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostRegressor# Create a random dataset
rng = np.random.RandomState(1)
X = np.sort(10 * rng.rand(160, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 2 * (0.5 - rng.rand(int(len(X)/5))) # 每五个点增加一次噪音# Fit regression modelestimators_num = 500regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_3 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=5),n_estimators=10, random_state=rng)
regr_4 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=5),n_estimators=estimators_num, random_state=rng)
regr_1.fit(X, y)
regr_2.fit(X, y)
regr_3.fit(X, y)
regr_4.fit(X, y)# Predict
X_test = np.arange(0.0, 10.0, 0.01)[:, np.newaxis]
y_test = np.sin(X_test).ravel()
y_test[::5] += 2 * (0.5 - rng.rand(int(len(X_test)/5))) # 每五个点增加一次噪音
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
y_3 = regr_3.predict(X_test)
y_4 = regr_4.predict(X_test)fig = plt.figure()
fig.set_size_inches(18.5, 10.5)
ax = fig.add_subplot(3, 1, 1)
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
ax.plot(X_test, y_1, color="cornflowerblue",label="max_depth=2", linewidth=2)
ax.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
ax.plot(X_test, y_3, color="r", label="n_estimators=100", linewidth=2)
ax.set_xlabel("data")
ax.set_ylabel("target")
ax.set_ylim(-1.5, 1.5)
ax.set_xlim(-0.5, 10.5)ax = fig.add_subplot(3, 1, 2)
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
ax.plot(X_test, y_3, color="r", label="n_estimators=10", linewidth=2)
ax.plot(X_test, y_4, color="blue", label="n_estimators=1000", linewidth=2)
ax.set_xlabel("data")
ax.set_ylabel("target")
ax.set_ylim(-1.5, 1.5)
ax.set_xlim(-0.5, 10.5)regr_4_estimators_num = len(regr_4.estimators_)
ax = fig.add_subplot(3, 1, 3)
ax.plot(list(range(1, regr_4_estimators_num + 1))[:100], list(regr_4.staged_score(X, y))[:100], label="Traing score")
ax.plot(list(range(1, regr_4_estimators_num + 1))[:100], list(regr_4.staged_score(X_test, y_test))[:100], label="Testing score")
ax.set_xlabel("estimator num")
ax.set_ylabel("score")
ax.legend(loc="lower right")
ax.set_ylim(0, 1)
ax.set_xlim(1, 100)
plt.show()

程序及绘图解析

第一幅图片中绘制了三张曲线,从图片我们可以明显看出,深度为5决策树的拟合效果要好于深度为2的决策树,而提升算法则大幅度强化了原来决策树的拟合能力.

第二张图片中则分别绘制了,n_estimators为10与n_estimators为500的AdaBoost算法(并且基估计器一致).可以看出n_estimators=500的AdaBoost估计器的拟合效果明显要高于n_estimators=10的估计器,但是我们也可以直观的看出后者相较于拟合了更多的噪音.

同时在第三幅图绘制的训练,测试曲线则是绘制了n_estimator=500的AdaBoost估计器在整个提升过程中(n_estimators=1到500的过程中)的训练效果,可以看出虽然随着n_estimators的增加确实可以使AdaBoost拥有更强的拟合能力,但是因为过拟合,测试成绩却也随着拟合能力的提高,先(略微)提高,然后降低了.

限制

虽然AdaBoost可以提高基学习器的拟合能力,但这种提升也取决于基学习器本身,AdaBoost算法无法无限制的提升基学习器的拟合能力.以刚刚的代码为例,假如将AdaBoost的基学习器的max_depth替换为2,那么AdaBoost将会很快早停.因此可见,在实际的使用中不仅仅是AdaBoost的超参数本身,基学习器的选择也是十分重要的.

代码以及演示效果:

regr_5 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=2),n_estimators=estimators_num, random_state=rng)
regr_6 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=3),n_estimators=estimators_num, random_state=rng)regr_5.fit(X, y)
regr_6.fit(X, y)
y_5 = regr_3.predict(X_test)
y_6 = regr_4.predict(X_test)print('regr_5的实际提升次数为%d'%len(regr_5.estimators_))
print('regr_6的实际提升次数为%d'%len(regr_5.estimators_))
# Plot the results
plt.figure(figsize=(18.5, 10.5))
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue",label="max_depth=2", linewidth=2)
plt.plot(X_test, y_5, color="yellowgreen", label="Ada_max_depth=2", linewidth=2)
plt.plot(X_test, y_6, color="r", label="Ada_max_depth=3", linewidth=2)
# plt.plot(X_test, y_4, color="black", label="n_estimators=500", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
regr_5的实际提升次数为10
regr_6的实际提升次数为10

通过绘制出的图形,我们可以看出regr_5(黄绿色)的拟合效果要好于之前所有而学习器,不仅拥有很好的拟合能力,而且过拟合程度很低,在实际的使用过程中,拥有最佳拟合能力与泛化能力的学习器正是我们想要的结果


regr_5 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=2),n_estimators=estimators_num, random_state=rng)

学习率与损失函数

在AdaBoostRegressor比较重要的另外两个超参数则是学习率与损失函数,学习率一般较小,这个请根据具体的CV进行判断,而损失函数的差距则不大,但是因为其对最终结果也存在着一定的影响,请在正式的实验中重视该超参数.
下面的代码展示了不同损失函数时的训练-测试误差曲线:

from sklearn import datasets,model_selection
diabetes = datasets.load_diabetes()  # 使用 scikit-learn 自带的一个糖尿病病人的数据集
X_train, X_test, y_train, y_test = model_selection.train_test_split(diabetes.data, diabetes.target,test_size=0.25, random_state=0)
losses = ['linear', 'square', 'exponential']
fig = plt.figure()
fig.set_size_inches(18.5, 10.5)
ax = fig.add_subplot(1, 1, 1)
for i, loss in enumerate(losses):regr = AdaBoostRegressor(loss=loss, n_estimators=30)regr.fit(X_train, y_train)## 绘图estimators_num = len(regr.estimators_)X = range(1, estimators_num + 1)ax.plot(list(X), list(regr.staged_score(X_train, y_train)),label="Traing score:loss=%s" % loss)ax.plot(list(X), list(regr.staged_score(X_test, y_test)),label="Testing score:loss=%s" % loss)ax.set_xlabel("estimator num")ax.set_ylabel("score")ax.legend(loc="lower right")ax.set_ylim(-1, 1)
plt.suptitle("AdaBoostRegressor")
plt.show()

进行分类决策树的相关实验,证明理论特性

建立四种学习率下SAMME与SAMME.R两种算法的比较.

from sklearn.ensemble import AdaBoostClassifier
digits = datasets.load_digits()
X_train, X_test, y_train, y_test = model_selection.train_test_split(digits.data, digits.target,test_size=0.25, random_state=0,stratify=digits.target)
algorithms = ['SAMME.R', 'SAMME']
fig = plt.figure()
fig.set_size_inches(18.5, 10.5)
learning_rates = [0.05, 0.1, 0.5, 0.9]
for i, learning_rate in enumerate(learning_rates):ax = fig.add_subplot(2, 2, i + 1)for i, algorithm in enumerate(algorithms):clf = AdaBoostClassifier(learning_rate=learning_rate,algorithm=algorithm)clf.fit(X_train, y_train)## 绘图estimators_num = len(clf.estimators_)X = range(1, estimators_num + 1)ax.plot(list(X), list(clf.staged_score(X_train, y_train)),label="%s:Traing score" % algorithms[i])ax.plot(list(X), list(clf.staged_score(X_test, y_test)),label="%s:Testing score" % algorithms[i])ax.set_xlabel("estimator num")ax.set_ylabel("score")ax.legend(loc="lower right")
#     ax.set_title("learing rate:%f" % learning_rate)
fig.suptitle("AdaBoostClassifier : learning_rates = [0.05, 0.1, 0.5, 0.9]")
plt.show()

我们首先考虑从学习率的角度进行比较,非常明显的是在这四幅图中随着学习率的增加,SAMME.R算法的成绩出现了大幅度的下降.
而SAMME在更大的学习率下则指表现出了更快的提升速度(当然对于最终结果,学习率较小更好一些).

同时下面给出一个新的代码,这个代码可以更形象的对比出,学习率对这两种算法的影响:

learning_rates = np.linspace(0.01, 1)
fig = plt.figure(figsize=(18.5,10.5))
algorithms = ['SAMME.R', 'SAMME']
for i, algorithm in enumerate(algorithms):ax = fig.add_subplot(2, 1, i+1)traing_scores = []testing_scores = []for learning_rate in learning_rates:clf = AdaBoostClassifier(learning_rate=learning_rate, n_estimators=100,algorithm=algorithm)clf.fit(X_train, y_train)traing_scores.append(clf.score(X_train, y_train))testing_scores.append(clf.score(X_test, y_test))ax.plot(learning_rates, traing_scores, label="Traing score")ax.plot(learning_rates, testing_scores, label="Testing score")ax.set_xlabel("learning rate")ax.set_ylabel("score")ax.legend(loc="best")ax.set_title("AdaBoostClassifier")
plt.show()

然后我们从两种算法的收敛速度进行比较相比于SAMME,SAMME.R明显拥有更快的收敛速度,同时获取较低的错误率也只需要更少的训练,此处可以参考sklearn的官方文档同时在官网的文档中还给出了另外一个例子,请看下面:

from sklearn.externals.six.moves import zip
from sklearn.datasets import make_gaussian_quantiles
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifierX, y = make_gaussian_quantiles(n_samples=13000, n_features=10,n_classes=3, random_state=1)n_split = 3000X_train, X_test = X[:n_split], X[n_split:]
y_train, y_test = y[:n_split], y[n_split:]bdt_real = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2),n_estimators=600,learning_rate=1)bdt_discrete = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2),n_estimators=600,learning_rate=1.5,algorithm="SAMME")bdt_real.fit(X_train, y_train)
bdt_discrete.fit(X_train, y_train)real_test_errors = []
discrete_test_errors = []for real_test_predict, discrete_train_predict in zip(bdt_real.staged_predict(X_test), bdt_discrete.staged_predict(X_test)):real_test_errors.append(1. - accuracy_score(real_test_predict, y_test))discrete_test_errors.append(1. - accuracy_score(discrete_train_predict, y_test))n_trees_discrete = len(bdt_discrete)
n_trees_real = len(bdt_real)# Boosting might terminate early, but the following arrays are always
# n_estimators long. We crop them to the actual number of trees here:
discrete_estimator_errors = bdt_discrete.estimator_errors_[:n_trees_discrete]
real_estimator_errors = bdt_real.estimator_errors_[:n_trees_real]
discrete_estimator_weights = bdt_discrete.estimator_weights_[:n_trees_discrete]plt.figure(figsize=(15, 5))plt.subplot(131)
plt.plot(range(1, n_trees_discrete + 1),discrete_test_errors, c='black', label='SAMME')
plt.plot(range(1, n_trees_real + 1),real_test_errors, c='black',linestyle='dashed', label='SAMME.R')
plt.legend()
plt.ylim(0.18, 0.62)
plt.ylabel('Test Error')
plt.xlabel('Number of Trees')plt.subplot(132)
plt.plot(range(1, n_trees_discrete + 1), discrete_estimator_errors,"b", label='SAMME', alpha=.5)
plt.plot(range(1, n_trees_real + 1), real_estimator_errors,"r", label='SAMME.R', alpha=.5)
plt.legend()
plt.ylabel('Error')
plt.xlabel('Number of Trees')
plt.ylim((.2,max(real_estimator_errors.max(),discrete_estimator_errors.max()) * 1.2))
plt.xlim((-20, len(bdt_discrete) + 20))plt.subplot(133)
plt.plot(range(1, n_trees_discrete + 1), discrete_estimator_weights,"b", label='SAMME')
plt.legend()
plt.ylabel('Weight')
plt.xlabel('Number of Trees')
plt.ylim((0, discrete_estimator_weights.max() * 1.2))
plt.xlim((-20, n_trees_discrete + 20))# prevent overlapping y-axis labels
plt.subplots_adjust(wspace=0.25)
plt.show()

比较SAMME和SAMME.R [1]算法的性能。SAMME.R使用概率估计来更新可加模型,而SAMME只使用分类。如示例所示,SAMME.R算法通常比SAMME更快地收敛,通过更少的提升迭代实现更低的测试误差。左侧显示每次升压迭代后测试集上每种算法的误差,中间显示每棵树测试集上的分类错误,右侧显示每棵树的升压权重。所有的树在SAMME.R算法中的权重都是1,因此不显示.

同时在里还有另外一个例子很好的展示了,AdaBoost对于不同基学习器的提升的影响.其对于强学习器的提升较少也较慢,但是对弱学习器的提升则更为明显.在下面的例子中,使用的第一个决策树基学习器的是’弱学习器’,AdaBoost对其性能的提升速度很快,而第二个学习器’高斯朴素贝叶斯分类器’在该数据集上则表现为’强学习器’,因此AdaBoost对其的提升要相对慢得多.

from sklearn.naive_bayes import GaussianNBdigits = datasets.load_digits()
X_train, X_test, y_train, y_test = model_selection.train_test_split(digits.data, digits.target,test_size=0.25, random_state=0,stratify=digits.target)fig = plt.figure(figsize=(18.5,10.5))
ax = fig.add_subplot(2, 1, 1)
########### 默认的个体分类器 #############
clf = AdaBoostClassifier(learning_rate=0.1)
clf.fit(X_train, y_train)
## 绘图
estimators_num = len(clf.estimators_)
X = range(1, estimators_num + 1)
ax.plot(list(X), list(clf.staged_score(X_train, y_train)), label="Traing score")
ax.plot(list(X), list(clf.staged_score(X_test, y_test)), label="Testing score")
ax.set_xlabel("estimator num")
ax.set_ylabel("score")
ax.legend(loc="lower right")
ax.set_ylim(0, 1)
ax.set_title("AdaBoostClassifier with Decision Tree")
####### Gaussian Naive Bayes 个体分类器 ########
ax = fig.add_subplot(2, 1, 2)
clf = AdaBoostClassifier(learning_rate=0.1, base_estimator=GaussianNB())
clf.fit(X_train, y_train)
## 绘图
estimators_num = len(clf.estimators_)
X = range(1, estimators_num + 1)
ax.plot(list(X), list(clf.staged_score(X_train, y_train)), label="Traing score")
ax.plot(list(X), list(clf.staged_score(X_test, y_test)), label="Testing score")
ax.set_xlabel("estimator num")
ax.set_ylabel("score")
ax.legend(loc="lower right")
ax.set_ylim(0, 1)
ax.set_title("AdaBoostClassifier with Gaussian Naive Bayes")
plt.show()

Discrete versus Real AdaBoost

* 下面的例子对AdaBoostClassifier的两种算法及其提升效果进行更详细的描述 *

from sklearn.metrics import zero_one_lossn_estimators = 400
# A learning rate of 1. may not be optimal for both SAMME and SAMME.R
learning_rate = 1.X, y = datasets.make_hastie_10_2(n_samples=12000, random_state=1)X_test, y_test = X[2000:], y[2000:]
X_train, y_train = X[:2000], y[:2000]dt_stump = DecisionTreeClassifier(max_depth=1, min_samples_leaf=1)
dt_stump.fit(X_train, y_train)
dt_stump_err = 1.0 - dt_stump.score(X_test, y_test)dt = DecisionTreeClassifier(max_depth=9, min_samples_leaf=1)
dt.fit(X_train, y_train)
dt_err = 1.0 - dt.score(X_test, y_test)ada_discrete = AdaBoostClassifier(base_estimator=dt_stump,learning_rate=learning_rate,n_estimators=n_estimators,algorithm="SAMME")
ada_discrete.fit(X_train, y_train)ada_real = AdaBoostClassifier(base_estimator=dt_stump,learning_rate=learning_rate,n_estimators=n_estimators,algorithm="SAMME.R")
ada_real.fit(X_train, y_train)fig = plt.figure(figsize=(16,8))
ax = fig.add_subplot(111)ax.plot([1, n_estimators], [dt_stump_err] * 2, 'k-',label='Decision Stump Error')
ax.plot([1, n_estimators], [dt_err] * 2, 'k--',label='Decision Tree Error')ada_discrete_err = np.zeros((n_estimators,))
for i, y_pred in enumerate(ada_discrete.staged_predict(X_test)):ada_discrete_err[i] = zero_one_loss(y_pred, y_test)ada_discrete_err_train = np.zeros((n_estimators,))
for i, y_pred in enumerate(ada_discrete.staged_predict(X_train)):ada_discrete_err_train[i] = zero_one_loss(y_pred, y_train)ada_real_err = np.zeros((n_estimators,))
for i, y_pred in enumerate(ada_real.staged_predict(X_test)):ada_real_err[i] = zero_one_loss(y_pred, y_test)ada_real_err_train = np.zeros((n_estimators,))
for i, y_pred in enumerate(ada_real.staged_predict(X_train)):ada_real_err_train[i] = zero_one_loss(y_pred, y_train)ax.plot(np.arange(n_estimators) + 1, ada_discrete_err,label='Discrete AdaBoost Test Error',color='red')
ax.plot(np.arange(n_estimators) + 1, ada_discrete_err_train,label='Discrete AdaBoost Train Error',color='blue')
ax.plot(np.arange(n_estimators) + 1, ada_real_err,label='Real AdaBoost Test Error',color='orange')
ax.plot(np.arange(n_estimators) + 1, ada_real_err_train,label='Real AdaBoost Train Error',color='green')ax.set_ylim((0.0, 0.5))
ax.set_xlabel('n_estimators')
ax.set_ylabel('error rate')leg = ax.legend(loc='upper right', fancybox=True)
leg.get_frame().set_alpha(0.7)plt.show()

参考资料

  • sklearn官方文档:AdaBoostClassifier
  • sklearn官方文档:Multi-class AdaBoosted Decision Trees
  • sklearn官方文档:Discrete versus Real AdaBoost
  • sklearn官方文档:ensemble(集成算法)
  • 《python大战机器学习 数据科学家的一个小目标》华校专,王正林编著

AdaBoost算法特性相关推荐

  1. 数据挖掘十大经典算法之——AdaBoost 算法

    数据挖掘十大经典算法系列,点击链接直接跳转: 数据挖掘简介及十大经典算法(大纲索引) 1. 数据挖掘十大经典算法之--C4.5 算法 2. 数据挖掘十大经典算法之--K-Means 算法 3. 数据挖 ...

  2. 基于Adaboost算法的人脸检测分类器!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:陈锴,Datawhale优秀学习者,中山大学数学系 人脸检测属于计 ...

  3. Adaboost算法原理分析和实例+代码(简明易懂)

    Adaboost算法原理分析和实例+代码(简明易懂) [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333   ...

  4. Adaboost算法原理分析和实例+代码(转载)

    [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时 ...

  5. 基于AdaBoost算法的情感分析研究

    源码下载 http://www.byamd.xyz/hui-zong-1/ 基于AdaBoost算法的情感分析研究 摘 要 随着互联网的快速发展,各类社交媒体平台如微信.QQ等也与日俱增,而微博更是集 ...

  6. 【机器学习】adaboost算法

    [机器学习]adaboost算法 转载自:https://blog.csdn.net/guyuealian/article/details/70995333(算法原理与实例结合讲解很好!) 一.Ada ...

  7. Adaboost算法详解(haar人脸检测)

    转自:https://wizardforcel.gitbooks.io/dm-algo-top10/content/adaboost.html(脸书动不动上不去故转载)(主要看adaboost的例子. ...

  8. 04 集成学习 - Boosting - AdaBoost算法构建

    03 集成学习 - Boosting - AdaBoost算法原理 十.AdaBoost算法构建 上一章最后说明了每个基模型的权值α是如何求得的,于是我就可以对模型进行更新操作了. 构建过程一 1.假 ...

  9. Adaboost 算法的原理与推导

    Adaboost 算法的原理与推导 0 引言 一直想写Adaboost来着,但迟迟未能动笔.其算法思想虽然简单:听取多人意见,最后综合决策,但一般书上对其算法的流程描述实在是过于晦涩.昨日11月1日下 ...

最新文章

  1. 连夜撸了一个简易聊天室
  2. UISlider 滑竿控件
  3. Python:PDB文件中原子和残基重新编号
  4. SparkSQL(Spark-1.4.0)实战系列(一)——DataFrames基础
  5. C# 多线程 线程池(ThreadPool) 2 如何控制线程池?
  6. 年前整理的Css规范
  7. c++17(30)-文件读写(1)
  8. flutter 自定义键盘_掘金 AMA:听闲鱼客户端架构师邬吉风聊 Flutter 和移动端开发那些事...
  9. dubbo之SPI扩展机制注解:@Extension注解的作用
  10. ensp动态路由ospf配置
  11. 【GPU精粹与Shader编程】(六) 《GPU Gems 3》:真实感皮肤渲染技术总结
  12. java poi pdf实例_java通过poi导出excel和pdf
  13. canvas教程14-资源管理器
  14. 神经元网络技术有限公司,神经网络网站
  15. 电子元器件简介——芯片封装篇
  16. 中职学生计算机学情分析报告,中职学生学情分析及对策
  17. MVCC和快照读丶当前读
  18. 信息检索相关任务及数据集介绍
  19. “云”中智控 IT管理新境界
  20. 青少年护眼灯哪个牌子好?盘点教育部推荐的护眼灯品牌

热门文章

  1. XtraReport交叉表自适应行高及最佳列宽(转)
  2. C#--数据类型和类型转换
  3. MySQL查看与修改编码方式(mysql、数据库、表)
  4. 什么是ActiveX插件
  5. Java 泛型背后的原理是什么?
  6. 8 种最坑的 SQL 错误用法,你有没有踩过坑?
  7. Spring Web 应用的最大败笔
  8. Java 运行时的内存划分
  9. Go语言TCP网络编程(详细)
  10. UNIX:缓冲区和重定向