《机器学习实战》——决策树

2023-11-16

本章介绍的决策树算法为ID3算法(Iterative Dichotomiser 3,迭代二叉树3代),主要流程为:根据信息增益找到划分数据的最佳特征——判断划分后每个数据子集是否为同一分类——若是,返回分类结果;若不是,再次划分数据子集(递归)。同时,本章利用Matplotlib的注解功能,将决策树可视化;利用pickle存储和读取决策树结构。

一、构造决策树

tree.py

1.计算信息熵

# 构造一个简单的“鱼鉴定”数据集
def createDataSet():
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']
    return dataSet, labels  # 2个特征(标签)

# 测试结果  
>>> import tree
>>> myDat,label=tree.createDataSet()
>>> myDat
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
# 计算给定数据集的香农熵
# first step:创建字典labelCounts={标签:标签出现次数}
# second step:根据公式求香农熵
def calcShannonEnt(dataSet):
    numEntries = len(dataSet)   # dataSet的个数
    labelCounts = {}    # 创建一个{标签:标签出现次数}的字典
    for featVec in dataSet:
        currentLabel = featVec[-1]  # dataSet最后一列,即标签
        if currentLabel not in list(labelCounts.keys()):    # Python 3.x中,dict.keys()返回值不是list
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1  # 统计每个标签出现次数
    shannonEnt = 0.0
    for key in labelCounts:     # 计算香农熵
        prob = float(labelCounts[key])/numEntries  # 每个类别标签出现的概率
        shannonEnt -= prob * log(prob, 2)   # 以2为底求对数
    return shannonEnt

# 测试结果
>>> tree.calcShannonEnt(myDat)
0.9709505944546686
# 修改数据集内容
>>> myDat[0][-1]='maybe'
>>> myDat
[[1, 1, 'maybe'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>> tree.calcShannonEnt(myDat)
1.3709505944546687

信息(information)

如果待分类的事务可能划分在多个分类之中,则符号 x i x_i xi的信息定义为: l ( x i ) = − l o g 2 p ( x i ) l(x_i)=-log_2p(x_i) l(xi)=log2p(xi)其中, p ( x i ) p(x_i) p(xi)为选择改分类的概率。可见某事务概率越高,其所包含的信息越少。

熵(entropy)

信息的期望值定义为熵,即所有类别的所有可能值所包含的信息的期望:
H = − ∑ l = 1 n p ( x i ) l o g 2 p ( x i ) H=-\sum_{l=1}^{n} p(x_i)log_2p(x_i) H=l=1np(xi)log2p(xi)其中, n n n是分类的数目。

信息增益(information gain)

通俗理解,信息增益即某项特征能为分类系统,增加多少信息。信息增益越大,该特征越‘重要’。

dict.keys()

dict.keys()

返回一个字典dict的所有键。
Python 3.x中,如果直接使用dict.keys(),那么返回值为dict_keys,并非直接的列表,若要返回列表值还需调用list函数。

>>> dict = {'Name': 'Zara', 'Age': 7}
>>> dict.keys()
dict_keys(['Name', 'Age'])
>>> list(dict.keys())
['Name', 'Age']

‘/’ 和 ‘//’ 的区别

实验环境:python 3.7
/ :float除法。无论除数、被除数是类型,结果都为float,且为精确结果。
//:整除。又称地板除,即舍弃小数部分向下取整(注意负数),除数、被除数任一为float,结果即为float。

>>> 3/2
1.5
>>> 3//2
1
>>> 3/2.0
1.5
>>> 3//2.0
1.0
>>> -3//2		# 向下取整
-2

2.划分数据集

# 按照给定特征划分数据集
# first step:创建新的list
# second step:判断满足条件的示例,抽取除划分特征外剩余的list内容
# third step:将抽取的list append到retDataSet中,形成新的list   
def splitDataSet(dataSet, axis, value): # 给定(划分数据集,划分特征所在列,划分特征值)
    retDataSet = [] # 划分后的新数据集
    for featVec in dataSet:
        if featVec[axis] == value:  # 划分特征值等于设定值
            reducedFeatVec = featVec[:axis] # 截取划分特征所在列前面的特征
            reducedFeatVec.extend(featVec[axis+1:]) # 添加划分特征所在列后面的特征(extend函数会将所有满足条件的特征列作为新的元素加入列表中)
            retDataSet.append(reducedFeatVec)   # 将重新‘组合’的列表整个加入retDataSet中
    return retDataSet

此代码段中用到extend()函数和append()函数两个扩展函数,二者有所区别,参考

# 测试结果
>>> myDat,label=tree.createDataSet()
>>> myDat
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>> tree.splitDataSet(myDat,0,1)	#按myDat数据集中,第0个特征值为1划分
[[1, 'yes'], [1, 'yes'], [0, 'no']]	#此三示例第0个特征值为1
>>> tree.splitDataSet(myDat,0,0)
[[1, 'no'], [1, 'no']]

set()

parame = {value01,value02,...}	
set(value)
# 当创建一个空集合时,只能用第二种方式,用第一种{ }创建的是一个空字典

集合(set)是一个无序的不重复元素序列。

# 1.去重功能
>>>basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # 这里演示的是去重功能
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # 快速判断元素是否在集合内
True
>>> 'crabgrass' in basket
False

# 2.两个set间的操作
>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # 集合a中包含而集合b中不包含的元素
{'r', 'd', 'b'}
>>> a | b                              # 集合a或b中包含的所有元素(或)
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # 集合a和b中都包含了的元素(与)
{'a', 'c'}
>>> a ^ b                              # 不同时包含于a和b的元素(异或)
{'r', 'd', 'b', 'm', 'z', 'l'}
# 选择最好的数据集划分方式,根据最大信息增益的原则
# first step:创建分类特征列表uniqueVals
# second step:计算每种划分方式的信息熵
# third step:计算最好的信息增益,返回对应的划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1   # 待划分数据集最后一列为类别,其余列为特征feature
    baseEntropy = calcShannonEnt(dataSet)   # 计算未划分数据集时的香农熵
    bestInfoGain = 0.0
    bestFeature = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]  # dataSet里每一个example的第i个特征的值
        # ⬆这一句展开来如下:
        # for example in dataSet:
        #     featList = []
        #     featList.extend([example[i]]) 
        # # featList.extend(example[i]) # 注意这么写是不对的,这么写featList无法被set调用
        uniqueVals = set(featList)  # set()可以去重,保证后面不会重复划分dataSet
        newEntropy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)     # 按照某个特征划分数据后的熵
        infoGain = baseEntropy - newEntropy # 计算信息增益
        if(infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

# 测试结果
>>> myDat
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>> tree.chooseBestFeatureToSplit(myDat)
0	#即按照第0个特征划分

3.递归构建决策树

构建决策树的流程大致为:得到原始数据集——基于最好的特征属性值划分数据集。由于特征值可能多于两个,所以存在多次划分,即需要递归处理。
递归结束的条件有二:一是程序遍历完所有划分数据集的特征属性,二是每个分支下的所有示例都具有相同的分类(我理解的是两个条件同时满足,递归才终止)。但有时数据集已经处理了所有特征属性,类标签仍不唯一,此时就需要决定如何定义该叶子节点。如下采用多数表决的方法。

# 创建树函数
# fist:特征类别完全相同停止继续划分,返回特征类别
# second:遍历完所有特征,返回出现次数最多的特征类别
# third:创建字典树,存储当前最好特征属性值
def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]    # classList表示类别标签
    if classList.count(classList[0]) == len(classList): # 若所有类别标签相同(classList中第0个元素的个数==classList的长度)
        return classList[0]                             # 则不用分类,直接返回类别。递归停止。
    if len(dataSet[0]) == 1:    # 若使用完了所有特征,仍不能将数据集划分为仅含一类的分组
        return majorityCnt(classList)   # 则调用majorityCnt函数投票。递归停止
    bestFeat = chooseBestFeatureToSplit(dataSet)    # 根据最大信息增益的原理选择最佳划分特征(特征索引,如第0个特征、第1个特征等)
    bestFeatLabel = labels[bestFeat]    # 最佳划分特征的标签
    myTree = {bestFeatLabel:{}}     # 构造字典树
    subLabels = labels[:]   # 复制labels给subLabels,防止破坏原始labels
    									# 这里的赋值源程序放在下面的循环里,没卵用啊...labels还是会变啊...所以放到了循环外
    del(subLabels[bestFeat])   # 去除当前最佳特征的标签
    featValues = [example[bestFeat] for example in dataSet] # 当前最佳特征对应的取值
    uniqueVals = set(featValues)
    for value in uniqueVals:
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
                                    # 递归调用。先要调用splitDataSet函数,获得subDataSet。
    return myTree

# 测试结果
>>> myDat,labels=tree.createDataSet()
>>> myTree=tree.createTree(myDat,labels)
>>> myTree
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

python中,函数参数为列表类型

createTree(dataSet, labels)函数中包含dataSet和labels两个参数,均为列表类型,且代码中重复调用labels参数,需要‘去除当前最佳特征的标签’,会改变原始labels的值。所以先将labels复制:subLabels = labels[:],再去除:del(subLabels[bestFeat])

list.count()

list.count(obj)

返回列表list中某个元素obj出现的次数。

>>> aList = [123, 'xyz', 'zara', 'abc', 123]
>>> aList.count(123)
2
>>> aList.count('zara')
1

二、绘制决策树(Matplotlib)

treePlotter.py

1.Matplotlib注解

import matplotlib.pyplot as plt
#解决中文显示问题
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

# 定义决策节点、叶节点以及标记线
decisionNode = dict(boxstyle="sawtooth", fc="0.8")  # 决策节点
leafNode = dict(boxstyle="round4", fc='0.8')    # 叶节点
arrow_args = dict(arrowstyle="<-")  # 标记线(起点为箭头尖端)
# arrow_args = dict(arrowstyle="->") # 标记线(起点为箭头线段端)——默认

dict()

class dict(**kwarg)			# 传入关键字
class dict(mapping, **kwarg)		# 利用某种mapping(元素容器)构造字典
class dict(iterable, **kwarg)		# 利用可迭代对象构造字典

用于创建一个字典。

>>>dict()                        # 创建空字典
{}
>>> dict(a='a', b='b', t='t')     # 传入关键字
{'a': 'a', 'b': 'b', 't': 't'}
>>> dict(zip(['one', 'two', 'three'], [1, 2, 3]))   # 映射函数方式来构造字典
{'three': 3, 'two': 2, 'one': 1} 
>>> dict([('one', 1), ('two', 2), ('three', 3)])    # 可迭代对象方式来构造字典
{'three': 3, 'two': 2, 'one': 1}
# 绘制节点,给定(节点文本内容,节点框中心坐标(标记线起点坐标),标记线终点坐标,绘制类型)
def plotNode(nodeTxt, centerPt, parentPt, nodeType):
# 个人理解:createPlot.ax1相当于一个全局的变量,在createPlot()函数中创建,在plotNode()函数中调用
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
                            xytext=centerPt, textcoords='axes fraction',
                            va="center", ha="center", bbox=nodeType, arrowprops=arrow_args)
    # node_txt: 节点文本内容
    # xy: 标记线终点坐标(此例中标记线为箭头,终点为箭头线段端)
    # xycoords:标记线的坐标原点位置,是以图像还是坐标轴
    # xytext: 节点框的中心坐标
    # textcoords:节点框的坐标原点位置,是以图像还是坐标轴
    # va: vertical alignment 文本中的内容 横向对齐方式
    # ha: horizontal alignment 文本中内容竖向对齐方式
    # bbox: 节点框的设置 
    # arrowprops: 标记线的类型,是一个字典,arrowstyle未指定,则默认类别为'->'

createPlot.ax1.annotate():

参考:1&2.

# 绘制
def createPlot():
    fig = plt.figure(1, facecolor='white') 
    fig.clf() 
    createPlot.ax1 = plt.subplot(111, frameon=False)    
    plotNode("决策节点", (0.5,0.1), (0.1,0.5), decisionNode)
    plotNode("叶节点", (0.8,0.1), (0.3,0.8), leafNode)
    plt.show()
# 测试结果
>>> import treePlotter
>>> treePlotter.createPlot()

plotNode()_example

2.构造注解树

为了绘制一颗决策树,要知道如何放置树的节点。所以定义下面两个函数,分别用来获取叶节点的个数(x轴长度)和树的层数(y轴高度):

# 获取叶节点数目,以便确定x轴长度
# 叶节点:得到类别的节点;决策节点:需要进一步判断的节点
# 思路:判断该节点对应值的数据类型是否为‘字典’,若是,该节点为决策节点,递归;若不是,该节点为叶节点
def getNumLeafs(myTree):
    numLeafs = 0
    # firstStr为第一个决策节点
    firstStr = list(myTree.keys())[0]   #py3.*中,dict.keys()的值类型不带下标,需转化成list
    # firstStr为第一个决策节点对应的值,即余下的节点
    secondDict = myTree[firstStr]
    for key in secondDict.keys():   # 在余下的节点中遍历
        if type(secondDict[key]).__name__=='dict':  # 判断第二个节点是否仍为字典类型
            numLeafs += getNumLeafs(secondDict[key])    # 若是,该节点为决策节点,递归调用getNumLeafs()
        else:
            numLeafs += 1   #若不是,该节点为叶节点
    return numLeafs

# 获取树的层数(决策节点的个数),以便确定y轴长度
def getTreeDepth(myTree):
    maxDepth = 0
    firstStr = list(myTree.keys())[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__=='dict':
            thisDepth = 1 + getTreeDepth(secondDict[key])
        else:
            thisDepth = 1
        if thisDepth > maxDepth: maxDepth = thisDepth # 取遍历完后的最大值
    return maxDepth

为节省时间,预存储两个树的信息:

# 预先存储树信息,避免每次测试都要创建树
def retrieveTree(i):
    listOfTrees = [{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},
                   {'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}]
    return listOfTrees[i]
# 测试结果
>>> treePlotter.retrieveTree(1)
{'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}
>>> myTree=treePlotter.retrieveTree(0)
>>> myTree
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
>>> treePlotter.getNumLeafs(myTree)
3
>>> treePlotter.getTreeDepth(myTree)
2

3.绘制决策树

# 在父子节点间填充文本信息
# 给定(标记线起点坐标(即当前节点框中心坐标),标记线终点坐标(即上一个节点框中心坐标),文本信息)
# 返回父子节点的中间位置坐标
def plotMidText(cntrPt, parentPt, txtString):
    xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]
    yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString)

plt.text()

  • 待消化
def plotTree(myTree, parentPt, nodeTxt):
    numLeafs = getNumLeafs(myTree)  # 获取子节点个数
    depth = getTreeDepth(myTree)    # 获取树的层数
    firstStr = list(myTree.keys())[0]
    # cntPt为叶节点中心坐标
    cntrPt = (plotTree.xOff + (1.0+float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff) # ???这里怎么计算
    plotMidText(cntrPt, parentPt, nodeTxt)
    plotNode(firstStr, cntrPt, parentPt, decisionNode)
    secondDict = myTree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[key]).__name__=='dict':
            plotTree(secondDict[key], cntrPt, str(key))
        else:
            plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD
      
def createPlot(inTree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)    #no ticks
    #createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses 
    plotTree.totalW = float(getNumLeafs(inTree))    #全局变量plotTree.totalW,储存树的宽度
    plotTree.totalD = float(getTreeDepth(inTree))   #全局变量PlotTree.totalD,储存树的高度
    plotTree.xOff = -0.5/plotTree.totalW    #全局变量plotTree.xOff,追踪已绘制的节点位置,从左到右,即递增
    plotTree.yOff = 1.0                     #全局变量plotTree.yOff,追踪已绘制的节点位置,从上到下,即递减    
    plotTree(inTree, (0.5,1.0), '') # 在(0.5,1.0)的位置绘制第一个节点(父节点/根节点)
    plt.show()  

三、测试和存储分类器

使用决策树执行分类

# 使用决策树的分类函数
# first step: 使用index方法查找当前列表中第一个匹配firsStr的元素
# second step: 递归遍历整棵树,比较testVec中的值和树节点的值,若为决策节点(字典类型),递归;否则即为叶节点,返回该节点类别标签
def classify(inputTree, featLabels, testVec):
    firstStr = list(inputTree.keys())[0]  # 决策树第一个特征
    secondDict = inputTree[firstStr]    # 决策树第一个特征对应的值
    featIndex = featLabels.index(firstStr)  # 决策树第一个特征在featLabls中的索引(第0个特征/第1个特征等)
    for key in secondDict.keys():   # 遍历余下的特征键值,找到和测试数据相等的key
        if testVec[featIndex] == key:   # 若testVec中第featIndex个值等于key
            if type(secondDict[key]).__name__=='dict':  # 若还是字典,递归
                classLabel = classify(secondDict[key], featLabels, testVec) 
            else:
                classLabel = secondDict[key]    # 否则直接返回key对应的类别标签
    return classLabel
# 测试结果
>>> myDat,labels=tree.createDataSet()
>>> myTree=tree.createTree(myDat,labels)
>>> myDat
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>> labels
['no surfacing', 'flippers']
>>> myTree
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
>>> tree.classify(myTree,labels,[1,1])
'yes'

index()

list.index(obj)

返回某个对象obj在列表list中的索引值。

>>> list1 = ['Google', 'Runoob', 'Taobao']
>>> list1.index("Google")
0
>>> list1.index("Taobao")
2

2.使用算法:决策树的存储

构造决策树是很耗时的任务,但是用构造好的决策树解决分类问题可以很快完成。所以最好能在每次执行分类时调用已经构造好的决策树,这就需要将决策树存储在磁盘中。

# 使用pickle模块存储决策树
def storeTree(inputTree, filename):
    import pickle
    # fw = open(filename, 'w')   #TypeError: write() argument must be str, not bytes
    fw = open(filename, 'wb')
    pickle.dump(inputTree, fw)
    fw.close()

# 使用pickle模块读取决策树
def grabTree(filename):
    import pickle
    # fr = open(filename)  # UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 0: illegal multibyte sequence
    fr = open(filename, 'rb')
    return pickle.load(fr)
# 测试结果
>>> tree.storeTree(myTree,'classifierStorage.txt')
>>> tree.grabTree('classifierStorage.txt')
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

pickle模块

用于序列化对象,可以将python中几乎所有的数据类型(列表,字典,集合,类等)序列化,将其作为文件储存。pickle序列化后的数据,可读性差,人一般无法识别。参考

pickle.dump(obj, file[, protocol])

序列化对象,并将结果数据流写入到文件对象中。参数protocol是序列化模式,默认值为0,表示以文本的形式序列化。protocol的值还可以是1或2,表示以二进制的形式序列化。

pickle.load(file)

反序列化对象。将文件中的数据解析为一个Python对象。

3.示例:使用决策树预测隐形眼镜类型

import tree
import treePlotter

fr = open('lenses.txt') # 读取隐形眼镜数据集
lenses = [inst.strip().split('\t') for inst in fr.readlines()]  # 将文本数据集转化为列表
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
lensesTree = tree.createTree(lenses, lensesLabels)
print(lensesTree)
treePlotter.createPlot(lensesTree)
# output:
{'tearRate': {'normal': {'astigmatic': {'no': {'age': {'young': 'soft', 'presbyopic': {'prescript': {'myope': 'no lenses', 'hyper': 'soft'}}, 'pre': 'soft'}}, 'yes': {'prescript': {'myope': 'hard', 'hyper': {'age': {'young': 'hard', 'presbyopic': 'no lenses', 'pre': 'no lenses'}}}}}}, 'reduced': 'no lenses'}}

在这里插入图片描述

总结

优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
缺点:可能会产生过度匹配问题。例如隐形眼镜的示例中,匹配选项过多,可以考虑裁剪部分叶节点(如果该节点不能产生太多信息)。
适用数据类型:标称型和数值型(需要离散化)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《机器学习实战》——决策树 的相关文章

随机推荐

  • 自媒体爆款标题怎么写?手把手教你写热门标题

    自媒体内容想提高阅读量 标题是关键 如何创作优质且有吸引的标题呢 自媒体爆款标题怎么写 今天对热门标题进行解析 手把手教你写爆款标题 1 标题贴合热点 用户对热点的关注度超乎想象 有时候对热点关键词的搜索都能让系统崩溃 所以 在标题中添加热
  • Python语言学习实战-内置函数sorted()的使用(附源码和实现效果)

    实现功能 sorted 函数是Python的内置函数之一 用于对可迭代对象进行排序操作 它可以对列表 元组 字符串等可迭代对象进行排序 并返回一个新的已排序的列表 sorted 函数的语法如下 sorted iterable key Non
  • unity用visual studio写代码的时候一直显示importing assets

    项目场景 提示 使用Unity时打开C 弹出opening visual studio 然后一直停在importing assets这个界面 不影响写代码和运行 但是非常不舒服 困扰我许久 特别浪费时间 问题描述 unity3d打开项目中遇
  • JAVA应用程序集成控件JxBrowser v7.2来啦!允许自定义错误页面

    JxBrowser 点击下载 是将基于Chromium的浏览器与Java应用程序集成 以处理和显示HTML5 CSS3 JavaScript Flash等 JxBrowser更新至最新版v7 2 允许针对HTTP和网络错误覆盖标准Chrom
  • ES 搜索7 (多词查询)

    多词查询 如果我们一次只能搜索一个词 那么全文搜索就会不太灵活 幸运的是 match 查询让多词查询变得简单 GET my index my type search query match title BROWN DOG 上面这个查询返回所
  • vue 使用el-option标签解决不回显的问题

    一 问题描述
  • 最新----Dubbo Spring Cloud 重塑微服务治理

    spring cloud alibaba dubbo examples代码示例 摘要 在 Java 微服务生态中 Spring Cloud1 成为了开发人员的首选技术栈 然而随着实践的深入和运用规模的扩大 大家逐渐意识到 Spring Cl
  • 中兴2023秋招二面

    中兴二面 面试时长为20分钟的样子 请问你带了身份证或者学生证件吗 1 自我介绍 姓名 学校 专业 兴趣爱好 2 项目分工 应该问的是如何分工 我回答的不太好 首先根据项目工作量 分为几份工作 团队成员自行根据自己的情况认领对应项目 团队负
  • LU分解法

    LU分解的原理是将一个矩阵分解为一个下三角矩阵L和一个上三角矩阵U的乘积 下面是LU分解的原理 定一个n n的矩阵A 我们希望将它分解为下三角矩阵L和上三角矩阵U的乘积 即A LU 我们可以在矩阵A上进行列主元高斯消元 消元的过程中会用到矩
  • File "errorchecker.pyx", line 17, in OpenGL_accelerate.errorchecker._ErrorChecker.__init__ (src\erro

    先安装 pip install PyOpenGL 3 0 2 再安装 pip install PyOpenGL PyOpenGL accelerate 结果 这次只安装PyOpenGL accelerate 调用代码会报错 File err
  • uView的组件u-picker 选择器

    网址 https www uviewui com components picker html 需要的是数组中的数组 处理核心是将接口获取回来的数组 赋给一个空数组 然后把这空数组再push到一个空数组里面 this arr1 res da
  • docker的配置,基础用法

    什么是docker docker中的容器 lxc gt libcontainer gt runC OCI OCF OCI Open Container initiative 开放容器倡议 由Linux基金会主导于2015年6月创立 旨在围绕
  • 【Swift】LeedCode整数反转

    Swift LeedCode 拿硬币 由于各大平台的算法题的解法很少有Swift的版本 小编这边将会出个专辑为手撕LeetCode算法题 新手撕算法 请包涵 给你一个 32 位的有符号整数 x 返回将 x 中的数字部分反转后的结果 如果反转
  • 小程序分享及返回上级页面

    分享监听 用户点击右上角分享 onShareAppMessage function res console log res if res from menu return title 邀请赢好礼 path pages member memb
  • 【hadoop报错】(ssh)Connection timed out

    背景 在虚拟机上启动hadoop 报错 Starting namenodes on node1 huike cn Last login Thu Oct 14 22 36 08 EDT 2021 on pts 0 node1 huike cn
  • 为什么单线程的Redis那么快?

    1 Redis单线程的本质 其实 Redis并不是单线程 我们之所以会一直称Redis是单线程 这是因为Redis在处理客户端的读写请求时 只有一个主线程 而在处理以下这些操作时 Redis会fork出其他的子线程来处理 主从数据同步 切片
  • 多元统计分析与R语言练习

    多元考试练习 文章目录 多元考试练习 一 多元线性回归模型 1 建立回归模型 2 逐步筛选 3 最优标准方程 影响最大 4 全局择优法 使用4 2 1版本的R 5 分析 6 由标准化偏回归系数可见 方差分析结果 二 判别分析 1 线性判别
  • python学习心得总结

    21年7月8上午是我第一次接触python这个语言 对于python这个语言之前了解的也并不是很多 也可以说几乎为零 因为我们之前的学习也不考python 所以也没想过去主动学习它 然而当我听老师讲解的时候 首先我发现python这个语言相
  • 使用VS2005下自带的MSSQL 2005 EXPRESS

    VS2005安装后自带一个试用版的SQL2005 EXPRESS版 方便了开发时使用数据库 不用再安装一个sql 2005 怪占用资源的 如何使用 安装后 在开始菜单里出现个sql的菜单组 但是找不到sql server的控制台 习惯用sq
  • 《机器学习实战》——决策树

    本章介绍的决策树算法为ID3算法 Iterative Dichotomiser 3 迭代二叉树3代 主要流程为 根据信息增益找到划分数据的最佳特征 判断划分后每个数据子集是否为同一分类 若是 返回分类结果 若不是 再次划分数据子集 递归 同