当前位置: 首页 > news >正文

python学智能算法(九)|决策树深入理解

【1】引言

前序学习进程中,初步理解了决策树的各个组成部分,此时将对决策树做整体解读,以期实现深入理解。

各个部分的解读文章链接为:

python学智能算法(八)|决策树-CSDN博客

【2】代码

【2.1】完整代码

这里直接给出完整代码:

import numpy as np
from math import log  # 引入log()函数求对数
import operator# 定义一个嵌套列表
def creatDataset():# dataset是一个嵌套列表dataset = [[1, 1, 'yes'],[1, 1, 'yes'],[1, 0, 'no'],[0, 1, 'no'],[0, 1, 'no']]# lables也是一个列表labels = ['no surfacing', 'flippers']return dataset, labels# calcShannonEnt是具体的香农熵求解函数
def calcShannonEnt(dataset):# numEntries获得了dataset列表的行数numEntries = len(dataset)# labelcounts是一个空的字典labelcounts = {}# for函数的意义是,对于dataset里面的每一行都会执行循环操作for feature in dataset:# currentlabel 取到了feature的最后一个元素currentlabel = feature[-1]# 由于labelcounts是一个空字典,labelcounts.keys()在第一次运行的时候不会指向任何标签,所以会被直接添加# currentlabel是每一行dataset的最后一列,也就是最后一个元素# if函数实际上进行了同类项合并工作if currentlabel not in labelcounts.keys():# 给以currentlabel为标签的项目赋值0labelcounts[currentlabel] = 0# 只要currentlabel和labelcounts.keys()存储的元素一致,就给以currentlabel为标签的项目赋值加1labelcounts[currentlabel] += 1# 定义香农熵的初始值=0ShannonEnt = 0.0# 由于labelcounts是字典,所以可以用key访问字典的项目for key in labelcounts:# 计算值为浮点数# 用key指向的项目对应的数量比上总数prob = float(labelcounts[key]) / numEntries# 香农熵就是频数乘以以2为底的频数的对数,然后还要取负值# 取负值是因为,频数小于1,所以对数小于0,一旦取负值就获得了正数ShannonEnt -= prob * log(prob, 2)return ShannonEntdataset, labels = creatDataset()
ShannonEnt = calcShannonEnt(dataset)
print('ShannonEnt=', ShannonEnt)# splitdataset把一些列因素直接删除后输出
def splitdataset(dataset, axis, value):# 创建一个新的列表retdataset = []# 对于dataset的每一行for featvec in dataset:# if第axis列的数据刚好和value相等if featvec[axis] == value:# reducedfeature先获取索引从第0个到axis-1的元素,一共axis个reducedfeatvec = featvec[:axis]# reducedfeature继续获取索引从第axis+1开始的所有元素# reducedfeature后面再获取从第axis+2个开始一直到最后一个元素reducedfeatvec.extend(featvec[axis + 1:])# retdataset存储了reducedfeature# retdataset中刚好没有位置索引为axis的元素retdataset.append(reducedfeatvec)return retdatasetdef choosebestfeaturetosplit(dataset):# 对dataset第0行求长度,获得列数,然后再减去1numfeatures = len(dataset[0]) - 1# 调用函数calcShannonEnt获得dataset的香农熵baseentroy = calcShannonEnt(dataset)# 定义一个常数bestinfogain = 0.0# 定义一个常数bestfeature = -1# 对于numfeatures中的每一个数# numfeatures比dataset的列数少一个for i in range(numfeatures):# 对于每一个在dataset中的元素,按照位置索引为i的形式提取featlist = [example[i] for example in dataset]# set是一个内置函数,将featlist这个列表转化为集合# 集合具有合并同类项的作用,重复的元素只会保留一个uniquevals = set(featlist)# 定义一个常数newentropy = 0.0# 对于uniquevals中的每一个值for value in uniquevals:# 调用splitdataset进行子集划分subdataset = splitdataset(dataset, i, value)# 获取每一个元素的香农熵prob = len(subdataset) / float(len(dataset))# 更新香农熵newentropy += prob * calcShannonEnt(subdataset)# 获得香农熵的变化量infogain = baseentroy - newentropy# 如果变化量查过阈值if (infogain > bestinfogain):# 新变化=变化量bestinfogain = infogain# 给bestfeature赋值ibestfeature = ireturn bestfeaturedef majoritycnt(classlist):# classcount是一个空字典classcount = {}for vote in classlist:# classlist是一个外部导入的参数# 从if条件来看,classlist也是一个字典# 对于classlist字典里的每一个键if vote not in classcount.keys():# 如果classlist里的键和clssscount里的键不一样# classcount字典里的vote键赋值0classcount[vote] = 0# 如果classlist里的键和clssscount里的键一样# classcount字典里的vote键值+1classcount[vote] += 1# Python 3中字典的iteritems()方法已被items()方法取代sortedclasscount = sorted(classcount.items(), key=operator.itemgetter(1), reverse=True)return sortedclasscount[0][0]def creattree(dataset, labels):# 对dataset中的最后一列取值# classlist是一个列元素列表classlist = [example[-1] for example in dataset]# 修正判断条件的括号# classlist.count(classlist[0])获得的是classlist列元素的第一个元素出现的次数# len(classlist)是classlist的行数,等于dataset中样本的数量if classlist.count(classlist[0]) == len(classlist):return classlist[0]# dataset[0]代表的是列数,如果列数=1,就直接返回classlist代入majoritycnt()函数的值if len(dataset[0]) == 1:return majoritycnt(classlist)# bestfeat通过choosebestfeaturetosplit(dataset)函数取值bestfeat = choosebestfeaturetosplit(dataset)# bestfeatlabel通过labels[bestfeat]函数取值bestfeatlabel = labels[bestfeat]# mytree是一个空字典,字典的键为bestfeatlabel,键值暂时是一个空字典mytree = {bestfeatlabel: {}}# 从特征标签中删除bestfeaturedel (labels[bestfeat])# featvalues的取值是dataset中位置索引为bestfeat的行featvalues = [example[bestfeat] for example in dataset]# 合并同类项uniquevals = set(featvalues)# 对于每一项for value in uniquevals:# sublabels是一个lables的副本sublabels = labels[:]# 获得决策树mytree[bestfeatlabel][value] = creattree(splitdataset(dataset, bestfeat, value), sublabels)return mytree# 测试代码
dataset, labels = creatDataset()
tree = creattree(dataset, labels.copy())
print("决策树:", tree)

如此长的代码如果不看上一篇文章会有些费力。如果确实不想看,可以先一起看最后构建决策树的部分。

【2.2】构建决策树代码

这里直接给出构建决策树代码:

# 新定义的creattree函数有dataset和labels两个参数
def creattree(dataset,labels):# classlist是从dataset中的每一行取出的最后一个数据classlist=[example[-1] for example in dataset]# classlist[0]表示classlist列表中的第一个元素# classlist.count(classlist[0])表示classlist列表中的第一个元素出现的次数# len(classlist)表示classlist的长度,就是这个列表中有几个元素的意思if classlist.count(classlist[0])==len(classlist):# 如果classlist第一个元素的数量就和len(classlisi)相等# 直接返回classlist[0]return classlist[0]# 如果dataset的第一行只有1个数据,表明所有的特征也都只有一个# 没有其他特征,也就是特征划分完毕if len(dataset[0])==1:# 调用majority()函数return majoritycnt(classlist)# bestfeat从choosebestfeaturetosplit()函数获取bestfeat=choosebestfeaturetosplit(dataset)# bestfeatlabel从labels中按照bestfeat位置索引获取bestfeatlabel=labels[bestfeat]# mytree是一个嵌套列表# bestfeatlabel是一个键,但它的值是一个空字典mytree={bestfeatlabel:{}}# del是一个删除函数,删除了labels中,bestfeat为位置索引的标签名del(labels[bestfeat])# featvalues是对dataset逐行取bestfeat对应的值featvalues=[example[bestfeat] for example in dataset]# uniquevals是对featvalues进行合并同类项uniquevals=set(featvalues)# 对于uniquevals中的每一个取值,构建一个子树for value in uniquevals:# labels[:]是一个切片操作sublabels=labels[:]# 绘制决策树mytree[bestfeatlabel][value]=creattree(splitdataset(dataset,bestfeat,value),sublabels)return mytree

其实这里也可以理解为主函数,因为在这里对子函数进行了调用。

【2.2.1】前置操作

首先看前三行:

# 新定义的creattree函数有dataset和labels两个参数
def creattree(dataset,labels):# classlist是从dataset中的每一行取出的最后一个数据classlist=[example[-1] for example in dataset]# classlist[0]表示classlist列表中的第一个元素# classlist.count(classlist[0])表示classlist列表中的第一个元素出现的次数# len(classlist)表示classlist的长度,就是这个列表中有几个元素的意思if classlist.count(classlist[0])==len(classlist):# 如果classlist第一个元素的数量就和len(classlisi)相等# 直接返回classlist[0]return classlist[0]

这是一个自定义函数,有两个参数引入:dataset和labels。

classlist=[],先不考虑方括号“[]”里面的内容,表明classlist是一个列表,内部可以不断存储新的元素。

classlist=[example[-1] for example in dataset]

实际的代码定义过程表明classlist使用了嵌套for循环遍历方法:

  1. for example in dataset,对于dataset,要遍历其中的每一行;
  2. axample[-1],提取最后一列数据;
  3. classlist实际上存储了dataset的最后一列数据。

然后使用了列表函数的自动计数功能classlist.count(),它计算了classlist[0] 也就是classlist第一个元素的出现次数,如果这个次数和classlist内部的元素数量相等,就会直接返回这个元素。

实际上这是一个结束操作,如果classlist内的所有元素都一样,已经没有继续分类的必要。

【2.2.2】调用函数

调用函数的部分相对复杂,拆开来看:

    if len(dataset[0])==1:# 调用majority()函数return majoritycnt(classlist)# bestfeat从choosebestfeaturetosplit()函数获取bestfeat=choosebestfeaturetosplit(dataset)# bestfeatlabel从labels中按照bestfeat位置索引获取bestfeatlabel=labels[bestfeat]

首先判断dataset[0]是否只剩下一个元素,如果是,就调用majority()函数。

借此机会回忆一下majority函数:

# majoritycnt是一个新函数,调用参数为classlist
def majoritycnt(classlist):# classcount是一个空列表classcount={}# 定义一个for循环来遍历外部输入参数classlistfor vote in classlist:# 如果vote不在clsaacount的键值中# 定义一个新的键vote,并赋值0if vote not in classcount.keys():classcount[vote]=0# if not in 是完成对首次出现的值进行键定义的操作# 但实际上只有出现它的次数就至少为1,所以这里会有一个自动加1的操作classcount[vote]+=1# sorted函数函数会对classcount中的字典进行键值对取值后排列# operator.itemgetter(1)是一个函数,会自动统计每个键值出现的次数# reverse则要求按照从大到小的顺序排列sortedclasscount=sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)# sortedclssscount作为列表,内部有很多元组# 每个元组的第一个元素代表统计出来的类别,第二个元素代表这个类别的数量return sortedclasscount[0][0]

majority()函数的外部输入参数是classlist,前述学习已知这是一个列表。

然后定义了一个空的字典classcount备用。

对于列表classlist,对其中的每一个元素都进行遍历,如果某个元素不在classcount中,就新增这个元素为字典classcount的键,然后赋键值为1,如果本来就是classcount中的键,将对应键值+1。

然后使用sorted()函数将classcount这个字典里面的项目进行排序:

  1. classcount.items()是获取classcount这个字典中所有项目的意思;
  2. key=operator.itemgetter(1)决定了排序的依据是python语言认为的第1个元素(第0个,第1个,常规认知里面的第2个);
  3. reverse=True表明排序后的数据将从大到小排列。

排序后的sortedclasscount是一个由元组组成的列表数组,每个元组都是由字典形式直接转换,第一个元素是字典的键,第二个元素是字典的值。

最后输出的sortedclasscount[0][0]是字典classcount中键值最大的一组键和值。

然后回到为何要调用majority()函数:需要先判断dataset[0]是否只剩下一个元素,如果是,就调用majority()函数。dataset[0]是一行数据,剩下一个元素时表明已经无法再细分。这个时候已经可以进行最后的判断,也就是找出classlist中各类别的数量极大值。

然后面对dataset[0]剩下不止一个元素的情况,此时需要通过调用choosebestfeaturetosplit()函数获得一个最佳的特征值:bestfeat = choosebestfeaturetosplit(dataset)。

借此机会回忆choosebestfeaturetosplit()函数:

from 划分数据集 import splitdataset
from 香农熵 import calcShannEntdef choosebestfeaturetosplit(dataset):# 取dataset的第0行,获取列数后减去1numfeature=len(dataset[0])-1# 直接调用calcShannEnt(dataset)函数获得数据集的原始香农熵baseentrop=calcShannEnt(dataset)# 定义bestinfogain的初始值为0.0bestinfogain=0.0# 定义bestfeature的初始值为-1bestfeature=-1# 定义一个for循环for i in range(numfeature):# feature是一个嵌套列表# for axample indataset的意思是对于dataset的每一行# example[i]是指每一行数据中的每一列featlist=[example[i] for example in dataset]# set()函数具有合并同类型的作用uniquevalues=set(featlist)# 定义newentropy初始值为0.0newentropy=0.0# 在一个新的for循环中# 调用splitdataset函数来进行数据划分for value in uniquevalues:# 参数i是取到的列数据# 逐列进行了数据同类合并操作# value就代表了每一列中的数据可能取值subdataset=splitdataset(dataset,i,value)# subdataset是按照i和value划分的集合# prob是划分的子集合和原来的数据集比例prob= len(subdataset)/float(len(dataset))# 新的熵是新子集比例和原来香农熵的乘积newentropy+=prob*calcShannEnt(subdataset)# 整个for循环是按照每列的形式,提取该列所有可能的取值,重新对数据及进行划分# newentropy是按照列进行数据集划分之后,获得的新熵值# infogain代表了数据集的原始熵值和新熵值的变化量,也就是信息增益infogain=baseentrop-newentropy# if判断信息增益超过最佳增益# 取信息增益为最佳增益# 取当前i为最佳的列划分依据if (infogain>bestinfogain):bestinfogain=infogainbestfeature=i# 在整个for循环中,按照列的形式提取数据后划分数据集# 然后计算这种划分方式产生的信息增益return bestfeature

choosebestfeaturetosplit()函数需要和香农熵定义函数以及数据集划分函数共同使用。

先看数据提取和初始定义部分:

    # 取dataset的第0行,获取列数后减去1numfeature=len(dataset[0])-1# 直接调用calcShannEnt(dataset)函数获得数据集的原始香农熵baseentrop=calcShannEnt(dataset)# 定义bestinfogain的初始值为0.0bestinfogain=0.0# 定义bestfeature的初始值为-1bestfeature=-1

choosebestfeaturetosplit()函数的参数是dataset,提取dataset列数据然后减1得到numfeature。              

baseentropy是对初始数据集香农熵的直接提取。

bestinfogain初始化定义为0.0。

bestfeature初始化定义为-1。

然后定义一个for循环:

    # 定义一个for循环for i in range(numfeature):# feature是一个嵌套列表# for axample indataset的意思是对于dataset的每一行# example[i]是指每一行数据中的每一列featlist=[example[i] for example in dataset]# set()函数具有合并同类型的作用uniquevalues=set(featlist)# 定义newentropy初始值为0.0newentropy=0.0

  这个for循环里面用到了numfeature,依据这个数据进行遍历:

featlist是一个列表,提取了dataset中的每一行数据的第i列,可以理解为featlist是一个取列的操作。

uniquevalues是一个集合,是通过调用set()函数合并同类项后的结果。

uniquevalues是set()函数对第i列数据进行同类项合并以后的结果。

然后在for循环内部定义了一个新的for循环,也就是依然对提取到的第i列数据进行操作。为便于说清楚,将对numfeature的遍历for循环定义为外循环,对uniquevalues的for循环定义为内循环。           

# 在一个新的for循环中# 调用splitdataset函数来进行数据划分for value in uniquevalues:# 参数i是取到的列数据# 逐列进行了数据同类合并操作# value就代表了每一列中的数据可能取值subdataset=splitdataset(dataset,i,value)# subdataset是按照i和value划分的集合# prob是划分的子集合和原来的数据集比例prob= len(subdataset)/float(len(dataset))# 新的熵是新子集比例和原来香农熵的乘积newentropy+=prob*calcShannEnt(subdataset)

在这个for循环中,对uniquevalues中的每个元素进行遍历 :

调用splitdataset()函数进行数据集划分获得subdataset。

然后将获得的subdataset长度和原始数据集长度进行对比,获得比例数据prob,prob和subdataset的香农熵相乘,据此获得新的熵。

最后需要判断是否获得了最大的信息增益(熵增),这个判断是在外层的for循环进行。

        # 整个for循环是按照每列的形式,提取该列所有可能的取值,重新对数据及进行划分# newentropy是按照列进行数据集划分之后,获得的新熵值# infogain代表了数据集的原始熵值和新熵值的变化量,也就是信息增益infogain=baseentrop-newentropy# if判断信息增益超过最佳增益# 取信息增益为最佳增益# 取当前i为最佳的列划分依据if (infogain>bestinfogain):bestinfogain=infogainbestfeature=i# 在整个for循环中,按照列的形式提取数据后划分数据集# 然后计算这种划分方式产生的信息增益return bestfeature

最后输出的bestfeature是对比了所有列数据之后获得的。

choosebestfeaturetosplit()函数一共调用了两个子函数,分别是香农熵计算函数calcShannEnt()和

数据集划分函数splitdataset()。

此处先回忆香农熵计算函数calcShannEnt():

# 定义香农熵计算函数
def calcShannEnt(dataset):# 取dataset数据集的行数numEntries=len(dataset)# 定义一个空字典# 字典包括键和键值两部分labelCounts={}# 定义一个循环,去除每一类数据的数量for featVec in dataset:# currentLabel取dataset的最后一列currentLabel=featVec[-1]# labelCounts.keys()取出了labelCounts这个字典里面的所有键值if currentLabel not in labelCounts.keys():# 如果currentLabel不在labelCounts的键值里面# 对labelCounts这个字典进行赋值# currentLabel是字典里面的键,0是对应的键值labelCounts[currentLabel]=0# 如果currentLabel在labelCounts的键值里面# 对labelCounts这个字典进行赋值# currentLabel是字典里面的键,对应的键值增加1labelCounts[currentLabel]+=1# 定义初始香农熵=0shannonEnt=0# 使用for循环# 对于字典labelCounts进行遍历for key in labelCounts:# 计算每一个键值在所有键中的比例# 这里计算的就是每一种类别的比例prob =float(labelCounts[key])/numEntries# 对数计算香农熵shannonEnt-=prob*log(prob,2)# 香农熵的计算值返回return shannonEnt

相对来说,香农熵计算函数最好理解,但需要注意的是,它以dataset数组的最后一列为依据,计算了每一种类别的比例,然后得到原始数据集的香农熵。

然后是分数据集划分函数splitdataset():

def splitdataset(dataset,axis,value):# 定义一个空列表retdataset=[]# 定义一个for循环for featvec in dataset:# axis是外部输入的参数# 对于dataset的每一行,会按照axis的位置索引进行判断# 如果预设值value被发现,会提取删除value后的行数据if featvec[axis]==value:# 获取第0到axis-1个数据reducedfeatvec=featvec[:axis]# 获取第axis+1到最后一个数据reducedfeatvec.extend(featvec[axis+1:])# 把获取到的数据放到空列表中# 空列表中存储的数据,刚好不包含value所在的行# 这还重反向剔除,找出这个值,然后取不包含这个值的部分retdataset.append(reducedfeatvec)return retdataset

这里的代码更加简短,主要使用了外部传入的dataset、axis和value参数来对第axis列的数据进行判断,如果该列有这个数据,取这行数据中这一列之外的所有数据。

现在我们再次回到主函数:

    if len(dataset[0])==1:# 调用majority()函数return majoritycnt(classlist)# bestfeat从choosebestfeaturetosplit()函数获取bestfeat=choosebestfeaturetosplit(dataset)# bestfeatlabel从labels中按照bestfeat位置索引获取bestfeatlabel=labels[bestfeat]

bestfeat是通过调用choosebestfeaturetosolit()函数获得的参数,这个参数将用于定位labels[bestfeature]。

labels是外部传入的参数:def creattree(dataset, labels)。

labels的来源则是creatdataset函数:

# 定义一个嵌套列表
def creatDataset():# dataset是一个嵌套列表dataset = [[1, 1, 'yes'],[1, 1, 'yes'],[1, 0, 'no'],[0, 1, 'no'],[0, 1, 'no']]# lables也是一个列表labels = ['no surfacing', 'flippers']return dataset, labels

删除labels[bestfeat]:

    # 从特征标签中删除bestfeaturedel (labels[bestfeat])

之后定义了一个空字典:

    # mytree是一个空字典,字典的键为bestfeatlabel,键值暂时是一个空字典mytree = {bestfeatlabel: {}}

取dataset中每一行的最佳特征:

    # featvalues的取值是dataset中位置索引为bestfeat的行featvalues = [example[bestfeat] for example in dataset]

bestfeature是从choosebestfeaturetosolit()函数获得的参数,此时定位到了最大信息增益对应的列,所以就直接从dataset中提取这一列数据,存储到featvalues列表中。

然后需要进行合并同类项操作:

    # 合并同类项uniquevals = set(featvalues)

之后就是获得决策树的操作:

    # 对于每一项for value in uniquevals:# sublabels是一个lables的副本sublabels = labels[:]# 获得决策树mytree[bestfeatlabel][value] = creattree(splitdataset(dataset, bestfeat, value), sublabels)return mytree

最难理解的部分其实是源于creattree(splitdataset(dataset, bestfeat, value), sublabels)。

首先splitdataset对原始数据集dataset依据bestfeat列和最佳特征值value进行了划分,然后使用sublabels获得bestfeature。这是一个递归过程,在函数内自己调用自己,最后实现决策树绘制。

【3】总结

对决策树程序进一步思考,深入理解内涵。

相关文章:

python学智能算法(九)|决策树深入理解

【1】引言 前序学习进程中,初步理解了决策树的各个组成部分,此时将对决策树做整体解读,以期实现深入理解。 各个部分的解读文章链接为: python学智能算法(八)|决策树-CSDN博客 【2】代码 【2.1】完整代…...

HTTP代理:内容分发战场上的「隐形指挥官」

目录 一、技术本质:流量博弈中的「规则改写者」 二、战略价值:内容分发的「四维升级」 三、实战案例:代理技术的「降维打击」 四、未来进化:代理技术的「认知升级」 五、结语:代理技术的「战略觉醒」 在数字内容爆…...

学习笔记(C++篇)--- Day2

1.类的定义 1.1 类的格式 ①class为类的关键字 ②在类的内容中还可以写函数,具体格式请看示例。 ③为了区分成员变量,一般习惯上成员变量会加一个特殊标识(如成员变量前面或者后面加_ 或者 m开头,注意C中这个并不是强制的&#x…...

下载firefox.tar.xz后如何将其加入到Gnome启动器

起因:近期(2025-04-07)发现firefox公布了130.0 版本,可以对pdf文档进行签名了,想试一下,所以卸载了我的Debian12上的firefox-esr,直接下载了新版本的tar.xz 包。 经过一番摸索,实现了将其加入Gn…...

VSCode英文翻译插件:变量命名、翻单词、翻句子

目录 【var-translate】 【Google Translate】 【code-translator】 【其他插件】 【var-translate】 非常推荐,可以提供小驼峰、大驼峰、下划线、中划线、常量等翻译,Windows下快捷键为Ctrl Shift v 可以整句英文翻译,并且支持多个免费…...

快速高效的MCP Severs

通用AI Agent的瓶颈 最近一直在用MCP协议开发通用智能体。 虽然大模型本身请求比较慢,但是还可以接受。 而最让人沮丧的是,工具效率也不高 比如社区的filesystem,每次只能创建一个目录,生成文件时,如果目录不存在&…...

原子化 CSS 的常见实现框架

原子化 CSS 是一种 CSS 架构方法,其核心思想是将样式拆分为最小粒度的单一功能类,每个类仅对应一个具体的样式属性(如颜色、边距、字体大小等),通过组合这些类来构建复杂的界面。这种方式强调代码复用性、维护性和灵活…...

技术速递|使用 GitHub Copilot Agent Mode 进行编程

作者:卢建晖 - 微软高级云技术布道师 翻译/排版:Alan Wang GitHub Copilot 持续发展,从最初的代码补全、生成、优化功能,到通过对话交互提升 AI 代码质量的 GitHub Copilot Chat,再到能够基于项目中多个文件的关联进行…...

Linux系统(Ubuntu和树莓派)的远程操作练习

目录 实验准备一、Ubuntu 下的远程操作二、树莓派下的远程操作三、思考 实验准备 ​ 1.双方应保证处于同一个局域网内 ​ 2.关闭防火墙 (否则别人将不能 ping 通自己,具体说明请参考:windows-关闭防火墙) ​ 3.配置虚拟机 ​ a.网桥模式配置 ​ 查询…...

电脑屏保壁纸怎么设置 桌面壁纸设置方法详解

电脑桌面壁纸作为我们每天面对的第一视觉元素,不仅能够彰显个人品味,还能营造舒适的工作或娱乐氛围。电脑桌面壁纸怎么设置呢?下面本文将为大家介绍Windows和macOS两大主流操作系统中设置电脑桌面壁纸的方法,帮助大家快速设置个性…...

为什么选择Redis?解析核心使用场景与性能优化技巧

解析核心使用场景与性能优化技巧 redis只能能操作字符串,要把Java对象存入redis非关系型数据库,需要用序列化变成字符串,再反序列化成Java对象 not only sql NoSQL非关系型数据库:缓存数据库,只能读取数据&#xff0…...

Docker中Redis修改密码失效

docker容器中,我们通过docker run命令运行某一容器 这里,我们通过以下命令来进行运行【注意,这里有两个关键点:-d 和--requirepass】 docker run \ --restartalways \ --log-opt max-size100m \ --log-opt max-file2 \ -p 6379:6…...

质数质数筛

1.试除法判定质数–O(sqrt(N)) bool is_prime(int x) {if (x < 2) return false;for (int i 2; i < x / i; i )if (x % i 0)return false;return true; }2.试除法分解质因数–O(logN)~O(sqrt(N)) void divide(int x) {for (int i 2; i < x / i; i )if (x % i …...

VGA接口设计

1.VGA简介 VGA(Video Graphics Array)视频图形阵列接口是一种模拟信号视频传输标准,用于连接计算机主机和显示设备,如显示器、投影仪等。 VGA接口能够传输红、绿、蓝三原色的模拟信号以及同步信号(数字信号),实现计算机图形和视频信号的输出和显示。 尽管数字化显示接口…...

clickhouse注入手法总结

clickhouse 遇到一题clickhouse注入相关的&#xff0c;没有见过&#xff0c;于是来学习clickhouse的使用&#xff0c;并总结相关注入手法。 环境搭建 直接在docker运行 docker pull clickhouse/clickhouse-server docker run -d --name some-clickhouse-server --ulimit n…...

VsCode保存时删除无用的引用

打开设置文件 教程&#xff1a;打开VsCode设置设置里添加 {"editor.codeActionsOnSave": {"source.organizeImports": false, // 禁用默认的整理导入"source.removeUnusedImports": true // 仅删除未使用的导入} }...

轻松Linux-4.进程概念

屋漏偏逢连夜雨&#xff0c;今天就学Linux 话不多说&#xff0c;展示军火 1.认识冯诺依曼体系 冯诺依曼体系其实并不是什么稀罕的东西&#xff0c;我们生活中的笔记本、服务器、计算机等等大多都遵守冯诺依曼体系 非常经典的一张图 我们所认识的计算机&#xff0c;是由一个个…...

畅游Diffusion数字人(21):基于Wan2.1的音频驱动数字人FantasyTalking

畅游Diffusion数字人(0)&#xff1a;专栏文章导航 前言&#xff1a;AI数字人是目前视觉AIGC最有希望大规模落地的场景之一。现阶段的商业工具&#xff0c;如字节的OminiHuman-1(即梦大师版)、快手的可灵对口型&#xff0c;虽然效果不错&#xff0c;但是收费昂贵。而开源解决方案…...

CentOS禁用nouveau驱动

1、验证 nouveau 是否在运行 lsmod | grep nouveau如果命令返回结果&#xff0c;说明 nouveau 驱动正在运行。 2、编辑黑名单文件 通过编辑黑名单配置文件来禁用 nouveau 驱动&#xff0c;这样在系统启动时不会加载它。 vi /etc/modprobe.d/blacklist-nouveau.conf修改以下…...

《Operating System Concepts》阅读笔记:p587-p596

《Operating System Concepts》学习第 52 天&#xff0c;p587-p596 总结&#xff0c;总计 10 页。 一、技术总结 1.Recovery (1)consistency checking consistency checking 工具&#xff1a;fsck。 (2)log-structure file system (3)WAFL file system 2.Veritas (1)Ve…...

k8s 1.24.17版本部署(使用Flannel插件)

1.k8s集群环境准备 推荐阅读: https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/ 1.1 环境准备 环境准备:硬件配置: 2core 4GB磁盘: 50GB操作系统: Ubuntu 22.04.04 LTSIP和主机名:10.0.0.231 master23110.0.0.232 worker23210.0…...

通信协议详解(十):PSI5 —— 汽车安全传感器的“抗干扰狙击手”

一、PSI5是什么&#xff1f; 一句话秒懂 PSI5就像传感器界的“防弹信使”&#xff1a;在汽车安全系统&#xff08;如气囊&#xff09;中&#xff0c;用两根线同时完成供电数据传输&#xff0c;即便车祸时线路受损&#xff0c;仍能确保关键信号准确送达&#xff01; 基础概念…...

Kafka生产者和消费者:数据管道的核心引擎与智能终端

在分布式系统中&#xff0c;数据的高效流动如同人体的血液循环&#xff0c;而Kafka的生产者&#xff08;Producer&#xff09;与消费者&#xff08;Consumer&#xff09;正是驱动这一循环的核心组件。它们不仅是Kafka客户端的基本形态&#xff0c;更是构建实时数据生态的基石。…...

特权FPGA之按键消抖

完整代码如下所示&#xff1a; timescale 1ns / 1ps// Company: // Engineer: 特权 // // Create Date: // Design Name: // Module Name: // Project Name: // Target Device: // Tool versions: // Description: // // Dependencies: // // Revision: // …...

实时比分更新系统的搭建

搭建一个实时比分更新系统需要考虑多个技术环节&#xff0c;以下是一个完整的实现方案&#xff1a; 一、系统架构 1.数据获取层 比分数据API接入&#xff08;如熊猫比分、API-Football等&#xff09; 网络爬虫&#xff08;作为备用数据源&#xff09; 2.数据处理层 …...

【Linux】线程的概念与控制

目录 1. 整体学习思维导图 2. 线程的概念 2.1 基础概念 2.2 Linux下的线程 初步理解&#xff1a; 2. 分页式存储 3.1 页表 3.1.1 页框/页 3.1.2 页表机制 3.1.3 从虚拟地址到物理地址的转换 总结&#xff1a; 3.2 TLB快表 3.3 缺页异常&#xff08;Page Fault&am…...

K8s 老鸟的配置管理避雷手册

Yining, China 引言 对于这种案例&#xff0c;你们的处理思路是怎么样的呢&#xff0c;是否真正的处理过&#xff0c;如果遇到&#xff0c;你们应该怎么处理。 最后有相关的学习群&#xff0c;有兴趣可以加入。 开始 一、血泪教训&#xff1a;环境变量引发的真实灾难 1.1 …...

飞速(FS)解决方案验证实验室搬迁升级,赋能客户技术服务

飞速&#xff08;FS&#xff09;解决方案验证实验室近日顺利完成搬迁升级&#xff0c;标志着飞速&#xff08;FS&#xff09;在解决方案可行性验证、质量保障以及定制化需求支持方面迈上新台阶&#xff0c;进一步提升了产品竞争力和客户信任度。 全新升级的实验室定位为技术验证…...

柔性关节双臂机器人奇异摄动鲁棒自适应PD控制

1 双臂机器人动力学模型 对于一个具有多个关节的机器人来说&#xff0c;机器人端动力学子方程及关节驱动电机端动力学子方程为&#xff1a; 以上为推导过程&#xff0c;MATLAB程序已完成&#xff0c;若需要可找我。...

遵循IEC62304YY/T0664:确保医疗器械软件生命周期合规性

一、EC 62304与YY/T 0664的核心定位与关系 IEC 62304&#xff08;IEC 62304&#xff09;是国际通用的医疗器械软件生命周期管理标准&#xff0c;适用于所有包含软件的医疗器械&#xff08;如嵌入式软件、独立软件、移动应用等&#xff09;&#xff0c;其核心目标是确保软件的安…...

Kafka和RocketMQ相比有什么区别?那个更好用?

Kafka和RocketMQ相比有什么区别?那个更好用? Kafka 和 RocketMQ 都是广泛使用的消息队列系统&#xff0c;它们有很多相似之处&#xff0c;但也有一些关键的区别。具体选择哪个更好用&#xff0c;要根据你的应用场景和需求来决定。以下是它们之间的主要区别&#xff1a; 1. …...

空对象模式(Null Object Pattern)在C#中的实现详解

一 、什么是空对象模式 空对象模模是靠”空对孔象式是书丯一种引施丼文行为,行凌,凌万成,个默疤"空象象象象来飞䛿引用用用用电从延盈盈甘仙丿引用用用职从延务在仅代砷易行行 」这种燕式亲如要目的片片 也说媚平父如如 核心思烟 定义一个人 派一个 &#xfffd; 创建…...

【Windows】Win2008服务器SQL服务监控重启脚本

以下是一个用于监控并自动重启 SQL Server 服务的批处理脚本&#xff0c;适用于 Windows Server 2008 和 SQL Server 2012&#xff08;默认实例&#xff09;&#xff1a; echo off setlocal enabledelayedexpansion:: 配置参数 set SERVICE_NAMEMSSQLSERVER set LOG_FILEC:\SQ…...

Spring MVC 操作会话属性详解(@SessionAttributes 与 @SessionAttribute)

Spring MVC 操作会话属性详解&#xff08;SessionAttributes 与 SessionAttribute&#xff09; 1. 核心注解对比 注解作用范围功能SessionAttributes类级别声明控制器中需要持久化的模型属性&#xff08;存入 HttpSession&#xff09;SessionAttribute方法参数/返回值显式绑定…...

416. 分割等和子集

416. 分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] 和…...

Composer安装Laravel步骤

Composer安装Laravel步骤 要使用 Composer 安装 Laravel&#xff0c;请按照以下步骤操作&#xff1a; 确保已经安装了 Composer。如果还没有安装&#xff0c;请访问 https://getcomposer.org/download/ 下载并安装。 打开命令行或终端。 使用 cd 命令导航到你的项目目录&…...

游戏引擎学习第209天

调整椅子α 昨天&#xff0c;我们实现了将数据输出到调试流中的功能&#xff0c;之前的调试流大多只包含性能分析数据&#xff0c;而现在我们可以将任意数据放入调试流中。 完成这个功能后&#xff0c;我们接下来要做的是收集这些数据并显示出来&#xff0c;这样我们就能有一…...

更新vscode后链接远程服务器出现了报错‘无法建立连接:远程主机不满足运行vscode服务器的先决条件’20250408

更新了vscode之后再链接远程服务器出现了报错&#xff0c;如下&#xff1a; 1. 确认服务器上的库版本 1.1 检查 glibc 版本 在服务器终端运行&#xff1a; ldd --version 最低要求&#xff1a;VS Code 远程开发需要 glibc ≥ 2.28。 1.2 检查 libstdc 版本 在服务器终端运…...

电磁兼容特种测试

并非所有的检测都能在实验室的标准场地中完成。今天&#xff0c;就带大家走进电磁兼容特种测试中需要现场测试的情况&#xff0c;看看哪些场合和设备有着特殊的测试需求。 哪种场合需要现场测试&#xff1f; 大型设备由于物理尺寸或供电功率上的限制&#xff0c;无法在一般…...

PyTorch 基础要点详解:从模型构建到评估

在深度学习领域&#xff0c;PyTorch 作为一款广受欢迎的开源框架&#xff0c;为开发者提供了便捷高效的工具。今天&#xff0c;我们就深入探讨一下 PyTorch 中的几个关键要点&#xff1a;torch.nn.Linear、torch.nn.MSELoss、model.train() 以及 model.eval()&#xff0c;了解它…...

Dockerfile中CMD命令未生效

今天在使用dockerfile构建容器镜像时&#xff0c;最后一步用到CMD命令启动start.sh&#xff0c;但是尝试几遍都未能成功执行脚本。最后查阅得知&#xff1a;Dockerfile中可以有多个cmd指令&#xff0c;但只有最后一个生效&#xff0c;CMD会被docker run之后的参数替换。 CMD会…...

Linux平台MQTT测试抓包分析

Linux平台搭建MQTT测试环境-CSDN博客基于这里的测试代码抓包 sudo tcpdump -i any -w mqtt1.cap 上述源码中 tcp://localhost:1883 配置连接&#xff1a; Broker Address: localhostPort: 1883 整体通信流程 1. Subscriber和Broker&#xff08;代理服务器&#xff09;建立…...

Docker全方位指南

目录 前言 第一部分&#xff1a;Docker基础与安装 1.1 什么是Docker&#xff1f; 1.2 Docker的适用场景 1.3 全平台安装指南 1.4 配置优化 第二部分&#xff1a;Docker核心操作与原理 2.1 镜像管理 2.2 容器生命周期 2.3 网络模型 2.4 Docker Compose 第三部分&…...

【经典DP】三步问题 / 整数拆分 / 不同路径II / 过河卒 / 下降路径最小和 / 地下城游戏

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;动态规划 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 动态规划总结Fibonacci数列BC140 杨辉三角杨辉三角三步问题最小花费爬楼梯孩子们的游戏解码方法整数拆分不同路径不同路径II过…...

Koji/OBS编译节点OS版本及工具版本管理深度实践指南

引言 在分布式编译框架Koji/OBS中&#xff0c;有效管理编译节点的操作系统&#xff08;OS&#xff09;版本及工具版本是确保构建环境稳定性、兼容性和安全性的关键。本文将从多版本共存、自动化更新、兼容性管理等多个维度&#xff0c;系统阐述如何高效管理编译节点的OS版本及…...

39、web前端开发之Vue3保姆教程(三)

四、Vue3中集成Element Plus 1、什么是Element Plus Element Plus 是一款基于 Vue 3 的开源 UI 组件库,旨在为开发者提供一套高质量、易用的组件,用于快速构建现代化的 web 应用程序。 Element Plus 提供了大量的 UI 组件,包括但不限于: 表单组件:输入框、选择器、开关…...

多类型医疗自助终端智能化升级路径(代码版.下)

医疗人机交互层技术实施方案 一、多模态交互体系 1. 医疗语音识别引擎 # 基于Wav2Vec2的医疗ASR系统 from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC import torchaudioclass MedicalASR:def __init__(self):self.processor = Wav2Vec2Processor.from_pretrai…...

Git代码管理

这里写目录标题 分支管理策略TrunkBased&#x1f331; 核心理念✅优点❌缺点适用场景 GitFlow✅ GitFlow 的优点❌ GitFlow 的缺点适用场景 AOneFlow✅ AOneFlow 的优点❌缺点适用场景 如何选择分支策略&#xff1f;代码提交规范&#x1f331;分支管理&#x1f504;代码更新⚔️…...

CubeMX配置STM32F103PWM连续频率输出

要求&#xff1a; 输出2-573Hz频率&#xff0c;输出频率步长小于1Hz 一、CubeMX配置 auto-reload preload在下个周期加载ARR Output compare preload 在下个周期加载CCR 二、 程序 1.启动PWM输出 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); 2.根据频率调整PSC、ARR、…...

举例说明计算机视觉(CV)技术的优势和挑战。

计算机视觉(CV)技术是人工智能领域的一个重要分支,通过让计算机“看”和“理解”图像或视频,可以实现许多实际应用。以下是计算机视觉技术的优势和挑战的例子: 优势: 自动化处理:CV技术可以自动化地处理大量图像或视频数据,实现快速而准确的分析和识别。提高效率:在许…...