xgboost是各种比赛中最常使用的方法,网上介绍非常多,但是大部分看起来都比较费劲,这篇文章我将通俗的讲一下xgboost是在干什么,是怎么实现的,每一步的细节中要注意什么问题,达到理解—应用的程度,想了解具体理论的各位看官请移步其他文章。

1.xgboost原理

说起xgboost,我们不得不提一下GBDT,也就是梯度提升决策树,这是一种基于树的集成算法,至于什么方法构成了GBDT的决策树,无非就是ID3、C4.5、C5.0、CART,最常用的就是那个CART,多棵树的集合就构成了GBDT。其实GBDT是对残差的拟合,什么意思呢?假设目标函数是9,第一棵树预测为5,剩下4的误差,那么下一颗树继续拟合4,直至误差满足我们的要求,这和xgboost的思路是一样的。那么问题来了,有了GBDT为啥还要用xgboost呢,有一种说法是,GBDT的每一步优化都依赖于上一步的误差,当大数据量的时候就太慢了,xgboost通过改变目标函数来避免了这个问题。

GBDT的目标函数是预测值和真实值差的累加,也就是误差累加,可以看出每一步计算都依赖于上面所有步的误差,效率比较低。xgboost自然要做出改进,怎么优化呢,一步步分解来看。

形式上,在目标函数后面加一个惩罚项:

xgboost目标函数

目标函数简化,采用高数中的泰勒展开,回忆一下泰勒展开是什么:

泰勒展开模式

好了怎么应用到上面的目标函数中呢,先来确认f(x)是啥,这个f(x)是上面说的那个损失函数l(yi,),也就是我们只泰勒展开这个l(yi,)就行了,那么扎展开的时候我们需要知道这个

是什么,来看损失函数的形式,

是个常量我们上一步求的,可以当f(x)来看,其中x自然是变量

,求导也要对它求。f(xi)是这把我们求的,是导致函数值变化的原因,巧了这个

也表示变化的原因,那么他两是一个东西。

现在能展开了吧,请看下式:

损失函数的泰勒展开

这不还是坑人吗,怎么变得这么简洁的,其实吧gi和hi是下面这样的:

好了前面那个l,我们上一步不是求出来了吗,把它忽略掉吧,损失函数变成这样了:

损失函数的简化形式

到了这一步,目标函数已经和上一步的损失无关了,也就是xgboost摆脱了GBDT的缺点,可以并行计算了,核心做法是做了个泰勒展开,但你以为xgboost就这样了吗,那你就太年轻了,继续来看。

树复杂度表达式展开

怎么还有个Ω没给我解释呢,别急啊,来了,这个Ω是表示树的复杂度的,你想啊树的复杂度能怎么表示,首先你得考虑叶子节点个数吧,然后xgboost人家考虑的更多一些,还把叶子节点的得分给考虑进去了,并且为了防止叶子节点太多影响你计算,给你加了个L2正则化,啥不懂L2正则化,自己去百度吧。同时为了平衡这两个指标,人家还给加了两个权重,是不是很贴心。

树的复杂度的表示方法

等一下啊,道理我都明白,但是你能不能告诉我叶子节点得分是怎么算的。这个吧,其实对于单颗决策树是很好理解的,如果是分类问题那么这个数就是0-1之间的一个数,代表的是样本分到这个节点上的得分值,如果是回归问题,那么这个值就是样本的平均值。但是对于xgboost,我们都把决策树的目标给改了,这个东西你不得算出来啊,计算方法在后边说,就是一个最优目标函数对应一个最优得分值。

目标函数的整合,目标函数的两个部分都知道咋回事了吧,把它放到一起吧,这样的话我们才能看怎么去优化,合并以后的公式是这样子的:

整合以后的目标函数形式

这个w好像能合并到一起啊,合到一起试试。

进一步整合目标函数

看上去头晕眼花的,什么东西啊,能不能再简单点,当然能。先这样:

然后再这样:

目标函数的最终形式

目标函数的优化,都到这一步了可以优化了吧,这里边变量就剩叶子节点的得分了,我们来求导,得到下面这个东西:

目标函数的优化

等一下啊,这个w不就是前面说的叶子节点得分值,原来是这么算的,求这个其实就是为了求目标函数值。好了有了目标函数值,接下来干嘛。回头想想我们的目标,我们现在知道要拟合的残差,我们有特征,接下来我们要找一颗最优的树进行样本划分啊,咋找,决策树找最优划分点不是算增益最大吗,那么我们拿着这个目标函数去找最大的增益不就是现在这棵树的目标了吗。好了怎么算呢,看下面式子:

树结构划分标准

其实划分算法太多了,有很多是为了提高效率的,这个就交给包内部去解决吧,我们知道他是要划分树了就好了。

如此循环往复,一个xgboost过程就完成了,其实大概就是拿到值先找到一颗差不多的树,一看不行啊还有误差啊,拿着这个误差再去找一棵树继续拟合,等到拟合的差不多了,这些个树就集成到一起进行划分。那么xgboost是怎么预测的,其实一句话就可以理解,就是每棵树叶子节点得分的加和,想想你的指标在每棵树上都有满足条件的划分,如果划分到那一类就把叶子节点的得分加起来。其实xgboost还有缩减和列取样的问题,意思是防止过拟合,就是说每一步叶子节点的权重都要乘上一个系数,这样的话使每棵树叶子节点权重对结果影响不会太大,剩下更多的空间交给模型去拟合,还有一个列取样其实是为了计算简便,每次计算时从特征空间中选出几个来构建树。

2.python导入相关包

python简直太友好了,可以直接调用xgboost包跑程序,我们要做的就是提取指标和调参,提取指标这个事我教不了你,得根据业务来,调参倒是有套路可寻。首先你要实现一个xgboost,你要知道你用什么工具去实现,python里有两个包,一个就叫xgboost,另外一个是xgboost的sklearn接口,叫XGBClassifer。另外要调参还有一个并行的网格搜索包,sklearn里的GridSearchCV。其他还有一些包需要引入就是打打辅助。

import pandas as pd

import numpy as np

import xgboost as xgb

from xgboost.sklearn import XGBClassifier

from sklearn import cross_validation, metrics #交叉验证和效果评估,其他模型也很常用。

from sklearn.grid_search import GridSearchCV #并行搜索,加快速度。

3.xgboost调参

准备工作已经做好了,接下来开始调参工作了,调参之前大家记得要做两件件事,就是先把数据整理好,把模型搭建好。

3.1 搭建模型

简单的很,已经引入了XGBClassifier,直接把相关默认参数设置好就可以了。

clf1 = XGBClassifier(learning_rate =0.1,

n_estimators=1000,

max_depth=5,

min_child_weight=1,

gamma=0,

subsample=0.8,

colsample_bytree=0.8,

objective= 'binary:logistic',

nthread=4,

scale_pos_weight=1,

seed=27)

3.2 参数解释

我们看到在建立xgboost的模型时,有很多参数,这些参数是什么意思呢,我们来看一下。

一般参数

这些参数用来控制XGBoost的整体功能,是一些通用的设置,有的时候都不用调整。

(1)booster[默认gbtree]

每次迭代的模型选择,有两个gbtree:基于树的模型和gbliner:线性模型,显然我们一般都会选择gbtree。

(2)silent[默认0]

是否开启静默模式,0为不开启,1为开启,开启后不输出任何信息,显然这不利于我们调参,默认选0就好了。

(3)nthread[默认取最大线程数]

这个参数用来控制最大并行的线程数,如果你希望取得所有CPU的核,那么你就不用管它。

booster参数或者说树的参数

这些参数是要重点调整的,比较重要,主要是用来控制每一步树的生成。

(1)eta [default=0.3]

学习率参数,就是原理中说的缩减,保证每一颗树对于结果的影响不太大,从而保证模型的效果。更新叶子节点权重时,乘以该系数,避免步长过大。参数值越大,越可能无法收敛。把学习率 eta 设置的小一些,小学习率可以使得后面的学习更加仔细。 典型值为0.01-0.2。

(2)min_child_weight [default=1]

大家对他的解释是决定最小叶子节点样本权重和,不太好理解。看了一些解释的文章,这个值可以理解为H值,还记得H值吗,就是损失函数对y(t-1)的二阶导数和,那么如果损失函数是平方函数(回归问题),这个就是1,如果是对数损失函数(分类问题),导数是a(1-a)的形式,a代表sigmoid函数,这样的话当y预测值非常大的时候,这个式子的值接近于0,这当然是不好的,因此你要给他设定一个阈值,小于这个阈值就不分裂了。现在可以解释了,这个值代表所有样本二阶导数的和,和上边说的叶子得分不是一个事,如果是回归问题实际代表样本个数,如果是分类问题实际代表a(1-a)所有样本计算值的加和。

明白这个参数是啥以后,来看他是干嘛的,这个参数用于避免过拟合,当它的值较大时,可以避免模型学习到局部的特殊样本。举个栗子来说,对正负样本不均衡时的 0-1 分类而言,假设 h 在 0.01 附近,min_child_weight 为 1 意味着叶子节点中最少需要包含 100 个样本,实际是通过控制样本数来控制过拟合的。你们应该看出来这个值越小越容易过拟合,需要通过cv进行调整优化。

(3)max_depth [default=6]

这个没啥好说的,每棵树的最大深度,也是用来避免过拟合的,max_depth越大,模型会学到更具体更局部的样本,典型值3-10,要用cv调优。

(4)max_leaf_nodes

树上最大节点的数量,和上面的那个参数一样,如果定义了这个参数就会忽略掉max_depth参数,我们调优还是以max_depth为主吧。

(5)gamma[default=0]

一听这种希腊字母就知道是个系数,在树的叶子节点上作进一步分区所需的最小损失减少。越大,算法越保守。取值在[0,∞] 。通俗点讲就是,这个节点还划不划分,先看看损失减不减少了再说。同样需要cv调优。

(6)max_delta_step [default=0]

这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。通常,这个参数不需要设置。但是当各类别的样本十分不平衡时,它对逻辑回归是很有帮助的。也就是说这个参数不用管啊。

(7)subsample [default=1]

样本采样用的,减小这个参数的值,算法会更加保守,避免过拟合,但是如果这个值设置得过小,它可能会导致欠拟合。典型值:0.5-1。既然有个范围,给他个面子cv调优一把吧。

(8)colsample_bytree [default=1]

列采样,就是选择生成树的特征,前面介绍过了,和设置缩减率一样是为了干嘛来着,是为了防止过拟合的,一般设置为: 0.5-1 ,也要用cv拟合。

(9)colsample_bylevel[default=1]

等一下哈,这个怎么和上面参数这么像,哦,它是在上面树的基础上,对每一级进行分裂时对列(就是特征)进行采样,大神们都说这个参数不用用了,用上面那个就行了。

(10)lambda [default=1]

又是个系数,这个是控制L2正则的,就是目标函数里的那个叶子节点得分前边的系数,用不用看你自己了。

(11)alpha [default=0]

想必你也想到了吧,有L2就有L1,用不用全凭自己了。

(12) scale_pos_weight [default=1]

这个是控制样本均衡与否的,如果是不均衡样本,设置一个正数可以保证快速收敛,具体为什么,也没人解释,先留着吧。

(13)tree_method[default=’auto’]

还记得我说过树的生成有很多方法吧,他们介绍的老复杂了,别看了,人家自动给我们打包好了,有三个可选的值, {‘auto’, ‘exact’, ‘approx’} ,分别对应 贪心算法(小数据集)/近似算法(大数据集) 。

大概就这么多吧,如果看到了别的,我再补充。

学习目标参数

这个是最后一类参数了,跟目标函数有关。

(1)objective [ default=reg:linear ]

这是返回目标函数值,这个东西包含的函数还挺多,默认是线形的。此外你还可以选择:binary:logistic 二分类的逻辑回归,返回预测的概率(不是类别)。multi:softmax 使用softmax的多分类器,返回预测的类别(不是概率)。在这种情况下,你还需要多设一个参数:num_class(类别数目)。multi:softprob 和multi:softmax参数一样,但是返回的是每个数据属于各个类别的概率。

(2)eval_metric[默认值取决于objective参数的取值]

也就是说怎么计算目标函数值,根据你目标函数的形式来,对于回归问题,默认值是rmse,对于分类问题,默认值是error。比较典型的有(我直接截图了懒得打字):

损失函数计算方法

你应该知道吧目标函数值和实际值之间的差距,就是这个参数要计算的重点。

(3)seed(default=0)

这个叫随机数种子,还记得random包里那个seed吗,这个参数就是为了可以使结果复现。

命令行参数

n_estimators 这个参数叫迭代次数,也就是说生成树的个数。

更多参数

更多参数请移步官方文档:xgboost官方文档

知道了这些参数,想要弄明白调参是干啥,调整什么就很容易了,下面会结合例子来说明。

3.3 调参方法

先来推荐一个大哥的博客,这个链接里https://blog.csdn.net/u014465639/article/details/74351982写了好几种模型的调参方法,想要了解的不妨去看看。

开始之前,给大家介绍一个新朋友,这个东西可以很好的帮助我们进行调参,它是sklearn里的一个包,[sklearn.model_selection.GridSearchCV],我们调参就是基于这个包的。那么这个包怎么实现调参呢,来看一眼它的常用参数。

(1)estimator:优化器,也就是你建立的模型,这里自然就是xgboost模型,如果要对其他集成算法调优,那就写其他模型了,注意模型需要初始化哦。

(2)param_grid:字典或者列表,一般用字典,请在这里输入你要优化的参数值。

(3)scoring :用啥子估计误差,如果不设置,那我没办法了,就用estimator的误差来衡量吧。

有了上面的方法,我们还会怕调参数吗,当然不会了,先设置好常用的参数,然后再依次调参。请注意,调参是有顺序的,按照下面这个来。

1.n_estimators

叫迭代次数,也就是生成树的个数。

cv_params = {'n_estimators': [400, 500, 600, 700, 800]}

other_params = {'learning_rate': 0.1, 'n_estimators': 500, 'max_depth': 5, 'min_child_weight': 1, 'seed': 0,

'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}

咦,这里边有n_estimators的值了,其实就是以他为基准进行挑选啊,首先给个基础值进去,给谁啊,当然是建立的初始模型了。

model = xgb.XGBRegressor(**other_params)

然后跑一下模型,这个我最后统一说,反正最后给出一个最优值,但是我们设置的粒度太粗了,不能直接用,接下来细调,同样方法跑一遍。

cv_params = {'n_estimators': [550, 575, 600, 650, 675]}

2.min_child_weight和max_depth

这两个参数是控制树生成的,树的结构对于最终的结果影响还是很大的,所以这个放到第二个调整批次是应当的,两个参数可以一起调。

cv_params = {'max_depth': [3, 4, 5, 6, 7, 8, 9, 10], 'min_child_weight': [1, 2, 3, 4, 5, 6]}

other_params = {'learning_rate': 0.1, 'n_estimators': 550, 'max_depth': 5, 'min_child_weight': 1,

'seed': 0,'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}

3.gamma

控制节点分裂标准的。

cv_params = {'gamma': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]}

4.subsample和colsample_bytree

采样的放一起,都是比例。

cv_params = {'subsample': [0.6, 0.7, 0.8, 0.9], 'colsample_bytree': [0.6, 0.7, 0.8, 0.9]}

reg_alpha和reg_lambda

正则化的指标,这里有一点需要注意你看这个写法和上面原理好像不一样啊,其实就是直接XGB包和XGB包的sklearn接口的区别,一般都调用sklearn接口,所以就写成符合sklearn习惯的样子了。

cv_params = {'reg_alpha': [0.05, 0.1, 1, 2, 3], 'reg_lambda': [0.05, 0.1, 1, 2, 3]}

6.learning_rate

学习率,每一叶子节点得分需要乘上这个数,一般比较小,从小的数字调起。

cv_params = {'learning_rate': [0.01, 0.05, 0.07, 0.1, 0.2]}

基本调参就告一段落了,这里需要特别指出一点就是调参可以提高模型性能,但是更重要的还是特征选择,数据清洗,特征融合等工作,大家注意把基础工作做好。

4.完整代码

基础数据啥的我就不列了啊,大概说一下概要吧,和网上的不一样,我也是按照自己的想法做了一些省略。

#1.建立一个初步的模型,看一下效果怎么样。

xgb1 = XGBClassifier(

learning_rate =0.1,

n_estimators=1000,

max_depth=5,

min_child_weight=1,

gamma=0,

subsample=0.8,

colsample_bytree=0.8,

objective= 'binary:logistic',

nthread=4,

scale_pos_weight=1,

seed=27)#经验值

xgb_param = xgb1.get_xgb_params()#得到模型的参数

xgtrain = xgb.DMatrix(dtrain[predictors].values, label=dtrain[target].values)#转换成原生xgboost需要的数据格式。

cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=alg.get_params()['n_estimators'], nfold=cv_folds,

metrics='auc', early_stopping_rounds=early_stopping_rounds, show_progress=False)#注意啊这是原生的模型自带的,你只需传参,cv_folds=5,表示5%的数据用于交叉验证。这个cvresults返回训练集和测试集的误差,行数就是最大迭代的次数。

xgb1.set_params(n_estimators=cvresult.shape[0])

xgb1.fit(dtrain[predictors], dtrain['Disbursed'],eval_metric='auc')

dtrain_predictions = alg.predict(dtrain[predictors])#算准确率用的

dtrain_predprob = alg.predict_proba(dtrain[predictors])[:,1]#算auc用的

feat_imp = pd.Series(alg.booster().get_fscore()).sort_values(ascending=False)#算重要度的指标

#‘weight’ - the number of times a feature is used to split the data across all trees.‘gain’ - the average gain of the feature when it is used in trees.‘cover’ - the average coverage of the feature when it is used in trees.

#weight - 该特征在所有树中被用作分割样本的特征的次数。gain - 在所有树中的平均增益。cover - 在树中使用该特征时的平均覆盖范围。

#

#2开始按步骤调参用的XGBclassifer。

#第一步调优

params_test1 = {'n_estimators': [400, 500, 600, 700, 800]}

other_params = {'learning_rate': 0.1, 'n_estimators': 500, 'max_depth': 5, 'min_child_weight': 1, 'seed': 27,

'subsample': 0.8, 'colsample_bytree': 0.8, 'gamma': 0, 'reg_alpha': 0, 'reg_lambda': 1}

model = XGBClassfoer(**other_params)

optimized_XGB 1= GridSearchCV(estimator=model, param_grid=cv_params, scoring='r2', cv=5, verbose=1, n_jobs=4)

optimized_XGB.fit(X_train, y_train)

evalute_result = optimized_GBM.grid_scores_

##第二步调优

param_test2 = { 'max_depth':range(3,10,2), 'min_child_weight':range(1,6,2)}

optimized_XGB2= GridSearchCV(estimator = XGBClassifier( learning_rate =0.1, n_estimators=140, max_depth=5,

min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,

objective= 'binary:logistic', nthread=4, scale_pos_weight=1, seed=27), param_grid = param_test2, scoring='roc_auc',n_jobs=4,iid=False, cv=5)

optimized_XGB2.fit(train[predictors],train[target])

optimized_XGB2.grid_scores_, optimized_XGB2.best_params_, optimized_XGB2.best_score_

#依次类推,得到最后的最优参数集合,再建立模型用于预测

#3.最终模型

model = XGBClassifer(learning_rate=0.1, n_estimators=550, max_depth=4, min_child_weight=5, seed=27,

subsample=0.7, colsample_bytree=0.7, gamma=0.1, reg_alpha=1, reg_lambda=1)

model.fit(X_train, y_train)

ans = model.predict(X_test)

  以上就是本篇的所有内容,很多东西就是讲思路,让大家都知道怎么回事,准确性可能差点,如果你想有更深的理解,还是结合其他人的文章看看。

python调参工作都是干啥的_xgboost原理及调参方法-通俗易懂版本相关推荐

  1. python调参工作都是干啥的_Python中Gradient Boosting Machine(GBM)调参方法详解

    1.前言 如果一直以来你只把GBM当作黑匣子,只知调用却不明就里,是时候来打开这个黑匣子一探究竟了! 这篇文章是受Owen Zhang (DataRobot的首席产品官,在Kaggle比赛中位列第三) ...

  2. python调参工作都是干啥的_知乎 | 计算机视觉工程师一天都大致在做些什么?

    点击上方"机器学习与生成对抗网络",关注"星标" 获取有趣.好玩的前沿干货! from知乎,3d视觉工坊编辑:著作权归作者,侵删 观点一 作者|张旭 https ...

  3. python在财务上的应用-财会人必看:这个工具,30分钟可以把人家一天的工作都给干完!...

    原标题:财会人必看:这个工具,30分钟可以把人家一天的工作都给干完! 每年3月到6月,工商年报.汇算清缴交织在一起,财务总是被安排得明明白白的.尤其今年还有首次个人所得税汇算清缴! 作为一个财务,除了 ...

  4. 有没有可以刷python题的软件_这个工具,30分钟可以把科研人一天的工作都给干完!...

    原标题:这个工具,30分钟可以把科研人一天的工作都给干完! 一入科研深似海,每逢返校倍忧桑. 被 paper 和发际线上移支配的恐惧要回来了--一个假发片还够用吗? 1 文献看到眼花,科研热点总是无缘 ...

  5. 每天30分钟学python-这个工具,30分钟可以把科研人一天的工作都给干完!

    原标题:这个工具,30分钟可以把科研人一天的工作都给干完! 一入科研深似海,每逢返校倍忧桑. 被 paper 和发际线上移支配的恐惧要回来了--一个假发片还够用吗? 1 文献看到眼花,科研热点总是无缘 ...

  6. 会python的人工作都不会太差什么梗_再不学Python 你就被同龄人甩开了吗?

    原创: 潘懿锟 唐佩瑶 清华大学(分数线,专业设置)清新时报 记者 | 潘懿锟 唐佩瑶 "会Python的人,工作都不会太差.追上同龄人,就趁现在!" 或许你已经对微信的广告推送感 ...

  7. 会python的人工作都不会太差什么梗_老板:你很努力,但我还是想提拔会Python的新人!...

    原标题:老板:你很努力,但我还是想提拔会Python的新人! 你尝试过那种满怀希望,然后希望完全落空的感觉吗? 01 越努力越幸运是伪命题吗 闺蜜给我发消息说: "不是说越努力越幸运吗?为啥 ...

  8. 生物科研神器!30分钟把人家一天的工作都给干完了!

    连着被放了两个月鸽子,我今天总算是约到了最近"肝"论文到头秃的闺蜜小北. 前阵子,小北的硕士论文进入了瓶颈期,每天在电脑前从早坐到晚,一点儿成果也没有,头发倒是掉了不少.  在网上 ...

  9. 搞生物的速看!有了它,30分钟可以把一天的工作都给干完!

    一入科研深似海,每逢开题倍忧桑. 被 paper 和发际线上移支配的恐惧要回来了--一个假发片还够用吗? 文献看到眼花,科研热点总是无缘 加了几十个实验组微信群. QQ 群,想追踪前沿文献,了解跟自己 ...

最新文章

  1. 第十、十一周项目-阅读程序,写出这些程序的运行结果(2)
  2. Windows2008应用之配置客户端自动添加打印机
  3. 一文说通C#中的异步迭代器
  4. web获取多行mysql结果_mysql中的多行查询结果合并成一个
  5. 10-10-020-简介-kafka的ZK上面的存储
  6. [纪事]再见,CodeArtist
  7. 隐马尔科夫模型(HMM)详解
  8. 关于更新win10 1903后VM ware无法启动的解决方法
  9. 什么是云计算,云计算的基本原理是什么?
  10. python百万邮件群发软件_用python来群发邮件的程序代码
  11. surface android模拟,Surface Duo将支持Android小部件 模拟磁铁体验
  12. LeetCode:121(Python)—— 买卖股票的最佳时机(简单)
  13. 微信app清空群聊天消息的方法
  14. 毕业论文ppt的研究方法及过程计算机专业,本科毕业论文的开题报告ppt
  15. 迅捷CAD工具箱,字母阵列功能
  16. matlab求解方程和多元函数方程组
  17. Solidworks使用技巧:文件重命名:在装配体中重命名零部件 在文件夹中重命名文件
  18. 史上最全的 Spring 面试题和答案
  19. 有源电力滤波器matlab仿真实验报告,MATLAB有源电力滤波器系统的设计与仿真
  20. Bugly Android热更新总结篇

热门文章

  1. 解决多进程模式下引起的“惊群”效应
  2. 让业务感知不到服务器的存在——基于弹性计算的无服务器化实践
  3. SecureCRT如何进入和退出全屏及调出菜单栏
  4. 迁移上云方法论-6R
  5. x86服务器中网络性能分析与调优(高并发、大流量网卡调优)
  6. QT隐式调用VC开发的DLL
  7. 简单说一下kafka 与其他消息队列
  8. Hive _偏门常用查询函数(二)附带实例(列转行、窗口函数)
  9. zookeeper 都有哪些使用场景?
  10. springMVC——SpringMVC原理详细解析