述概:

剪枝:在机器学习的决策树算法中,为防止过拟合现象和过度开销,而采用剪枝的方法,主要有预剪枝和后剪枝两种常见方法。

预剪枝:在决策树生成的过程中,预先估计对结点进行划分能否提升决策树泛化性能。如果能提升,则对此结点进行划分,否则不划分。
优点:
1、使用预剪枝,决策树中很多分支未展开,可以很好的防止过拟合。
2、因为是在构造决策树的过程中进行的,所以时间开销比较小。

缺点:
1、预剪枝是基于贪心的策略。虽然一个结点进行划分不能带来泛化性能的提升,但很可能其后续结点能够带来泛化性能的提升。所以这种贪心策略放弃了一些泛化性能提升的可能性。
2、由于贪心策略,预剪枝决策树欠拟合的风险会比较大。

后剪枝:后剪枝是在决策树构建完成之后,自底向上地对每一个非叶结点进行考察,如果将此结点地子树替换为叶结点能够带来决策树模型泛化性能地提升,那么就将此非叶结点地子树替换为叶结点,否则不替换。
优点:
1、与预剪枝相比,保留了更多的分支,欠拟合风险比较小
2、泛化性能一般情况下也比预剪枝得到的决策树泛化性能好
缺点:
剪枝发生在决策树构建完成之后,而且要自底向上的检查每个非叶结点,时间开销会比较大。

Python实现:

以西瓜书中的”西瓜数据集“为例实现剪枝。

import math
import matplotlib
import numpy as np# # 创建西瓜书数据集2.0
def createDataXG20():data = np.array([['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'], ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑'], ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'], ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑'], ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'], ['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘'], ['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘'], ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑'], ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑'], ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘'], ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑'], ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘'], ['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑'], ['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑'], ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘'], ['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑'], ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑']])label = np.array(['是', '是', '是', '是', '是', '是', '是', '是', '否', '否', '否', '否', '否', '否', '否', '否', '否'])name = np.array(['色泽', '根蒂', '敲声', '纹理', '脐部', '触感'])return data, label, name#划分数据集
def splitXgData20(xgData, xgLabel):xgDataTrain = xgData[[0, 1, 2, 5, 6, 9, 13, 14, 15, 16], :]xgDataTest = xgData[[3, 4, 7, 8, 10, 11, 12], :]xgLabelTrain = xgLabel[[0, 1, 2, 5, 6, 9, 13, 14, 15, 16]]xgLabelTest = xgLabel[[3, 4, 7, 8, 10, 11, 12]]return xgDataTrain, xgLabelTrain, xgDataTest, xgLabelTest# 定义一个常用函数 用来求numpy array中数值等于某值的元素数量
equalNums = lambda x, y: 0 if x is None else x[x == y].size# 定义计算信息熵的函数
def singleEntropy(x):"""计算一个输入序列的信息熵"""# 转换为 numpy 矩阵x = np.asarray(x)# 取所有不同值xValues = set(x)# 计算熵值entropy = 0for xValue in xValues:p = equalNums(x, xValue) / x.sizeentropy -= p * math.log(p, 2)return entropy# 定义计算条件信息熵的函数
def conditionnalEntropy(feature, y):"""计算 某特征feature 条件下y的信息熵"""# 转换为numpyfeature = np.asarray(feature)y = np.asarray(y)# 取特征的不同值featureValues = set(feature)# 计算熵值entropy = 0for feat in featureValues:p = equalNums(feature, feat) / feature.sizeentropy += p * singleEntropy(y[feature == feat])return entropy# 定义信息增益
def infoGain(feature, y):return singleEntropy(y) - conditionnalEntropy(feature, y)# 定义信息增益率
def infoGainRatio(feature, y):return 0 if singleEntropy(feature) == 0 else infoGain(feature, y) / singleEntropy(feature)# 使用西瓜数据测试函数
xgData, xgLabel, xgName = createDataXG20()
print("Ent(D)为:" + str(round(singleEntropy(xgLabel), 4)))
print("Gain(D, 色泽)为:" + str(round(infoGain(xgData[:,0] ,xgLabel), 4)))
print("Gain(D, 根蒂)为:" + str(round(infoGain(xgData[:,1] ,xgLabel), 4)))
print("Gain(D, 敲声)为:" + str(round(infoGain(xgData[:,2] ,xgLabel), 4)))
print("Gain(D, 纹理)为:" + str(round(infoGain(xgData[:,3] ,xgLabel), 4)))
print("Gain(D, 脐部)为:" + str(round(infoGain(xgData[:,4] ,xgLabel), 4)))
print("Gain(D, 触感)为:" + str(round(infoGain(xgData[:,5] ,xgLabel), 4)))

# 特征选取
def bestFeature(data, labels, method='id3'):assert method in ['id3', 'c45']data = np.asarray(data)labels = np.asarray(labels)# 根据输入的method选取 评估特征的方法:id3 -> 信息增益; c45 -> 信息增益率def calcEnt(feature, labels):if method == 'id3':return infoGain(feature, labels)elif method == 'c45':return infoGainRatio(feature, labels)# 特征数量  即 data 的列数量featureNum = data.shape[1]# 计算最佳特征bestEnt = 0bestFeat = -1for feature in range(featureNum):ent = calcEnt(data[:, feature], labels)if ent >= bestEnt:bestEnt = entbestFeat = feature# print("feature " + str(feature + 1) + " ent: " + str(ent)+ "\t bestEnt: " + str(bestEnt))return bestFeat, bestEnt# 根据特征及特征值分割原数据集  删除data中的feature列,并根据feature列中的值分割 data和label
def splitFeatureData(data, labels, feature):"""feature 为特征列的索引"""# 取特征列features = np.asarray(data)[:, feature]# 数据集中删除特征列data = np.delete(np.asarray(data), feature, axis=1)# 标签labels = np.asarray(labels)uniqFeatures = set(features)dataSet = {}labelSet = {}for feat in uniqFeatures:dataSet[feat] = data[features == feat]labelSet[feat] = labels[features == feat]return dataSet, labelSet# 多数投票
def voteLabel(labels):uniqLabels = list(set(labels))labels = np.asarray(labels)finalLabel = 0labelNum = []for label in uniqLabels:# 统计每个标签值得数量labelNum.append(equalNums(labels, label))# 返回数量最大的标签return uniqLabels[labelNum.index(max(labelNum))]# 创建决策树
def createTree(data, labels, names, method='id3'):data = np.asarray(data)labels = np.asarray(labels)names = np.asarray(names)# 如果结果为单一结果if len(set(labels)) == 1:return labels[0]# 如果没有待分类特征elif data.size == 0:return voteLabel(labels)# 其他情况则选取特征bestFeat, bestEnt = bestFeature(data, labels, method=method)# 取特征名称bestFeatName = names[bestFeat]# 从特征名称列表删除已取得特征名称names = np.delete(names, [bestFeat])# 根据选取的特征名称创建树节点decisionTree = {bestFeatName: {}}# 根据最优特征进行分割dataSet, labelSet = splitFeatureData(data, labels, bestFeat)# 对最优特征的每个特征值所分的数据子集进行计算for featValue in dataSet.keys():decisionTree[bestFeatName][featValue] = createTree(dataSet.get(featValue), labelSet.get(featValue), names,method)return decisionTree# 树信息统计 叶子节点数量 和 树深度
def getTreeSize(decisionTree):nodeName = list(decisionTree.keys())[0]nodeValue = decisionTree[nodeName]leafNum = 0treeDepth = 0leafDepth = 0for val in nodeValue.keys():if type(nodeValue[val]) == dict:leafNum += getTreeSize(nodeValue[val])[0]leafDepth = 1 + getTreeSize(nodeValue[val])[1]else:leafNum += 1leafDepth = 1treeDepth = max(treeDepth, leafDepth)return leafNum, treeDepth# 使用模型对其他数据分类
def dtClassify(decisionTree, rowData, names):names = list(names)# 获取特征feature = list(decisionTree.keys())[0]# 决策树对于该特征的值的判断字段featDict = decisionTree[feature]# 获取特征的列feat = names.index(feature)# 获取数据该特征的值featVal = rowData[feat]# 根据特征值查找结果,如果结果是字典说明是子树,调用本函数递归if featVal in featDict.keys():if type(featDict[featVal]) == dict:classLabel = dtClassify(featDict[featVal], rowData, names)else:classLabel = featDict[featVal]return classLabel# 可视化
import matplotlib.pyplot as plt
matplotlib.rc("font", family='Microsoft YaHei')decisionNodeStyle = dict(boxstyle="sawtooth", fc="0.8")
leafNodeStyle = {"boxstyle": "round4", "fc": "0.8"}
arrowArgs = {"arrowstyle": "<-"}# 画节点
def plotNode(nodeText, centerPt, parentPt, nodeStyle):createPlot.ax1.annotate(nodeText, xy=parentPt, xycoords="axes fraction", xytext=centerPt, textcoords="axes fraction", va="center", ha="center", bbox=nodeStyle,arrowprops=arrowArgs)# 添加箭头上的标注文字
def plotMidText(centerPt, parentPt, lineText):xMid = (centerPt[0] + parentPt[0]) / 2.0yMid = (centerPt[1] + parentPt[1]) / 2.0createPlot.ax1.text(xMid, yMid, lineText)# 画树
def plotTree(decisionTree, parentPt, parentValue):# 计算宽与高leafNum, treeDepth = getTreeSize(decisionTree)# 在 1 * 1 的范围内画图,因此分母为 1# 每个叶节点之间的偏移量plotTree.xOff = plotTree.figSize / (plotTree.totalLeaf - 1)# 每一层的高度偏移量plotTree.yOff = plotTree.figSize / plotTree.totalDepth# 节点名称nodeName = list(decisionTree.keys())[0]# 根节点的起止点相同,可避免画线;如果是中间节点,则从当前叶节点的位置开始,#      然后加上本次子树的宽度的一半,则为决策节点的横向位置centerPt = (plotTree.x + (leafNum - 1) * plotTree.xOff / 2.0, plotTree.y)# 画出该决策节点plotNode(nodeName, centerPt, parentPt, decisionNodeStyle)# 标记本节点对应父节点的属性值plotMidText(centerPt, parentPt, parentValue)# 取本节点的属性值treeValue = decisionTree[nodeName]# 下一层各节点的高度plotTree.y = plotTree.y - plotTree.yOff# 绘制下一层for val in treeValue.keys():# 如果属性值对应的是字典,说明是子树,进行递归调用; 否则则为叶子节点if type(treeValue[val]) == dict:plotTree(treeValue[val], centerPt, str(val))else:plotNode(treeValue[val], (plotTree.x, plotTree.y), centerPt, leafNodeStyle)plotMidText((plotTree.x, plotTree.y), centerPt, str(val))# 移到下一个叶子节点plotTree.x = plotTree.x + plotTree.xOff# 递归完成后返回上一层plotTree.y = plotTree.y + plotTree.yOff# 画出决策树
def createPlot(decisionTree):fig = plt.figure(1, facecolor="white")fig.clf()axprops = {"xticks": [], "yticks": []}createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)# 定义画图的图形尺寸plotTree.figSize = 1.5# 初始化树的总大小plotTree.totalLeaf, plotTree.totalDepth = getTreeSize(decisionTree)# 叶子节点的初始位置x 和 根节点的初始层高度yplotTree.x = 0plotTree.y = plotTree.figSizeplotTree(decisionTree, (plotTree.figSize / 2.0, plotTree.y), "")plt.show()# 使用西瓜数据测试函数
xgData, xgLabel, xgName = createDataXG20()
xgTree = createTree(xgData, xgLabel, xgName, method = 'id3')
print(xgTree)
createPlot(xgTree)

初始决策树:

# 创建预剪枝决策树
def createTreePrePruning(dataTrain, labelTrain, dataTest, labelTest, names, method='id3'):trainData = np.asarray(dataTrain)labelTrain = np.asarray(labelTrain)testData = np.asarray(dataTest)labelTest = np.asarray(labelTest)names = np.asarray(names)# 如果结果为单一结果if len(set(labelTrain)) == 1:return labelTrain[0]# 如果没有待分类特征elif trainData.size == 0:return voteLabel(labelTrain)# 其他情况则选取特征bestFeat, bestEnt = bestFeature(dataTrain, labelTrain, method=method)# 取特征名称bestFeatName = names[bestFeat]# 从特征名称列表删除已取得特征名称names = np.delete(names, [bestFeat])# 根据最优特征进行分割dataTrainSet, labelTrainSet = splitFeatureData(dataTrain, labelTrain, bestFeat)# 预剪枝评估# 划分前的分类标签labelTrainLabelPre = voteLabel(labelTrain)labelTrainRatioPre = equalNums(labelTrain, labelTrainLabelPre) / labelTrain.size# 划分后的精度计算if dataTest is not None:dataTestSet, labelTestSet = splitFeatureData(dataTest, labelTest, bestFeat)# 划分前的测试标签正确比例labelTestRatioPre = equalNums(labelTest, labelTrainLabelPre) / labelTest.size# 划分后 每个特征值的分类标签正确的数量labelTrainEqNumPost = 0for val in labelTrainSet.keys():labelTrainEqNumPost += equalNums(labelTestSet.get(val), voteLabel(labelTrainSet.get(val))) + 0.0# 划分后 正确的比例labelTestRatioPost = labelTrainEqNumPost / labelTest.size# 如果没有评估数据 但划分前的精度等于最小值0.5 则继续划分if dataTest is None and labelTrainRatioPre == 0.5:decisionTree = {bestFeatName: {}}for featValue in dataTrainSet.keys():decisionTree[bestFeatName][featValue] = createTreePrePruning(dataTrainSet.get(featValue),labelTrainSet.get(featValue), None, None, names, method)elif dataTest is None:return labelTrainLabelPre# 如果划分后的精度相比划分前的精度下降, 则直接作为叶子节点返回elif labelTestRatioPost < labelTestRatioPre:return labelTrainLabelPreelse:# 根据选取的特征名称创建树节点decisionTree = {bestFeatName: {}}# 对最优特征的每个特征值所分的数据子集进行计算for featValue in dataTrainSet.keys():decisionTree[bestFeatName][featValue] = createTreePrePruning(dataTrainSet.get(featValue),labelTrainSet.get(featValue), dataTestSet.get(featValue),labelTestSet.get(featValue), names, method)return decisionTree# 将西瓜数据分割为测试集和训练集
xgDataTrain, xgLabelTrain, xgDataTest, xgLabelTest = splitXgData20(xgData, xgLabel)
# 生成不剪枝的树
xgTreeTrain = createTree(xgDataTrain, xgLabelTrain, xgName, method = 'id3')
# 生成预剪枝的树
xgTreePrePruning = createTreePrePruning(xgDataTrain, xgLabelTrain, xgDataTest, xgLabelTest, xgName, method = 'id3')
# 画剪枝前的树
print("剪枝前的树")
createPlot(xgTreeTrain)
# 画剪枝后的树
print("剪枝后的树")
createPlot(xgTreePrePruning)

预剪枝前决策树:

预剪枝后决策树:

# 创建决策树 带预划分标签
def createTreeWithLabel(data, labels, names, method='id3'):data = np.asarray(data)labels = np.asarray(labels)names = np.asarray(names)# 如果不划分的标签为votedLabel = voteLabel(labels)# 如果结果为单一结果if len(set(labels)) == 1:return votedLabel# 如果没有待分类特征elif data.size == 0:return votedLabel# 其他情况则选取特征bestFeat, bestEnt = bestFeature(data, labels, method=method)# 取特征名称bestFeatName = names[bestFeat]# 从特征名称列表删除已取得特征名称names = np.delete(names, [bestFeat])# 根据选取的特征名称创建树节点 划分前的标签votedPreDivisionLabel=_vpdldecisionTree = {bestFeatName: {"_vpdl": votedLabel}}# 根据最优特征进行分割dataSet, labelSet = splitFeatureData(data, labels, bestFeat)# 对最优特征的每个特征值所分的数据子集进行计算for featValue in dataSet.keys():decisionTree[bestFeatName][featValue] = createTreeWithLabel(dataSet.get(featValue), labelSet.get(featValue),names, method)return decisionTree# 将带预划分标签的tree转化为常规的tree
# 函数中进行的copy操作
def convertTree(labeledTree):labeledTreeNew = labeledTree.copy()nodeName = list(labeledTree.keys())[0]labeledTreeNew[nodeName] = labeledTree[nodeName].copy()for val in list(labeledTree[nodeName].keys()):if val == "_vpdl":labeledTreeNew[nodeName].pop(val)elif type(labeledTree[nodeName][val]) == dict:labeledTreeNew[nodeName][val] = convertTree(labeledTree[nodeName][val])return labeledTreeNew# 后剪枝 训练完成后决策节点进行替换评估  这里可以直接对xgTreeTrain进行操作
def treePostPruning(labeledTree, dataTest, labelTest, names):newTree = labeledTree.copy()dataTest = np.asarray(dataTest)labelTest = np.asarray(labelTest)names = np.asarray(names)# 取决策节点的名称 即特征的名称featName = list(labeledTree.keys())[0]# print("\n当前节点:" + featName)# 取特征的列featCol = np.argwhere(names == featName)[0][0]names = np.delete(names, [featCol])newTree[featName] = labeledTree[featName].copy()featValueDict = newTree[featName]featPreLabel = featValueDict.pop("_vpdl")# print("当前节点预划分标签:" + featPreLabel)# 是否为子树的标记subTreeFlag = 0# 分割测试数据 如果有数据 则进行测试或递归调用  np的array我不知道怎么判断是否None, 用is None是错的dataFlag = 1 if sum(dataTest.shape) > 0 else 0if dataFlag == 1:# print("当前节点有划分数据!")dataTestSet, labelTestSet = splitFeatureData(dataTest, labelTest, featCol)for featValue in featValueDict.keys():# print("当前节点属性 {0} 的子节点:{1}".format(featValue ,str(featValueDict[featValue])))if dataFlag == 1 and type(featValueDict[featValue]) == dict:subTreeFlag = 1# 如果是子树则递归newTree[featName][featValue] = treePostPruning(featValueDict[featValue], dataTestSet.get(featValue),labelTestSet.get(featValue), names)# 如果递归后为叶子 则后续进行评估if type(featValueDict[featValue]) != dict:subTreeFlag = 0# 如果没有数据  则转换子树if dataFlag == 0 and type(featValueDict[featValue]) == dict:subTreeFlag = 1# print("当前节点无划分数据!直接转换树:"+str(featValueDict[featValue]))newTree[featName][featValue] = convertTree(featValueDict[featValue])# print("转换结果:" + str(convertTree(featValueDict[featValue])))if subTreeFlag == 0:ratioPreDivision = equalNums(labelTest, featPreLabel) / labelTest.sizeequalNum = 0for val in labelTestSet.keys():equalNum += equalNums(labelTestSet[val], featValueDict[val])ratioAfterDivision = equalNum / labelTest.size# 如果划分后的测试数据准确率低于划分前的,则划分无效,进行剪枝,即使节点等于预划分标签# 注意这里取的是小于,如果有需要 也可以取 小于等于if ratioAfterDivision < ratioPreDivision:newTree = featPreLabelreturn newTree# 生成的树的结构
xgTreeBeforePostPruning = {"脐部": {"_vpdl": "是", '凹陷': {'色泽':{"_vpdl": "是", '青绿': '是', '乌黑': '是', '浅白': '否'}}, '稍凹': {'根蒂':{"_vpdl": "是", '稍蜷': {'色泽': {"_vpdl": "是", '青绿': '是', '乌黑': {'纹理': {"_vpdl": "是", '稍糊': '是', '清晰': '否', '模糊': '是'}}, '浅白': '是'}}, '蜷缩': '否', '硬挺': '是'}}, '平坦': '否'}}xgTreePostPruning = treePostPruning(xgTreeBeforePostPruning, xgDataTest, xgLabelTest, xgName)
createPlot(convertTree(xgTreeBeforePostPruning))
createPlot(xgTreePostPruning)

后剪枝前决策树:

后剪枝后决策树:

总结:一棵过拟合的树常常十分复杂,剪枝技术的数显就是为了解决这个问题。两种简直方法分别是预剪枝(在书的构建过程中就进行剪枝)和后剪枝(当属构建完成后再剪枝),预剪枝更有效但需要定义一些参数。

机器学习:决策树的预剪枝和后剪枝相关推荐

  1. 机器学习--决策树二(预剪枝和后剪枝)

    一.什么是决策树的剪枝 对比日常生活中,环卫工人在大街上给生长茂密的树进行枝叶的修剪.在机器学习的决策树算法中,有对应的剪枝算法.将比较复杂的决策树,化简为较为简单的版本,并且不损失算法的性能. 二. ...

  2. 【机器学习入门】(4) 决策树算法理论:算法原理、信息熵、信息增益、预剪枝、后剪枝、算法选择

    各位同学好,今天我向大家介绍一下python机器学习中的决策树算法的基本原理.内容主要有: (1) 概念理解:(2) 信息熵:(3) 信息增益:(4) 算法选择:(5) 预剪枝和后剪枝. python ...

  3. 决策树的预剪枝与后剪枝

    前言: 本次讲解参考的仍是周志华的<机器学习>,采用的是书中的样例,按照我个人的理解对其进行了详细解释,希望大家能看得懂. 1.数据集 其中{1,2,3,6,7,10,14,15,16,1 ...

  4. 机器学习-预剪枝和后剪枝

    一棵完全生长的决策树会面临一个很严重的问题,即过拟合.当模型过拟合进行预测时,在测试集上的效果将会很差.因此我们需要对决策树进行剪枝, 剪掉一些枝叶,提升模型的泛化能力. 决策树的剪枝通常有两种方法, ...

  5. 【机器学习】树模型预剪枝和后剪枝

    在树模型建模的过程中的树模型的超参数会影响模型的精度,那么如何调整超参数呢?可以提前限制模型的超参数,也可以在训练模型之后再调整.本文将介绍树模型的预剪枝和后剪枝的实践过程. 原始模型 使用基础数据集 ...

  6. 决策树_(预剪枝和后剪枝)_以判断西瓜好坏为例

    剪枝的目的: 剪枝的目的是为了避免决策树模型的过拟合.因为决策树算法在学习的过程中为了尽可能的正确的分类训练样本,不停地对结点进行划分,因此这会导致整棵树的分支过多,也就导致了过拟合.决策树的剪枝策略 ...

  7. 决策树剪枝的基本策略有预剪枝和后剪枝,请简述并分析两种剪枝策略

    1.决策树是一类常见的机器学习方法,是基于树结构进行决策的.一般的,一棵决策树包含两类结点:内部节点和叶结点,其中内部节点表示表示一个特征或属性,叶结点表示__决策结果____. 2.在决策树学习中, ...

  8. 决策树剪枝:预剪枝、后剪枝

    一棵完全生长的决策树会面临一个很严重的问题,即过拟合.当模型过拟合进行预测时,在测试集上的效果将会很差.因此我们需要对决策树进行剪枝, 剪掉一些枝叶,提升模型的泛化能力. 决策树的剪枝通常有两种方法, ...

  9. 【ML】决策树--剪枝处理(预剪枝、后剪枝)

    1. 剪枝(pruning)处理 首先,我们先说一下剪枝的目的--防止"过拟合". 在决策树的学习过程中,为了保证正确性,会不断的进行划分,这样可能会导致对于训练样本能够达到一个很 ...

最新文章

  1. zabbix监控客户端(二)
  2. 求你了,别再用 pip 那乌龟的速度去安装库了!
  3. 折半查找一个有序数组中的一个元素,即二分法
  4. JSON 使用 教程
  5. 根据rtk参数在arcgis中进行可视化
  6. 下载完apk安装包后实现自动安装;
  7. Android Multimedia框架总结(二十三)MediaCodec补充及MediaMuxer引入(附案例)
  8. uva 1328(kmp)
  9. Enterprise Manager 无法连接到数据库实例。下面列出了组件的状态。
  10. MySQL之MHA集群的详细教程
  11. 网络分析系列之十三 Wireshark显示过滤器
  12. Python简单监控键盘输入的木马实现
  13. 将两块球形橡皮泥揉在一起,捏成一个正方体。请编程,完成下述功能:从键盘读入2个球形橡皮泥的直径,直径为浮点数;求正方体的边长,并保留两位小数输出;
  14. codeforces:D1. Chopping Carrots (Easy Version)【最大最小值问题 + 控制一边让另一边尽量靠近 + 思维】
  15. 什么是 Google Play服务
  16. 产品经理数据分析入门指南
  17. 入手评测 联想小新Pro 16怎么样?
  18. 微信消息管理之接收事件推送
  19. O2OA (翱途) 平台 V8.0 发布新增数据台账能力
  20. c语言版票务管理系统,求救求救 票务管理系统 好人一生平安

热门文章

  1. vue——数字加逗号分隔
  2. ubuntu kylin mysql_Ubuntu Kylin 安装和配置mysql
  3. MySql delete多表关联删除的使用方法
  4. 二、Java框架之Spring注解开发
  5. NetApp FAS混合式Flash Array
  6. 一系列国内外顶尖互联网公司的技术博客,晋升程序员必备!
  7. 面试题之——乐观锁和悲观锁区别
  8. Mysql的常见面试题 + 索引原理分析
  9. 神经网络中的对抗样本
  10. Redis -- 主从