python学智能算法(八)|决策树

【1】引言

前序学习进程中,已经对KNN邻近算法有了探索,相关文章链接为:

python学智能算法(七)|KNN邻近算法-CSDN博客

但KNN邻近算法有一个特点是:它在分类的时候,不能知晓每个类别内事物的具体面貌,只能获得类别,停留在事物的表面。

为了进一步探索事物的内在特征,就需要学习新的算法。

本篇文章就是在KNN的基础上学习新算法:决策树。

【2】原理分析

在学习决策树执之前,需要先了解香农熵。

本科学控制课,老师讲到香农熵,那时候啥也不懂,以为就是个普通公式,多年以后,看到这三个字难免感慨当年太过幼稚。

【2.1】香农熵

香农熵比较简单,从数学层面上看就是对数求和。

这是香农熵的求解代码:

import numpy as np
from math import log #引入log()函数求对数# 定义一个嵌套列表
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 ShannonEnt
dataset,labels=creatDataset()
ShannonEnt=calcShannonEnt(dataset)
print('ShannonEnt=',ShannonEnt)

整体代码非常简单,总结起来就是一个公式:

代码中需要注意的是:dataset是一个嵌套列表,labelcounts是一个字典。

【2.2】数据集划分

数据集划分,目的是找出某些关键特征后,将其删除。

# 定义一个嵌套列表
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# 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中刚好没有第axis+1个元素retdataset.append(reducedfeatvec)return retdatasetdataset, labels = creatDataset()
retdataset = splitdataset(dataset, 0,1)
retdataset1 = splitdataset(dataset, 1,1)
retdataset2 = splitdataset(dataset, 1,0)
print("retdataset:", retdataset)
print("retdataset1:", retdataset1)
print("retdataset2:", retdataset2)

数据集划分只用了一个for循环加if判断就能实现,划分的原理是:对于每一行元素,如果指定列的元素和指定数据相等,就把这个相等的元素挑出去,然后把这行数据剩下的部分添加到一个新的列表里;如果指定列的元素和指定数据不相等,这一行数据会直接略过。

上述代码运行的效果是:

retdataset: [[1, 'yes'], [1, 'yes'], [0, 'no']]
retdataset1: [[1, 'yes'], [1, 'yes'], [0, 'no'], [0, 'no']]
retdataset2: [[1, 'no']]

【2.3】特征选择

数据集划分后,序言按照制定的特征作为依据,判断这个特征指向的样本对应的香农熵。

要想理解特征选择的意义,需要把前面的香农熵计算和数据集划分子函数都一起写进来:

from math import log  # 引入log()函数求对数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是具体的香农熵求解函数
# 实际上calcShannonEnt是dataset最后一列的香农熵
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 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中刚好没有第axis+1个元素retdataset.append(reducedfeatvec)return retdataset# choosebestfeaturetosplit计算的香农熵对象元素是dataset最后一列对应的元素
def 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的形式提取# 每一行位置索引为i的元素赋值给featlist# 这个嵌套列表,因为for的存在,把dataset每一行和位置索引为i的元素赋值给featlist# featlist存储的元素数量和dataset的函数一致# featlist作为列表没有提前预定义,此处定义这个量和定义如何取值一起出现featlist = [example[i] for example in dataset]# set是一个内置函数,将featlist这个列表转化为集合# 集合具有合并同类项的作用,重复的元素只会保留一个uniquevals = set(featlist)# 定义一个常数newentropy = 0.0# 对于uniquevals中的每一个值# uniquevals执行过程中,相当于把整个dataset计算获得的uniquevals进行遍历# value是uniquevals中的具体元素,也是列位置索引为i的dataset取到的值for value in uniquevals:# 调用splitdataset对dataset进行子集划分# 子集划分的列数和获得uniquevals的列数一致,value是uniquevals的存储值# subdataset不会是空值subdataset = splitdataset(dataset, i, value)# 获取每一个元素的香农熵# 需要注意的是,在每一个i的取值范围内,都会执行subdataset操作# subdataset是按照列元素进行的集合划分# 这个prob实际上是针对列元素展开的,有多少列,就会有多少次prob计算# prob实际上代表的是subdataset行数和dataset行数的比例prob = len(subdataset) / float(len(dataset))# 更新香农熵# calcShannonEnt(subdataset)计算了subdataset的最后一列的香农熵# newtropy是prob这个比例和对应香农熵的乘积newentropy += prob * calcShannonEnt(subdataset)# 获得香农熵的变化量# baseentroy是dataset的香农熵# newtropy是第i列元素为特征进行集合划分之后,对新集合开展的香农熵计算和新集合数量比例的乘积infogain = baseentroy - newentropy# 如果变化量超过阈值if (infogain > bestinfogain):# 新变化=变化量bestinfogain = infogain# 给bestfeature赋值ibestfeature = ireturn bestfeaturedataset, labels = creatDataset()
ShannonEnt=calcShannonEnt(dataset)
print('ShannonEnt=',ShannonEnt)
bestfeature=choosebestfeaturetosplit(dataset)
print('bestfeature=',bestfeature)

但在前面理解的基础上,可以先记住两条原则:

  1. 香农熵是以一行数据列表的最后一列为计算依据,开展的对数运算;
  2. 数据计划分时,会把特征这个依据从一行数据列表中删除。

而为了理解特征选择子函数choosebestfeaturetosplit(dataset),需要把这个函数分作三部分。

【2.3.1】准备部分

    # 对dataset第0行求长度,获得列数,然后再减去1numfeatures = len(dataset[0]) - 1# 调用函数calcShannonEnt获得dataset的香农熵baseentroy = calcShannonEnt(dataset)# 定义一个常数bestinfogain = 0.0# 定义一个常数bestfeature = -1

准备部分获得一些备用值:

numfeatures = len(dataset[0]) - 1,对应的是dataset列表的列数-1;

baseentroy = calcShannonEnt(dataset),是对dataset计算香农熵;

bestinfogain = 0.0和bestfeature = -1都是直接赋值。

【2.3.2】特征值提取

# 对于numfeatures中的每一个数# numfeatures比dataset的列数少一个for i in range(numfeatures):# 对于每一行在dataset中的元素,按照列位置索引为i的形式提取# 每一行位置索引为i的元素赋值给featlist# 这个嵌套列表,因为for的存在,把dataset每一行和位置索引为i的元素赋值给featlist# featlist存储的元素数量和dataset的函数一致# featlist作为列表没有提前预定义,此处定义这个量和定义如何取值一起出现featlist = [example[i] for example in dataset]# set是一个内置函数,将featlist这个列表转化为集合# 集合具有合并同类项的作用,重复的元素只会保留一个uniquevals = set(featlist)# 定义一个常数newentropy = 0.0# 对于uniquevals中的每一个值# uniquevals执行过程中,相当于把整个dataset计算获得的uniquevals进行遍历# value是uniquevals中的具体元素,也是列位置索引为i的dataset取到的值

在特征值提取部分,featlist通过嵌套for循环来提取了特征,然后通过set函数做了合并同类型操作。

featlist本质上是对dataset的列数据进行了提取,然后再合并同类项。

注意newtropy在每列特征值获得后,初始值都是0.0。

【2.3.3】特征值香农熵

        for value in uniquevals:# 调用splitdataset对dataset进行子集划分# 子集划分的列数和获得uniquevals的列数一致,value是uniquevals的存储值# subdataset不会是空值subdataset = splitdataset(dataset, i, value)# 获取每一个元素的香农熵# 需要注意的是,在每一个i的取值范围内,都会执行subdataset操作# subdataset是按照列元素进行的集合划分# 这个prob实际上是针对列元素展开的,有多少列,就会有多少次prob计算# prob实际上代表的是subdataset行数和dataset行数的比例prob = len(subdataset) / float(len(dataset))# 更新香农熵# calcShannonEnt(subdataset)计算了subdataset的最后一列的香农熵# newtropy是prob这个比例和对应香农熵的乘积newentropy += prob * calcShannonEnt(subdataset)

在获得特征值之后,以每一个特征值为依据,对取得特征值的列进行数据集划分。

也就是在某列取得特征值,这一列的数据就会被提取出来参与数据集划分。

对于每一个特征值对应的数据集,都要依据最后一列元素计算香农熵,然后这个香农熵还要和每个数据集行数占整个dataset行数的比例相乘。实际上,每个数据集的行数就代表了这个特征值在dataset的第i列中出现的次数。

需要注意的是,newentropy需要把第i列获得的所有特征值对应的数据集的香农熵都算一遍再叠加在一起。

【2.3.4】特征值香农熵变化量

# 获得香农熵的变化量# baseentroy是dataset的香农熵# newtropy是第i列元素为特征进行集合划分之后,对新集合开展的香农熵计算和新集合数量比例的乘积infogain = baseentroy - newentropy

这一步相对来说比较简单,用整个数据集dataset的香农熵减去特征值数据集的香农熵,获得一个当前熵增益。

【2.3.5】最佳熵增益

        if (infogain > bestinfogain):# 新变化=变化量bestinfogain = infogain# 给bestfeature赋值ibestfeature = i

如果当前熵增益>最佳熵增益,就把当前熵增益赋值给最佳熵增益,记录此时特征值在dataset中的列数。

总体而言,对于最佳列数的选择,是对dataset除最后一列之外的每一列元素都进行特征值选择,再计算香农熵后做出的选择。

当它们偏离dataset香农熵越远,被选中的概率越大。

【2.4】多数表决

def 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]

对于多数表决部分,相对比较简单,整体上是一个排序的目标。

整个函数的输入参数其实也是列表,需要计算出列表中有多少个键值,然后对键值进行从大到小的排序即可,整个函数只返回最大值。

【2.5】获得决策树

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

获得决策树的部分相对复杂一些,下一篇文章对整体做结构分析,到时候详细说明。

此时的完整代码为:

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)

【3】总结

学习了决策树的基础知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 OpenCV 拼接进行图像处理对比:以形态学操作为例

图像处理在计算机视觉中起着至关重要的作用,而 OpenCV 作为一个强大的图像处理库,提供了丰富的函数来实现各类图像处理任务。形态学操作(Morphological Operations)是其中常用的技术,尤其适用于二值图像的处理。常见的…

版本控制器Git ,Gitee如何连接Linux Gitee和Github区别

📖 示例场景 假设你和朋友在开发一个「在线笔记网站」,代码需要频繁修改和协作: 只用本地文件管理 每次修改后手动复制文件,命名为 v1.html、v2.html 问题:无法追踪具体改动内容;多人修改易冲突&#xff1…

使用DeepSeek翻译英文科技论文,以MarkDown格式输出,使用Writage 3.3.1插件转换为Word文件

一、使用DeepSeek翻译英文科技论文,以MarkDown格式输出 以科技论文“Electrical Power System Sizing within the Numerical Propulsion System Simulation”为例。 关于Writage 3.3.1的进一步了解,可发送邮件至邮箱pyengine163.com. 首先,打…

【NPU 系列专栏 3.0 -- scale-out 和 scale-in 和 scale-up 和 scale-down

文章目录 Overview1. Scale-out 和 Scale-in (横向扩展/缩减)举例:AI SoC 中的 Scale-out 和 Scale-in2. Scale-up 和 Scale-down (纵向扩展/缩减)举例:AI SoC 中的 Scale-up 和 Scale-down对比总结Overview 本文会 以 AI SoC 为例 详细介绍什么是 scale-out 和 scale-i…

Spring Boot 集成 Quartz 实现定时任务(Cron 表达式示例)

Spring Boot 集成 Quartz 实现定时任务(Cron 表达式示例) 前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Spring Boot 观察定时任务执行5. Quartz Cron 表达式详解6. 结论 前言 在 Spring Boot 项目中,我们经常…

智能汽车图像及视频处理方案,支持视频智能拍摄能力

美摄科技,作为智能汽车图像及视频处理领域的先行者,凭借其卓越的技术实力和前瞻性的设计理念,为全球智能汽车制造商带来了一场视觉盛宴的革新。我们自豪地推出——美摄科技智能汽车图像及视频处理方案,一个集高效性、智能化、画质…

QPrintDialog弹出慢的问题

开发环境 操作系统: openkylin2qt版本 : 5.15.10排查过程 首先看下问题的现象, 问题现象 复现问题的demo很简单,只能是从跟踪qt代码方面入手 void MainWindow::on_pushButton_clicked(){QPrinter printer;QPrintDialog dialog(&printer,this);dialog.exec();} 现在需要找一…

VLAN:逻辑隔离冲突网络的详细讲解

1. VLAN的基本概念 VLAN(Virtual Local Area Network,虚拟局域网) 是一种将物理网络划分为多个逻辑独立网络的技术。通过VLAN,不同逻辑网络可以在同一物理网络基础设施上运行,彼此隔离,互不影响。 核心功能…

投影算子(Projection Operator)的定义、性质、分类以及应用

文章目录 1. 投影算子的定义2. 投影算子的几何意义3. 一些简单的例子例 1:二维平面上的投影例 2:投影到一条任意方向的直线例 3:三维空间中投影到一个平面 4. 投影算子的性质4.1、幂等性(Idempotency): P 2…

java使用Apache POI 操作word文档

项目背景: 当我们对一些word文档(该文档包含很多的标题比如 1.1 ,1.2 , 1.2.1.1, 1.2.2.3)当我们删除其中一项或者几项时,需要手动的对后续的进行补充。该功能主要是对标题进行自动的补充。 具…

接收与发送ipv6数据包

一、ipv6的概念 IPv6 是英文 “Internet Protocol Version 6”(互联网协议第 6 版)的缩写,是互联网工程任务组(IETF)设计的用于替代 IPv4 的下一代 IP 协议,其地址数量号称可以为全世界的每一粒沙子编上…

龙虎榜——20250321

今日A股龙虎榜方向分析 根据2025年3月21日龙虎榜数据(涨停56家,跌停31家),市场呈现结构性分化行情,资金聚焦海洋经济、机器人、锂电等主线,部分个股遭机构大幅抛售。以下是具体方向解析: 一、资…

springboot milvus search向量相似度查询 踩坑使用经验

1.前提提要:java的pom 版本为:2.4.9 milvus 版本是:2.4.13-hotfix 2.先来工具类方法 /*** 向量搜索* param client* param query* return*/public SearchResp search(NonNull MilvusClientV2 client, NonNull VectorCondition query) {final …

[网络安全] 滥用Azure内置Contributor角色横向移动至Azure VM

本文来源于团队的超辉老师,其系统分析了Azure RBAC角色模型及其在权限滥用场景下的攻击路径。通过利用AADInternals工具提升用户至Contributor角色,攻击者可在Azure VM中远程执行命令,创建后门账户,实现横向移动。文中详述了攻击步…

Android Compose 基础布局之 Box 和 Stack 源码深度剖析(九)

Android Compose 基础布局之 Box 和 Stack 源码深度剖析 一、引言 1.1 Android 开发中布局的重要性 在 Android 应用开发里,布局是构建用户界面(UI)的关键环节。良好的布局设计能够提升用户体验,使应用界面更加美观、易用且具有…

知识蒸馏:让大模型“瘦身“而不失智慧的魔术

引言:当AI模型需要"减肥" 在人工智能领域,一个有趣的悖论正在上演:大模型的参数规模每年以10倍速度增长,而移动设备的算力却始终受限。GPT-4的1750亿参数需要价值500万美元的GPU集群运行,但现实中的智能设备…

多路FM调频广播解调器:多路电台FM广播信号一体化解调处理方案

多路FM调频广播解调器:多路电台FM广播信号一体化解调处理方案 支持OEM型号开放式协议支持二次开发设计 北京海特伟业科技有限公司任洪卓发布于2025年3月21日 在信息传播领域,FM调频广播媒体以其独特的优势持续发挥着重要作用。为了应对日益增长的多路…

如何在Spring Boot中设置HttpOnly Cookie以增强安全性

引言 在Web开发中,Cookie是用于在客户端和服务器之间传递信息的重要机制。然而,Cookie的安全性一直是一个备受关注的问题。特别是当Cookie中存储了敏感信息(如会话ID)时,如何防止这些信息被恶意脚本窃取就显得尤为重要。HttpOnly属性是增强Cookie安全性的一种有效手段。本…

LangManus:新一代开源智能体框架如何让AI开发更简单?

你是否想过,代码生成、数据分析甚至系统调试,都能由一个“AI助手”自动完成?最近,一款名为LangManus的开源项目在开发者社区掀起热议。它不只是一个工具库,更是一个能自主思考、执行复杂任务的智能体框架。无论是企业内…

【STM32】SPI通信协议W25Q64Flash存储器芯片(学习笔记)

通信接口部分有介绍SPI:【STM32】USART串口协议&串口外设-学习笔记-CSDN博客 SPI通信协议 SPI通信 SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线四根通信线:SCK(Serial Clock&…