树回归CART
之前线性回归创建的模型需要拟合所有的样本点,但数据特征众多,关系复杂时,构建全局模型就很困难。之前构建决策树使用的算法是ID3。
ID3 的做法是每次选取当前最佳的特征来分割数据,并按照该特征的所有可能取值来切分。也就是说,如果一个特征有 4 种取值,那么数据将被切分成 4 份。一旦按照某特征切分后,该特征在之后的算法执行过程中将不会再起作用,所以有观点认为这种切分方式过于迅速。另外一种方法是二元切分法,即每次把数据集切分成两份。如果数据的某特征值等于切分所要求的值,那么这些数据就进入树的左子树,反之则进入树的右子树。
除了切分过于迅速外, ID3 算法还存在另一个问题,它不能直接处理连续型特征。只有事先将连续型特征转换成离散型,才能在 ID3 算法中使用。但这种转换过程会破坏连续型变量的内在性质。而使用二元切分法则易于对树构造过程进行调整以处理连续型特征。具体的处理方法是: 如果特征值大于给定值就走左子树,否则就走右子树。另外,二元切分法也节省了树的构建时间,但这点意义也不是特别大,因为这些树构建一般是离线完成,时间并非需要重点关注的因素。
CART 是十分著名且广泛记载的树构建算法,它使用二元切分来处理连续型变量。对 CART 稍作修改就可以处理回归问题。决策树中使用香农熵来度量集合的无组织程度。如果选用其他方法来代替香农熵,就可以使用树构建算法来完成回归。
回归树与分类树的思路类似,但是叶节点的数据类型不是离散型,而是连续型。
还有一点要说明,构建决策树算法,常用到的是三个方法: ID3, C4.5, CART.
三种方法区别是划分树的分支的方式:
- ID3 是信息增益分支
- C4.5 是信息增益率分支
- CART 做分类工作时,采用 GINI 值作为节点分裂的依据;回归时,采用样本的最小方差作为节点的分裂依据。
工程上总的来说:
CART 和 C4.5 之间主要差异在于分类结果上,CART 可以回归分析也可以分类,C4.5 只能做分类;C4.5 子节点是可以多分的,而 CART 是无数个二叉子节点;
以此拓展出以 CART 为基础的 “树群” Random forest , 以 回归树 为基础的 “树群” GBDT 。
树剪枝
一棵树如果节点过多,表明该模型可能对数据进行了 “过拟合”。
通过降低决策树的复杂度来避免过拟合的过程称为 剪枝(pruning)
。在函数 chooseBestSplit() 中提前终止条件,实际上是在进行一种所谓的 预剪枝(prepruning)
操作。另一个形式的剪枝需要使用测试集和训练集,称作 后剪枝(postpruning)
。
预剪枝(prepruning)
顾名思义,预剪枝就是及早的停止树增长,在构造决策树的同时进行剪枝。
所有决策树的构建方法,都是在无法进一步降低熵的情况下才会停止创建分支的过程,为了避免过拟合,可以设定一个阈值,熵减小的数量小于这个阈值,即使还可以继续降低熵,也停止继续创建分支。但是这种方法实际中的效果并不好。
后剪枝(postpruning)
决策树构造完成后进行剪枝。剪枝的过程是对拥有同样父节点的一组节点进行检查,判断如果将其合并,熵的增加量是否小于某一阈值。如果确实小,则这一组节点可以合并一个节点,其中包含了所有可能的结果。合并也被称作 塌陷处理
,在回归树中一般采用取需要合并的所有子树的平均值。后剪枝是目前最普遍的做法。
模型树
用树来对数据建模,除了把叶节点简单地设定为常数值之外,还有一种方法是把叶节点设定为分段线性函数,这里所谓的 分段线性(piecewise linear)
是指模型由多个线性片段组成。
from __future__ import print_function
from Tkinter import *
from numpy import *# 默认解析的数据是用tab分隔,并且是数值类型
# general function to parse tab -delimited floats
def loadDataSet(fileName):"""loadDataSet(解析每一行,并转化为float类型)Desc: 该函数读取一个以 tab 键为分隔符的文件,然后将每行的内容保存成一组浮点数Args:fileName 文件名Returns:dataMat 每一行的数据集array类型Raises:"""# 假定最后一列是结果值# assume last column is target valuedataMat = []fr = open(fileName)for line in fr.readlines():curLine = line.strip().split('\t')# 将所有的元素转化为float类型# map all elements to float()# map() 函数具体的含义,可见 https://my.oschina.net/zyzzy/blog/115096fltLine = map(float, curLine)dataMat.append(fltLine)return dataMatdef binSplitDataSet(dataSet, feature, value):"""binSplitDataSet(将数据集,按照feature列的value进行 二元切分)Description: 在给定特征和特征值的情况下,该函数通过数组过滤方式将上述数据集合切分得到两个子集并返回。Args:dataMat 数据集feature 待切分的特征列value 特征列要比较的值Returns:mat0 小于等于 value 的数据集在左边mat1 大于 value 的数据集在右边Raises:"""# # 测试案例# print 'dataSet[:, feature]=', dataSet[:, feature]# print 'nonzero(dataSet[:, feature] > value)[0]=', nonzero(dataSet[:, feature] > value)[0]# print 'nonzero(dataSet[:, feature] <= value)[0]=', nonzero(dataSet[:, feature] <= value)[0]# dataSet[:, feature] 取去每一行中,第1列的值(从0开始算)# nonzero(dataSet[:, feature] > value) 返回结果为true行的index下标mat0 = dataSet[nonzero(dataSet[:, feature] <= value)[0], :]mat1 = dataSet[nonzero(dataSet[:, feature] > value)[0], :]return mat0, mat1# 返回每一个叶子结点的均值
# returns the value used for each leaf
# 我的理解是: regLeaf 是产生叶节点的函数,就是求均值,即用聚类中心点来代表这类数据
def regLeaf(dataSet):return mean(dataSet[:, -1])# 计算总方差=方差*样本数
# 我的理解是: 求这组数据的方差,即通过决策树划分,可以让靠近的数据分到同一类中去
def regErr(dataSet):# shape(dataSet)[0] 表示行数return var(dataSet[:, -1]) * shape(dataSet)[0]# 1.用最佳方式切分数据集
# 2.生成相应的叶节点
def chooseBestSplit(dataSet,leafType=regLeaf,errType=regErr,ops=(1,4)):'''chooseBestSplit(用最佳方式切分数据集 和 生成相应的叶节点)Args:dataSet 加载的原始数据集leafType 建立叶子点的函数errType 误差计算函数(求总方差)ops [容许误差下降值,切分的最少样本数]。Returns:bestIndex feature的index坐标bestValue 切分的最优值Raises:'''#ops=(1,4),非常重要,因为它决定了决策树划分停止的threshold值,被称为预剪枝(prepruning),其实也就是用于控制函数的停止时机。# 之所以这样说,是因为它防止决策树的过拟合,所以当误差的下降值小于tolS,或划分后的集合size小于tolN时,选择停止继续划分。# 最小误差下降值,划分后的误差减小小于这个差值,就不用继续划分tolS=ops[0]# 划分最小 size 小于,就不继续划分了tolN=ops[1]# 如果结果集(最后一列为1个变量),就返回退出# .T 对数据集进行转置# .tolist()[0] 转化为数组并取第0列if len(set(dataSet[:,-1].T.tolist()[0]))==1:# 如果集合size为1,也就是说全部的数据都是同一个类别,不用继续划分。# exit cond 1return None,leafType(dataSet)# 计算行列值m,n=shape(dataSet)# 无分类误差的总方差和# the choice of the best feature is driven by Reduction in RSS error from meanS=errType(dataSet)# inf 正无穷大bestS, bestIndex, bestValue = inf, 0, 0# 循环处理每一列对应的feature值for featIndex in range(n-1): # 对于每个特征# [0]表示这一列的[所有行],不要[0]就是一个array[[所有行]],下面的一行表示的是将某一列全部的数据转换为行,然后设置为list形式for splitVal in set(dataSet[:,featIndex].T.tolist()[0]):# 对该列进行分组,然后组内成员的val值进行二元切分mat0,mat1=binSplitDataSet(dataSet,featIndex,splitVal)# 判断二元切分的方式的元素数量是否符合预期if(shape(mat0)[0]<tolN)or(shape(mat1)[0]<tolN):continuenewS=errType(mat0)+errType(mat1)# 如果二元切分,算出来的误差在可接受范围内,那么就记录切分点,并记录最小误差# 如果划分后误差小于 bestS,则说明找到了新的bestSif newS < bestS:bestIndex = featIndexbestValue = splitValbestS = newS# 判断二元切分的方式的元素误差是否符合预期# if the decrease (S-bestS) is less than a threshold don't do the splitif (S - bestS) < tolS:return None, leafType(dataSet)mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)# 对整体的成员进行判断,是否符合预期# 如果集合的 size 小于 tolN if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): # 当最佳划分后,集合过小,也不划分,产生叶节点return None, leafType(dataSet)return bestIndex, bestValue# assume dataSet is NumPy Mat so we can array filtering
# 假设 dataSet 是 NumPy Mat 类型的,那么我们可以进行 array 过滤
def createTree(dataSet,leafType=regLeaf,errType=regErr,ops=(1,4)):"""createTree(获取回归树)Description: 递归函数: 如果构建的是回归树,该模型是一个常数,如果是模型树,其模型师一个线性方程。Args:dataSet 加载的原始数据集leafType 建立叶子点的函数errType 误差计算函数ops=(1, 4) [容许误差下降值,切分的最少样本数]Returns:retTree 决策树最后的结果"""# 选择最好的切分方式: feature索引值,最优切分值# choose the best splitfeat,val=chooseBestSplit(dataSet,leafType,errType,ops)# if the splitting hit a stop condition return val# 如果 splitting 达到一个停止条件,那么返回 val'''*** 最后的返回结果是最后剩下的 val,也就是len小于topN的集合'''if feat is None:return valretTree={}retTree['spInd']=featretTree['spVal']=val# 大于在右边,小于在左边,分为2个数据集lSet,rSet=binSplitDataSet(dataSet,feat,val)# 递归的进行调用,在左右子树中继续递归生成树retTree['left'] = createTree(lSet, leafType, errType, ops)retTree['right'] = createTree(rSet, leafType, errType, ops)return retTree# 判断节点是否是一个字典
def isTree(obj):"""Desc:测试输入变量是否是一棵树,即是否是一个字典Args:obj -- 输入变量Returns:返回布尔类型的结果。如果 obj 是一个字典,返回true,否则返回 false"""return (type(obj).__name__=='dict')# 计算左右枝丫的均值
def getMean(tree):"""Desc:从上往下遍历树直到叶节点为止,如果找到两个叶节点则计算它们的平均值。对 tree 进行塌陷处理,即返回树平均值。Args:tree -- 输入的树Returns:返回 tree 节点的平均值"""if isTree(tree['right']):tree['right']=getMean(tree['right'])if isTree(tree['left']):tree['left']=getMean(tree['left'])return (tree['left']+tree['right'])/2.0# 检查是否适合合并分枝
def prune(tree, testData):"""Desc:从上而下找到叶节点,用测试数据集来判断将这些叶节点合并是否能降低测试误差Args:tree -- 待剪枝的树testData -- 剪枝所需要的测试数据 testData Returns:tree -- 剪枝完成的树"""# 判断是否测试数据集没有数据,如果没有,就直接返回tree本身的均值if shape(testData)[0]==0:return getMean(tree)# 判断分枝是否是dict字典,如果是就将测试数据集进行切分if(isTree(tree['right'])or isTree(tree['left'])):lSet,rSet=binSplitDataSet(testData,tree['spInd'],tree['spVal'])# 如果是左边分枝是字典,就传入左边的数据集和左边的分枝,进行递归if isTree(tree['left']):tree['left'] = prune(tree['left'], lSet)# 如果是右边分枝是字典,就传入左边的数据集和左边的分枝,进行递归if isTree(tree['right']):tree['right'] = prune(tree['right'], rSet)# 上面的一系列操作本质上就是将测试数据集按照训练完成的树拆分好,对应的值放到对应的节点# 如果左右两边同时都不是dict字典,也就是左右两边都是叶节点,而不是子树了,那么分割测试数据集。# 1. 如果正确 # * 那么计算一下总方差 和 该结果集的本身不分枝的总方差比较# * 如果 合并的总方差 < 不合并的总方差,那么就进行合并# 注意返回的结果: 如果可以合并,原来的dict就变为了 数值if not isTree(tree['left']) and not isTree(tree['right']):lSet,rSet=binSplitDataSet(testData,tree['spInd'],tree['spVal'])# power(x, y)表示x的y次方;这时tree['left']和tree['right']都是具体数值errorNoMerge = sum(power(lSet[:, -1] - tree['left'], 2)) + sum(power(rSet[:, -1] - tree['right'], 2))treeMean = (tree['left'] + tree['right'])/2.0errorMerge = sum(power(testData[:, -1] - treeMean, 2))# 如果 合并的总方差 < 不合并的总方差,那么就进行合并if errorMerge < errorNoMerge:print("merging")return treeMean# 两个return可以简化成一个else:return treeelse:return tree# 得到模型的ws系数: f(x) = x0 + x1*featrue1+ x2*featrue2 ...
# create linear model and return coeficients
def modelLeaf(dataSet):"""Desc:当数据不再需要切分的时候,生成叶节点的模型。Args:dataSet -- 输入数据集Returns:调用 linearSolve 函数,返回得到的 回归系数ws"""ws, X, Y = linearSolve(dataSet)return ws# 计算线性模型的误差值
def modelErr(dataSet):"""Desc:在给定数据集上计算误差。Args:dataSet -- 输入数据集Returns:调用 linearSolve 函数,返回 yHat 和 Y 之间的平方误差。"""ws, X, Y = linearSolve(dataSet)yHat = X * ws# print corrcoef(yHat, Y, rowvar=0)return sum(power(Y - yHat, 2))# helper function used in two places
def linearSolve(dataSet):"""Desc:将数据集格式化成目标变量Y和自变量X,执行简单的线性回归,得到wsArgs:dataSet -- 输入数据Returns:ws -- 执行线性回归的回归系数 X -- 格式化自变量XY -- 格式化目标变量Y"""m, n = shape(dataSet)# 产生一个关于1的矩阵X = mat(ones((m, n)))Y = mat(ones((m, 1)))# X的0列为1,常数项,用于计算平衡误差X[:, 1: n] = dataSet[:, 0: n-1]Y = dataSet[:, -1]# 转置矩阵*矩阵xTx = X.T * X# 如果矩阵的逆不存在,会造成程序异常if linalg.det(xTx) == 0.0:raise NameError('This matrix is singular, cannot do inverse,\ntry increasing the second value of ops')# 最小二乘法求最优解: w0*1+w1*x1=yws = xTx.I * (X.T * Y)return ws, X, Y# 回归树测试案例
# 为了和 modelTreeEval() 保持一致,保留两个输入参数
def regTreeEval(model, inDat):"""Desc:对 回归树 进行预测Args:model -- 指定模型,可选值为 回归树模型 或者 模型树模型,这里为回归树inDat -- 输入的测试数据Returns:float(model) -- 将输入的模型数据转换为 浮点数 返回"""return float(model)# 模型树测试案例
# 对输入数据进行格式化处理,在原数据矩阵上增加第0列,元素的值都是1,
# 也就是增加偏移值,和我们之前的简单线性回归是一个套路,增加一个偏移量
def modelTreeEval(model, inDat):"""Desc:对 模型树 进行预测Args:model -- 输入模型,可选值为 回归树模型 或者 模型树模型,这里为模型树模型,实则为 回归系数inDat -- 输入的测试数据Returns:float(X * model) -- 将测试数据乘以 回归系数 得到一个预测值 ,转化为 浮点数 返回"""n = shape(inDat)[1]X = mat(ones((1, n+1)))X[:, 1: n+1] = inDat# print X, modelreturn float(X * model)# 计算预测的结果
# 在给定树结构的情况下,对于单个数据点,该函数会给出一个预测值。
# modelEval是对叶节点进行预测的函数引用,指定树的类型,以便在叶节点上调用合适的模型。
# 此函数自顶向下遍历整棵树,直到命中叶节点为止,一旦到达叶节点,它就会在输入数据上
# 调用modelEval()函数,该函数的默认值为regTreeEval()
def treeForeCast(tree,inData,modelEval=regTreeEval):"""Desc:对特定模型的树进行预测,可以是 回归树 也可以是 模型树Args:tree -- 已经训练好的树的模型inData -- 输入的测试数据,只有一行modelEval -- 预测的树的模型类型,可选值为 regTreeEval(回归树) 或 modelTreeEval(模型树),默认为回归树Returns:返回预测值"""if not isTree(tree):return modelEval(tree,inDate)# 书中写的是inData[tree['spInd']],只适合inData只有一列的情况,否则会产生异常if inData[0,tree['spInd']]<=tree['spVal']:# 可以把if-else去掉,只留if里面的分支if isTree(tree['left']):return treeForeCast(tree['left'],inData,modelEval)else:return modelEval(tree['left'],inData)else:# 同上,可以把if-else去掉,只留if里面的分支if isTree(tree['right']):return treeForeCast(tree['right'], inData, modelEval)else:return modelEval(tree['right'], inData)# 预测结果
def createForeCast(tree, testData, modelEval=regTreeEval):"""Desc:调用 treeForeCast ,对特定模型的树进行预测,可以是 回归树 也可以是 模型树Args:tree -- 已经训练好的树的模型testData -- 输入的测试数据modelEval -- 预测的树的模型类型,可选值为 regTreeEval(回归树) 或 modelTreeEval(模型树),默认为回归树Returns:返回预测值矩阵"""m=len(testData)yHat=mat(zeros((m,1)))# print yHatfor i in range(m):yHat[i,0]=treeForeCast(tree,mat(testData[i]),modelEval)# print "yHat==>", yHat[i, 0]return yHat
# 测试数据集
testMat=mat(eye(4))
print(testMat)
print(type(testMat))
mat0,mat1=binSplitDataSet(testMat,1,0.5)
print(mat0,'\n-----------\n', mat1)# 回归树
myDat=loadDataSet('data/9.RegTrees/data1.txt')
myMat=mat(myDat)
myTree=createTree(myMat)
print (myTree)#1.预剪枝就是: 提起设置最大误差数和最少元素数
myDat = loadDataSet('data/9.RegTrees/data3.txt')
myMat=mat(myDat)
myTree=createTree(myMat,ops=(0,1))
print (myTree)# 2. 后剪枝就是: 通过测试数据,对预测模型进行合并判断
myDatTest = loadDataSet('data/9.RegTrees/data3test.txt')
myMat2Test = mat(myDatTest)
myFinalTree = prune(myTree, myMat2Test)
print ('\n\n\n-------------------')
print (myFinalTree)# 模型树求解
myDat = loadDataSet('data/9.RegTrees/data4.txt')
myMat = mat(myDat)
myTree = createTree(myMat, modelLeaf, modelErr)
print (myTree)# 回归树 VS 模型树 VS 线性回归
trainMat = mat(loadDataSet('data/9.RegTrees/bikeSpeedVsIq_train.txt'))
testMat = mat(loadDataSet('data/9.RegTrees/bikeSpeedVsIq_test.txt'))
# 回归树
myTree1 = createTree(trainMat, ops=(1, 20))
print (myTree1)
yHat1 = createForeCast(myTree1, testMat[:, 0])
print ("--------------\n")
print (yHat1)
print ("ssss==>", testMat[:, 1])
# corrcoef 返回皮尔森乘积矩相关系数
# 描述XY相关程度
print("regTree:",corrcoef(yHat1,testMat[:,1],rowvar=0)[0,1])# 模型树
myTree2 = createTree(trainMat, modelLeaf, modelErr, ops=(1, 20))
yHat2 = createForeCast(myTree2, testMat[:, 0], modelTreeEval)
print( myTree2)
print ("modelTree:", corrcoef(yHat2, testMat[:, 1],rowvar=0)[0, 1])# 线性回归
ws, X, Y = linearSolve(trainMat)
print (ws)
m = len(testMat[:, 0])
yHat3 = mat(zeros((m, 1)))
for i in range(shape(testMat)[0]):yHat3[i]=testMat[i,0]*ws[1,0]+ws[0,0]
print ("lr:", corrcoef(yHat3, testMat[:, 1],rowvar=0)[0, 1])
使用GUI
from __future__ import print_function
from Tkinter import *
from numpy import *import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')def test_widget_text(root):mylabel = Label(root, text="helloworld")# 相当于告诉 布局管理器(Geometry Manager),如果不设定位置,默认在 0行0列的位置mylabel.grid()# 最大为误差, 最大子叶节点的数量
def reDraw(tolS, tolN):# clear the figurereDraw.f.clf()reDraw.a = reDraw.f.add_subplot(111)# 检查复选框是否选中if chkBtnVar.get():if tolN < 2:tolN = 2myTree = createTree(reDraw.rawDat, regTrees.modelLeaf, regTrees.modelErr, (tolS, tolN))yHat = createForeCast(myTree, reDraw.testDat, regTrees.modelTreeEval)else:myTree = createTree(reDraw.rawDat, ops=(tolS, tolN))yHat = createForeCast(myTree, reDraw.testDat)# use scatter for data setreDraw.a.scatter(reDraw.rawDat[:, 0].A, reDraw.rawDat[:, 1].A, s=5)# use plot for yHatreDraw.a.plot(reDraw.testDat, yHat, linewidth=2.0, c='red')reDraw.canvas.draw()def getInputs():try:tolN = int(tolNentry.get())except:tolN = 10print("enter Integer for tolN")tolNentry.delete(0, END)tolNentry.insert(0, '10')try:tolS = float(tolSentry.get())except:tolS = 1.0print("enter Float for tolS")tolSentry.delete(0, END)tolSentry.insert(0, '1.0')return tolN, tolS# 画新的tree
def drawNewTree():# #get values from Entry boxestolN, tolS = getInputs()reDraw(tolS, tolN)def main(root):# 标题Label(root, text="Plot Place Holder").grid(row=0, columnspan=3)# 输入栏1, 叶子的数量Label(root, text="tolN").grid(row=1, column=0)global tolNentrytolNentry = Entry(root)tolNentry.grid(row=1, column=1)tolNentry.insert(0, '10')# 输入栏2, 误差量Label(root, text="tolS").grid(row=2, column=0)global tolSentrytolSentry = Entry(root)tolSentry.grid(row=2, column=1)# 设置输出值tolSentry.insert(0,'1.0')# 设置提交的按钮Button(root, text="确定", command=drawNewTree).grid(row=1, column=2, rowspan=3)# 设置复选按钮global chkBtnVarchkBtnVar = IntVar()chkBtn = Checkbutton(root, text="Model Tree", variable = chkBtnVar)chkBtn.grid(row=3, column=0, columnspan=2)# 退出按钮Button(root, text="退出", fg="black", command=quit).grid(row=1, column=2)# 创建一个画板 canvasreDraw.f = Figure(figsize=(5, 4), dpi=100)reDraw.canvas = FigureCanvasTkAgg(reDraw.f, master=root)reDraw.canvas.draw()reDraw.canvas.get_tk_widget().grid(row=0, columnspan=3)reDraw.rawDat = mat(loadDataSet('data/9.RegTrees/sine.txt'))reDraw.testDat = arange(min(reDraw.rawDat[:, 0]), max(reDraw.rawDat[:, 0]), 0.01)reDraw(1.0, 10)
# 创建一个事件
root = Tk()
# test_widget_text(root)
main(root)
# 启动事件循环
root.mainloop()
相关文章:
树回归CART
之前线性回归创建的模型需要拟合所有的样本点,但数据特征众多,关系复杂时,构建全局模型就很困难。之前构建决策树使用的算法是ID3。 ID3 的做法是每次选取当前最佳的特征来分割数据,并按照该特征的所有可能取值来切分。也就是说&…...
zemax色差与消色差
色差,颜色像差 轴向色差:不同波长的光束通过透镜后焦点位于沿轴的不同位置 垂轴色差:每个波长成像的放大率不同 单透镜为例: 输入需要设置为多波长 观察光线光扇图: 不同波长的光之间差异较大(不同颜色…...
成绩定级脚本(Python)
成绩评定脚本 写一个成绩评定的python脚本,实现用户输入成绩,由脚本来为成绩评级: #成绩评定脚本.pyscoreinput("please input your score:") if int(score)> 90:print("A") elif int(score)> 80:print("B&…...
骨传导耳机的危害有哪些?会损害听力吗?
如果正常的使用,骨传导耳机是没有危害的,由于骨传导耳机独特的传声方式,所以并不会对人体造成损伤,还可以在一定程度上保护听力。 如果想更具体知道骨传导耳机有什么危害,就要先了解什么是骨传导耳机,骨传…...
Redis模块二:缓存分类 + Redis模块三:常见缓存(应用)
缓存大致可以分为两大类:1)本地缓存 2)分布式缓存 目录 本地缓存 分布式缓存 常见缓存的使用 本地缓存:Spring Cache 分布式缓存:Redis 本地缓存 本地缓存也叫单机缓存,也就是说可以应⽤在单机环…...
Revit SDK 内容摘要: 8.0 -8.1
前提 不包含已单独写博客部分。 Revit SDK Samples 8.0 AnalyticalViewer 分析模型,VB,略。 namespace Autodesk.Revit.DB.Structure {public class AnalyticalModel : Element{public AnalyticalRigidLinksOption RigidLinksOption { get; set; }p…...
列表和字典练习
定义四个学生信息 在Python环境下,用列表定义: >>> stu1[xiaoming,True,21,79.9] >>> stu1[lihong,False,22,69.9] >>> stu1[zhangqiang,True,20,89.9] >>> stu1[EMT,True,23,99.9]如图,定义了四个列表…...
iwebsec靶场 文件包含漏洞通关笔记2-文件包含绕过(截断法)
目录 前言 1.%00截断 2.文件字符长度截断法(又名超长文件截断) 方法1(路径截断法) 方法2(点号截断法) 第02关 文件包含绕过 1.打开靶场 2.源码分析 3.00文件截断原理 4.00截断的条件 5.文件包含00截断绕过 …...
【基于Cocos Creator实现的赛车游戏】9.实现汽车节点的控制逻辑
转载知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具 项目地址:赛车小游戏-基于Cocos Creator 3.5版本实现: 课程的源码,基于Cocos Creator 3.5版本实现 在上一节的课程中,您已经实现了通过触控给刚体施…...
蓝蓝设计为教育行业提供软件UI交互设计服务
在教育行业,软件的用户体验设计对于提供优质教育体验至关重要。教育行业软件用户体验设计需要考虑到学生和教师的需求,以及教育环境的特殊性。为了确保设计的成功,选择一家专业的设计公司是至关重要的,而北京蓝蓝设计公司就是您的…...
Java从入门到精通-类和对象(二)
0. 类和对象 3. 类的构造方法 构造方法是一种特殊的方法,用于创建和初始化对象。构造方法的名称必须与类名相同,它没有返回值,并且在创建对象时自动调用。构造方法的主要作用是确保对象在创建时具有合适的初始状态。 以下是构造方法的基本概…...
Python解析MDX词典数据并保存到Excel
原始数据和处理结果: https://gitcode.net/as604049322/blog_data/-/tree/master/mdx 下载help.mdx词典后,我们无法直接查看,我们可以使用readmdict库来完成对mdx文件的读取。 安装库: pip install readmdict对于Windows平台还…...
线性代数的本质(四)
文章目录 行列式二阶行列式 n n n 阶行列式行列式的性质克拉默法则行列式的几何理解 行列式 二阶行列式 行列式引自对线性方程组的求解。考虑两个方程的二元线性方程组 { a 11 x 1 a 12 x 2 b 1 a 21 x 1 a 22 x 2 b 2 \begin{cases} a_{11}x_1a_{12}x_2b_1 \\ a_{21}x_…...
FreeMarker详细介绍
FreeMarker详细介绍 FreeMarker FreeMarker概述 FreeMarker概念 FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 是一个Java类库…...
房地产小程序 | 小程序赋能,房地产业务数字化升级
随着科技的不断发展,房地产行业正逐渐向数字化转型。在这个过程中,房地产小程序成为了一种重要的工具,可以帮助房地产企业提供更好的购房体验、增加销售额,并实现管理的便捷化。 优点 便捷购房体验:房地产小程序为用户…...
Databend 开源周报第 110 期
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 使用 BendSQL 管…...
开源大模型ChatGLM2-6B 1. 租一台GPU服务器测试下
0. 环境 租用了1台GPU服务器,系统 ubuntu20,GeForce RTX 3090 24G。过程略。本人测试了ai-galaxy的,今天发现网友也有推荐autodl的。 (GPU服务器已经关闭,因此这些信息已经失效) SSH地址:* 端…...
SQL10 用where过滤空值练习
描述 题目:现在运营想要对用户的年龄分布开展分析,在分析时想要剔除没有获取到年龄的用户,请你取出所有年龄值不为空的用户的设备ID,性别,年龄,学校的信息。 示例:user_profile iddevice_idge…...
JVM--Hotspot Architecture 详解
一、Java Virtual Machine (JVM)概述 Java Virtual Machine 虚拟机 (JVM) 是一种抽象的计算机。JVM本身也是一个程序,但是对于编写在其中执行的程序来说,它看起来像一台机器。对于特定的操作系统ÿ…...
ThreadLocal功能实现
模拟ThreadLocal功能实现 当前线程任意方法内操作连接对象 一个栈对应一个线程 , 一个方法调用另一个方法都是在一个线程内 , 只有执行了线程的start方法才会创建一个线程 定义一个Map集合 , key是当前线程(Thread.currentThread) , value是要绑定的数据(Connection对象) 以…...
Linux编辑器-vim使用
文章目录 前言一、vim编辑器1、vim的基本概念2、vim的基本操作2.1 命令模式切换至插入模式2.2 插入模式切换至命令模式2.3 命令模式切换至底行模式 3、vim命令模式命令集3.1 移动光标3.2 删除文字3.3 复制与粘贴3.4 替换3.5 撤销上一次操作3.6 更改3.7 跳至指定的行 4、vim末行…...
自助式数据分析平台:JVS智能BI功能介绍(二)数据集管理
数据集是JVS-智能BI中承载数据、使用数据、管理数据的基础,同样也是构建数据分析的基础。可以通俗地将其理解为数据库中的普通的表,他来源于智能的ETL数据加工工具,可以将数据集进行分析图表、统计报表、数字大屏、数据服务等制作。 在整体的…...
《5G技术引领教育信息化新革命》
5G技术引领教育信息化新革命 随着5G技术的快速发展,教育领域也迎来了全新的信息化时代。5G技术为教育行业提供了更高速、更稳定、更智能的网络连接,使得教育信息化不再局限于传统的课堂教学,而是延伸到了线上、线下的全时空教育。本文将详细介…...
cmake学习过程记录
目录 基础命令学习配置opencvcmake (Windows版本) 基础命令学习 //设置最低版本号 cmake_minimum_required(VERSION 3.5)//设置项目名称 project (hello_headers)//递归遍历文件夹src中的cpp文件放到变量SOURCES中 file(GLOB_RECURSE SOURCES src/*.cpp)//设置目标exe名称…...
Vue3、Vite使用 html2canvas 把Html生成canvas转成图片并保存,以及填坑记录
这两天接到新需求就是生成海报分享,生成的格式虽然是一样的但是自己一点点画显然是不符合我摸鱼人的性格,就找到了html2canvas插件,开始动工。 安装 npm install html2canvas --save文档 options 的参数都在里面按照自己需求使用 https://a…...
centos yum源配置(CentOS7 原生 yum 源修改为阿里 yum 源)
文章目录 centos yum源配置centos搭建内网yum源内网centos的yum软件源配置CentOS7 原生 yum 源修改为阿里 yum 源 centos yum源配置 centos搭建内网yum源 您好,在CentOS系统上搭建本地内网YUM仓库的方法如下: 安装httpd和createrepo工具 yum install httpd createrepo -y创…...
linux————ansible
一、认识自动化运维 自动化运维: 将日常IT运维中大量的重复性工作,小到简单的日常检查、配置变更和软件安装,大到整个变更流程的组织调度,由过去的手工执行转为自动化操作,从而减少乃至消除运维中的延迟,实现“零延时”…...
初识Java 8-1 接口和抽象类
目录 抽象类和抽象方法 接口定义 默认方法 多重继承 接口中的静态方法 作为接口的Instrument 本笔记参考自: 《On Java 中文版》 接口和抽象类提供了一种更加结构化的方式分离接口和实现。 抽象类和抽象方法 抽象类,其介于普通类和接口之间。在构…...
微信小程序音频后台播放功能
微信小程序在手机息屏后依旧能播放音频,需要使用 wx.getBackgroundAudioManager() 方法创建后台音乐播放器,并将音乐播放任务交给这个后台播放器。 具体实现步骤如下: 小程序页面中,使用 wx.getBackgroundAudioManager() 方法创…...
NotePad——xml格式化插件xml tools在线安装+离线安装
在使用NotePad时,在某些情形下,需要格式化Xml格式内容,可以使用Xml Tools插件。 一、在线安装 1. 打开Notepad 软件 2. 选择插件,选择“插件管理” 3. 搜索 XML Tools,找到该插件后,勾选该文件ÿ…...
精仿手表网站/最佳bt磁力猫
如何使用windows版Docker并在IntelliJ IDEA使用Docker运行Spring Cloud项目 #1:前提准备 1.1 首先请确认你的电脑是windows10专业版或企业版,只有这只有这两个版本才带有hyper-v #2:介绍 以往我们如果想要在windows上使用docker,都…...
宁皓 wordpress/seo是什么
不知道大家有没有遇到过这样的问题,有时候电脑网络正常连接,QQ微信都能正常登陆和聊天,就是打不开网页,有些小伙伴就会以为电脑系统问题甚至去重装系统。其实不用那么麻烦,正常联网却上不去网站很可能是DNS出了问题&am…...
徐州网站建设青州陈酿/余姚seo智能优化
语法array preg_grep ( string $pattern, array $input [, int $flags] );定义和用法返回给定数组input中与模式pattern 匹配的元素组成的数组.如果将flag设置为PREG_GREP_INVERT, 这个函数返回输入数组中与 给定模式pattern不匹配的元素组成的数组.返回值返回给定数组input中与…...
做网站哪一家公司好/营销网站建设大概费用
在皕杰报表的函数中,数据集函数和单元格函数都有sum求和函数,但其用法是不同的。我们先看两个函数的说明: 一、数据集函数sum 函数说明:从数据集中,从满足条件的记录中,算出给定字段或表达式的总和 语法&a…...
网站建设 58同城/如何优化网站推广
1数据库的代码自动生成 2ArcGIS版本的实现原理 A表和D表存储 3断点续传,多线程下载。 4类似Evernote的同步机制。 5点弧拓扑数据编辑 6事务的机制 1.服务器编程——服务器队列和客户端 2.异步编程 3.池化 4.透视和正视 5.Boost库的使用 6.资源的统一管理 7.SharpDev…...
做网站需要代码吗/持续优化疫情防控举措
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像。 输入描述: 二叉树的镜像定义: /* struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;TreeNode(int x) :val(x), left(NULL), right(NULL) {} };*/ class Solution { pub…...