尝试利用决策树进行分类以及成绩预测

任务是回归,组长大佬在用各种模型做回归,于是我想先进行分类(后来老师指导说可以先尝试进行分类),通过之前机器学习课的学习,对于这种多属性的数据进行分类,我的第一尝试是采用决策树。因此现在的目的就是根据属性,预测学生成绩属于什么档次。

总体概括:

  • 数据处理
  • 决策树实现
  • 第一次改进:后剪枝
  • 第二次改进:数据集微调
  • 第三次改进:成绩预测
  • 第四次改进:测试集验证集分离并测试

这个算法和思路直到6.27正式完工(中间换了数据集,但我舍不得放下这个方法,就继续了),下面是具体的总结:

思路

首先观察组长发的脱敏的数据集,起初的想法是对每个课程,建立并训练一个决策树模型,从而当预测时候,根据课程不同采用不同的决策树模型。但观察发现数据问题——某些课的很多的学生所有可用属性全部为零,这样对于一个课程来说,可用的数据太少,实在是不容易出好的效果,因此决定对整个数据集训练一个决策树,同时将课程作为其中一个属性,辅助决策树的判断。

决策树原理介绍1 2 3

决策树基本上就是把我们以前的经验总结出来。如果我们要出门打篮球,一般会根据“天气”、“温度”、“湿度”、“刮风”这几个条件来判断,最后得到结果:去打篮球?还是不去?

决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。

1) 开始,构建根节点,将所有训练数据都放在根节点,选择一个最优特征,按着这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。

2) 如果这些子集已经能够被基本正确分类,那么构建叶节点,并将这些子集分到所对应的叶节点去。

3)如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点,如果递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止。

4)每个子集都被分到叶节点上,即都有了明确的类,这样就生成了一颗决策树。

划分数据集的大原则是:将无序数据变得更加有序。特征选择就是决定用哪个特征来划分特征空间,信息增益就能够很好地表示这一直观的准则。

在划分数据集之前之后信息发生的变化称为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。

熵定义为信息的期望值,如果待分类的事物可能划分在多个类之中,则符号Xi 的信息定义为:

其中,p(xi)是选择该分类的概率。

为了计算熵,我们需要计算所有类别所有可能值所包含的信息期望值,通过下式得到:

其中,n为分类数目,熵越大,随机变量的不确定性就越大

在这里采用信息增益作为属性划分的依据(ID3决策树),用来寻找最合适的划分属性和划分条件,信息增益公式为:

观察数据集发现,属性数值是连续的,并不是一个个离散选项,于是采用二分的方式对属性进行处理。当测试某属性时,将该属性取值进行排序,之后依次计算两个值的均值,作为二分点,从而得到二分的属性选择。如下图:

因为数据没有缺失值,所以不必进行缺失值处理。所以下面就按照基本思想创建模型。但由于所给数据的lable是连续的,因此应当先对数据处理,使得数据label是离散的,从而使决策树可以分类到一个类别上。

部分关键代码及解释

首先是读取数据,并且进行处理。此处要对label离散化,采用0代表70以下,1代表85以下70以上,2代表85以上,作为标签:

import random
fr = open('D:\PythonProject\practice_useless\mooc_data.txt','r')#将属性由str类型转换为float
data =[ i.strip().split(',') for i in fr.readlines()]
for i in data:for k in range(24):i[k]=float(i[k])#该读取用于对全部数据的决策树,因此去掉没用的学生学号班级等信息,只留对成绩有关的属性(保留课程号,利于决策树判断)
#同时处理最后一列,即得分。用0代表70以下,1代表85以下70以上,2代表85以上。作为标签。
#包括标签在内总长21,属性20个
def all_read():data1=[] #存放最终的数据for i in data:temp=i[3:-1]#保留的属性score=i[-1]if score<70:temp.append(0.0)elif score>=70 and score<85:temp.append(1.0)elif score >=85:temp.append(2.0)data1.append(temp)return data1

计算当前数据集信息熵:

'''
计算信息熵
输入当前数据集
输出当前数据集的信息熵
'''
def countEnt(dataset):num = len(dataset)  # 样本数,用来做分母计算占比dic = {}  # key为类别,value为个数# 对每一个数据,取最后,即为类别,然后加入字典for i in dataset:if i[-1] not in dic:dic[i[-1]] = 1else:dic[i[-1]] = dic[i[-1]] + 1ent = 0  # 信息熵for i in dic.values():ent = ent - (i / num) * log(i / num, 2)return ent

计算数据集中个数最多的类别,用于当决策树无法再分时,采用最多的类别当作叶子节点。

'''
输入数据集的类别列表
输出最多的类别
'''
def major(classlist):dict={}for i in classlist:if i not in dict.keys():dict[i] = 1else:dict[i] = dict[i] + 1a=sorted(dict.items(),key=lambda x:x[1],reverse=True)return a[0][0]

因为score为连续值,所以按照二分法来处理:

'''
计算按k属性划分后 大于 和 小于value的数据 两个集合
输入数据集dataset,划分属性的索引k,中分点value
返回两个数据集列表 可以同时接收
'''
def splitset(dataset,k,value):#左右两个集合lset = []rset = []for i in dataset:if i[k] < value:lset.append(i)else:rset.append(i)return lset,rset

计算最佳划分属性及最佳中分点,利用熵增来选择。

'''
输入数据集
输出最佳属性的索引和中分点的值
'''
def bestSplit(dataset):num=len(dataset[0])-1  #属性个数preEnt=countEnt(dataset)  #初始信息熵bestfeature=-1 #最佳属性的索引bestmid=None  #最好的中分点bestEntGain=0 #最多的信息增益for i in range(num):   #对每个属性l=[k[i] for k in dataset]l=set(l) #去重,以方便计算中分点且没重复sorted(l)#由小到大排序l=list(l)length=len(l)-1  #中分点个数minEnt=float("inf") # 用来记录最小的信息熵goodmid=None  #记录最小信息熵的中分点for k in range(length):mid=( l[k]+ l[k+1])/2  #计算中分点left,right=splitset(dataset,i,mid)  #按中分点分数据集probleft = len(left) / len(dataset)  #算权重probright = len(right) / len(dataset)newEnt =probleft * countEnt(left) + probright * countEnt(right) #新信息熵if newEnt<minEnt:minEnt =newEntgoodmid =mid#遍历完所有中分点,得到该属性下的最好中分点goodmid和最小信息熵minEntEntGain=preEnt - minEnt   #计算此时的信息增益if EntGain > bestEntGain:  #如果信息增益大,则更新信息增益,最佳属性,中分点bestEntGain =EntGainbestmid =goodmidbestfeature=ireturn bestfeature,bestmid

有了之前的辅助函数,可以进行决策树的创建了(其中的难点是决策树的表示,这里采用了字典套字典的方式,其中key为 是 和 否,item则是新的字典,即子节点,采用递归创建):

'''
输入数据集,属性集合
输出决策树
'''
def createTree(dataset ,labels):l=[k[-1] for k in dataset]  #类别列表s=set(l)s=list(s)if len(s)== 1:  #如果只有一个类别,则结束,返回该类别return s[0]bestfeature,bestmid=bestSplit(dataset)if bestfeature == -1:  #不能找到更好的属性及中分点,返回该集合个数最多的类别return major(l)x =labels[bestfeature] + '<' + str(bestmid)tree={x:{}}left,right=splitset(dataset,bestfeature,bestmid)sublabels=labels[:]  #取全部属性  因为连续型分类不需要去除属性-tree[x]['是'] = createTree(left , sublabels)tree[x]['否'] = createTree(right, sublabels)return tree

测试1

下面进行测试,首先要根据决策树模型(字典套字典)写一个测试函数(关键点在于对字典套字典这个结构的遍历,需要采用=='dict’来判断是否是叶子节点,需要调整对属性集合进行处理的代码,使其能够完成寻找index,value等值的位置的确定。同时注意递归的时候参数的传递问题,这种细节容易出bug):

'''
输入一个数据(属性为float,类别为str),训练好的树,属性集合
输出属于的类别
'''
def testTree(testdata,tree,labels):str = list(tree.keys())[0]a = str.find('<') #找到<所在位置pre =str[:a]  # < 前面的部分,比如 :属性4value=float(str[a+1:])   #<后面的部分,比如: 1.0featureIndex =labels.index(pre)  #在属性集合中找到该属性的索引leibie = None  #所属类别nextdic = tree[str] # 判断是否的那个字典{'是':... , '否':...}if testdata[featureIndex]<value:  #满足<,即key为 '是'#下面再判断key为是的情况下,其value类型是否为类别(即判断是否是叶子节点)if type(nextdic['是']).__name__=='dict':  #不是叶子节点leibie =testTree(testdata,nextdic['是'],labels)else:leibie = nextdic['是']else :        #不满足<,即key为'否'# 下面再判断key为否的情况下,其value类型是否为类别(即判断是否是叶子节点)if type(nextdic['否']).__name__=='dict':  #不是叶子节点leibie =testTree(testdata,nextdic['否'],labels)  #不是叶子节点else:leibie = nextdic['否']   #是叶子节点return leibie

下面采用五折交叉验证,下面是部分关键代码:

#改进前的决策树 五折交叉验证
def tree1():data=read.all_read()labels = ['属性1','属性2','属性3','属性4','属性5','属性6','属性7','属性8','属性9','属性10','属性11','属性12','属性13','属性14','属性15','属性16','属性17','属性18','属性19','属性20']random.shuffle(data)  # 打乱数据集# 五折交叉验证data1 = data[0:180]data2 = data[180:360]data3 = data[360:540]data4 = data[540:720]data5 = data[720:900]#############################################################traindata = data1 + data2 + data3 + data4testdata = data5Tree = createTree(traindata, labels)correct = 0wrong = 0# 对训练集for i in traindata:if testTree(i, Tree, labels) == i[-1]:  # 预测正确correct = correct + 1else:wrong = wrong + 1# 训练集正确率coradio5 = correct / 720# 对测试集correct = 0wrong = 0for i in testdata:if testTree(i, Tree, labels) == i[-1]:  # 预测正确correct = correct + 1else:wrong = wrong + 1# 测试集正确率radio5 = correct / 180print("训练集正确率:" + str(coradio5) + "  测试集 : 正确:"+ str(correct) + "  错误:" + str(wrong) + "  测试集正确率:" + str(radio5))

最终结果:

由此可见,训练集上正确率不错,但是测试集上并不高。说明有过拟合的风险,导致模型泛化能力不强。对于决策树的过拟合现象,可以采用剪枝手段进行抑制。

尝试改进思路(后剪枝)

预剪枝这个策略带来的问题就是有可能会丢失那些在后续确实能提高泛化性能的结点,因此预剪枝带来欠拟合的风险。因此采用后剪枝。思想是先从训练集中生成一颗完整的决策树,然后自底向上地对非叶节点进行考察,若将该节点对应地子树替换为叶节点能带来决策树泛化性能提升,则将该子树替换为叶节点。虽然相对于预剪枝,训练时间开销是比较大的,但是好在数据集并不庞大,可以尝试采用。

完成后剪枝需要实现两个子方法,一个testNow:计算当前节点,如果不剪枝,即保留左右节点的情况 测试集准确率。另一个testMajor:计算剪枝,即不保留左右结点的 测试集准确率(类别为测试集个数最多的种类)。下面是子方法的代码(关键点是参数的传递,因为testNow方法需要用到之前写的testTree,但是后剪枝方法不需要传入labels了,所以无法给该方法labels参数,便又定义了一个一样的labels,其实作用就是用来找index):

def testMajor(majorClass,testset):  #majorClass为主类别,即个数最多的类别,testset为测试集num =len(testset)if num == 0: return 1 #如果测试集在该节点没有,则说明该分支对于测试集无用,可以删去,则返回最大正确率,以便之后的比较中删去分支right=0for i in testset:if i[-1] == majorClass:right = right+1#返回正确率return float(right/num)def testNow(tree,testset):l=len(testset)if l==0: return 0  #如果测试集在该节点没有,则说明该分支对于测试集无用,可以删去,则返回最小正确率,以便之后的比较中删去分支right=0labels = ['属性1','属性2','属性3','属性4','属性5','属性6','属性7','属性8','属性9','属性10','属性11','属性12','属性13','属性14','属性15','属性16','属性17','属性18','属性19','属性20']for i in range(l):if testset[i][-1] == testTree(testset[i],tree,labels):right = right+1return float(right/l)

下面是后剪枝主函数,是建立在已经创建好的决策树的基础上, 如果剪枝之后准确率大于或等于当前,则剪枝,即返回当前个数最多的类别,否则(即剪枝前准确率高于剪枝后)返回该树:

def backCutTree(tree,dataset,testset):first =list(tree.keys())[0]classList=[i[-1] for i in dataset]  #类别列表secondDic = tree[first]i = 0while 1:if first[i] != '<' and first[i] != '>':i=i+1else:breakindex=int(first[2:i])-1value=float(first[i+1:])#先将所有非叶子节点,进行递归,将子节点经历完剪枝过程for key in secondDic.keys():  # 对每个分支if type(secondDic[key]).__name__ =="dict":  #如果分支不是叶子节点,则进行递归left,right=splitset(dataset,index,value) #对训练集和测试集分割left_test,right_test =splitset(testset,index,value)#进行递归if key == "是":tree[first][key] =backCutTree(secondDic[key],left,left_test)if key == "否":tree[first][key] = backCutTree(secondDic[key], right, right_test)#对当前节点进行剪枝判断if testMajor(major(classList),testset) >= testNow(tree,testset):return major(classList)return tree

测试2

由于之前的测试代码比较不精简,于是在写一个函数,将对决策树的测试整体写入一个函数,从而简化代码。该函数为:

#计算tree正确率,用于下面的剪枝测试
def countCoradio(tree,dataset):correct=0l=len(dataset)labels = ['属性1', '属性2', '属性3', '属性4', '属性5', '属性6', '属性7', '属性8', '属性9', '属性10', '属性11', '属性12', '属性13', '属性14', '属性15', '属性16', '属性17', '属性18', '属性19', '属性20']for i in dataset:if testTree(i, tree, labels) == i[-1]:  # 预测正确correct = correct + 1return float(correct/l)

下面便是精简了以后的,后剪枝决策树的五折交叉验证的部分关键代码:

#用后剪枝的决策树 五折交叉验证
def tree2():data=read.all_read()labels = ['属性1','属性2','属性3','属性4','属性5','属性6','属性7','属性8','属性9','属性10','属性11','属性12','属性13','属性14','属性15','属性16','属性17','属性18','属性19','属性20']random.shuffle(data)  # 打乱数据集# 五折交叉验证data1 = data[0:180]data2 = data[180:360]data3 = data[360:540]data4 = data[540:720]data5 = data[720:900]sum_back = 0  # 预剪枝总正确率print("后剪枝:*******************************")#############################################################traindata = data1 + data2 + data3 + data4testdata = data5Tree = createTree(traindata, labels)# 进行后剪枝的树tree = backCutTree(Tree, traindata, testdata)print(json.dumps(tree, indent=3, ensure_ascii=False))kk = countCoradio(tree, testdata)print("训练集正确率:" + str(countCoradio(tree, traindata)) + "测试集正确率:" + str(kk))sum_back = sum_back + kk

决策树的部分结构为:

五折交叉验证测试结果为:

可见比之前,泛化能力提高了不少,有所改进,但这样的结果还是不令人满意。

尝试改进思路(数据集微调)

众所周知,分数高的学生,他的该数据集中的各项属性,理应有较高的取值(主观猜想),因此根据这个主观推断对数据集进行一定微调:将每个学生,根据他成绩所在的档次,随机的在不同属性上加上一个数值(从而形成一个 好的平时表现就有好成绩的,符合主观猜想的数据),用这个数据进行决策树的训练,但是注意测试的时候,仍然采用原数据集,这样才能保证是对原数据集的泛化能力的预测,而不是偏离方向。

这个数据集微调的过程在数据读取函数中直接进行即可,返回微调后的数据集和微调前的数据集,下面是具体代码(在此代码中,微调增加的范围是0-4,其中属性值是否增加是随机的):

#另一个考虑,因为很多课的学生属性均为零,很不利于决策树
#所以对data进行一点改造,根据成绩档次不同,对属性取值进行微调
def all_read_new():data2=[]data_pre=[] #保留不经过修改的数据,同样做返回值,可用于测试for i in data:temp=i[3:-1]#保留的属性score=i[-1]if score<70:temp.append(0.0)elif score>=70 and score<85:temp.append(1.0)elif score >=85:temp.append(2.0)data_pre.append(temp)#对除课程号和成绩档次 以外的属性,根据成绩档次进行微调for j in range(len(temp[1:-1])):temp[1+j]=temp[1+j]+(temp[-1]*random.random()*2)*random.randint(0,1)data2.append(temp)return data2,data_pre

后面同样进行五折交叉验证,只不过换一个读取数据的函数即可,同时注意测试的时候,采用的测试集是未处理过的测试集,下面进行测试。

测试3

五折交叉验证:

结果非常的amazing啊!这样处理数据得到的模型,泛化能力大大加强。同时这也说明,该数据集的确符合我们的主观猜想,就是:平时表现好的同学,的确会容易获得好成绩。

尝试成绩预测

这样的表现让我看到成绩预测的希望曙光。我认为可以将学生成绩划分为比较细的档次(比如75-80档,90-95档),这样进行决策树分类以后,得到学生的成绩档次,可以认为档次的中值是他的预测得分。这样可以近似于对学生成绩的预测(因为一旦预测正确了档次,那么绝对误差不会超过2.5)

于是对读取函数进行改进,分为9个档次,60一下为一档,之后每增加5分为一档。同时仍然采用之前的改进(数据集微调,后剪枝)。新的读取函数为:

#所以对data进行一点改造,根据成绩档次不同,对属性取值进行微调
def all_read_more():data2=[]data_pre=[] #保留不经过修改的数据,同样做返回值,可用于测试for i in data:temp=i[3:-1]#保留的属性score=i[-1]if score<60:temp.append(0.0)elif score>=60 and score<65:temp.append(1.0)elif score>=65 and score<70:temp.append(2.0)elif score>=70 and score<75:temp.append(3.0)elif score>=75 and score<80:temp.append(4.0)elif score>=80 and score<85:temp.append(5.0)elif score>=85 and score<90:temp.append(6.0)elif score>=90 and score<95:temp.append(7.0)elif score >=95:temp.append(8.0)data_pre.append(temp)#对除课程号和成绩档次 以外的属性,根据成绩档次进行微调for j in range(len(temp[1:-1])):temp[1+j]=temp[1+j]+(temp[-1]*random.random()*2)*random.randint(0,1)data2.append(temp)return data2,data_pre

测试4

下面是五折交叉验证的部分代码,注意读取函数的改变:

#用后剪枝的决策树,并且对数据集进行微调,同时增加类别,作为成绩预测值, 五折交叉验证
def tree4():data,data_pre=read.all_read_more()labels = ['属性1','属性2','属性3','属性4','属性5','属性6','属性7','属性8','属性9','属性10','属性11','属性12','属性13','属性14','属性15','属性16','属性17','属性18','属性19','属性20']random.shuffle(data)  # 打乱数据集# 五折交叉验证data1 = data[0:180]data2 = data[180:360]data3 = data[360:540]data4 = data[540:720]data5 = data[720:900]sum_back = 0  # 预剪枝总正确率print("后剪枝:*******************************")#############################################################traindata = data1 + data2 + data3 + data4testdata = data_pre[720:900]Tree = createTree(traindata, labels)# 进行后剪枝的树tree = backCutTree(Tree, traindata, testdata)print(json.dumps(tree, indent=3, ensure_ascii=False))kk = countCoradio(tree, testdata)print("训练集正确率:" + str(countCoradio(tree, traindata)) + "测试集正确率:" + str(kk))sum_back = sum_back + kk

运行得到结果:

结果还是非常的amazing啊,测试集正确率不低。

进一步改进(测试集与验证集的划分)

但是仔细思考,问题随之而来,因为在之前采用了后剪枝,就是在测试集的基础上,对决策树进行的修剪。但实际上,之前我一直没有注意测试集和验证集的区分,导致后剪枝在测试及基础上进行修剪,自然会使该模型在同样的测试集上表现良好的性能(数据微调仅仅是让这个测试集正确率上限更高罢了),所以下面的改进就是(也不算是改进,其实应该是改错)对训练集和验证及进行区分。

  1. 验证集和测试集不同
  2. 验证集来自训练集的再划分
  3. 验证集的划分是为了模型选择和调参
  4. 测试集是用来测试学习器对新样本的判别能力,用测试误差作为泛化误差的近似值。

因此对于该数据集,将训练集,验证集,测试集的比例设为6:2:2,然后修改测试函数,下面是部分测试函数:

#进行测试集和验证集的区分,其他改进仍然保留
def tree5():data, data_pre = read.all_read_more()labels = ['属性1', '属性2', '属性3', '属性4', '属性5', '属性6', '属性7', '属性8', '属性9', '属性10', '属性11', '属性12', '属性13', '属性14', '属性15', '属性16', '属性17', '属性18', '属性19', '属性20']random.shuffle(data)  # 打乱数据集# 五折交叉验证data1 = data[0:180]data2 = data[180:360]data3 = data[360:540]data4 = data[540:720]data5 = data[720:900]sum_back = 0  # 预剪枝总正确率print("后剪枝:*******************************")#############################################################traindata = data1 + data2 + data3validationdata = data4testdata = data_pre[720:900]Tree = createTree(traindata, labels)# 进行后剪枝的树tree = backCutTree(Tree, traindata, validationdata)print(json.dumps(tree, indent=3, ensure_ascii=False))kk = countCoradio(tree, testdata)print("训练集正确率:" + str(countCoradio(tree, traindata)) + "测试集正确率:" + str(kk))sum_back = sum_back + kk

测试5


结果非常amazing(这已经是找的很多次次测试中最佳的结果了),准确率果然下降了,虽然很痛心,但这的确是最能表现模型泛化能力的了。但也不是一点进步没有,毕竟经过数据集微调和后剪枝,模型泛化能力比之前强了好几个百分点。可以根据该概率计算误差的期望,差不多是5,即每次预测距离真实值的绝对误差的期望为5,因此还可以接受的 .

总结

即使经过了很多的修改,但仍然没有很好的表现(组长大佬用另一个数据集能做出80正确率,模型表现更好),于是放弃该算法。


  1. https://www.cnblogs.com/molieren/articles/10664954.html ↩︎

  2. https://blog.csdn.net/jiaoyangwm/article/details/79525237 ↩︎

  3. cnblogs.com/htfeng/p/9931707.html ↩︎

项目实训工作总结(2)相关推荐

  1. 项目实训工作记录(二)

    项目实训工作记录(二)赵乐乐 201800301115 词向量搜索分析与算法设计 项目实训工作记录(二)赵乐乐 201800301115 1.词向量搜索 2.搜索过程中的问题分析 3.基于效率的算法设 ...

  2. 学生计算机培训照片,四川新华电脑学校三维项目实训室参观照片

    四川新华电脑学校为加强学生的实践动手能力,每个专业开设项目实训室,新华独创"任务驱动式五步教学法"让每位新华学子理论与实践并驾齐驱,学校课程设置改革紧跟市场需求,市场需要什么人才, ...

  3. 项目实训-关键词提取-任务理解工作分配

    项目实训记录系列博客 一马当先,争做国家栋梁. 博客说明 本博客初衷是用于学校项目实训知识梳理.工作内容.收获感悟的记录. 若能在您的学习之路上有所帮助,不胜荣幸.但若需转载,也请注明出处. 博客包含 ...

  4. 项目实训-收尾工作-组织协调

    项目实训记录系列博客 一马当先,争做国家栋梁. 博客说明 本博客初衷是用于学校项目实训知识梳理.工作内容.收获感悟的记录. 若能在您的学习之路上有所帮助,不胜荣幸.但若需转载,也请注明出处. 博客包含 ...

  5. 项目实训第一周工作(3)

    项目实训题目:饮食健康管理系统设计与实现 我的工作:数据清洗 具体工作事项:数据清洗:错误数据处理:图片大小归一化:图片存放位置归并:与数据库同学沟通:不对应(冗余或缺失)图片的删除与处理等. 本博客 ...

  6. c4d完全学习手册_动态视觉设计就业班,全商业项目实训,一线制作团队10人小班授课,持续提升学习...

    CUBE专注动态视觉设计培训.CUBE依托本身设计公司制作资源优势,将培训制作完美结合,开设有北京实体培训课程以及网络案例实战课程. CUBE课程与工作要求完美对接,16周高强度集训,零基础学员毕业后 ...

  7. 项目实训第一周(车道线检测)

    项目实训我主要负责计算机视觉方面,识别出车道线并据此导航.相关内容也更新在我的个人博客上个人网站 相关介绍 车道线检测如果用传统方法,识别速度较慢,效果不够好,容易受到多种因素的干扰,因此我们打算开发 ...

  8. java编码规范文档 下载_软件项目实训及课程设计指导——制定待开发项目中各种文档的规范...

    软件项目实训及课程设计指导--制定待开发项目中各种形式文档的规范 1.制定对课程设计项目开发过程中的规范性要求 (1)从"形式"到"内容"两个方面控制和要求开发 ...

  9. web前端小项目个人实例_Web前端:小程序界面与逻辑项目实训

    大家好,我来了!本期为大家带来的Web前端学习知识是"Web前端:小程序界面与逻辑项目实训",喜欢Web前端的小伙伴,一起看看吧! 主要内容 数据绑定 渲染 界面层数据渲染 事件处 ...

最新文章

  1. 《评人工智能如何走向新阶段》后记(再续7)
  2. 【Dijkstra】最短路径
  3. ORACLE中科学计数法显示问题的解决
  4. 计算机的键盘如何保养,知识每天涨一点:快捷键2 键盘键位知识 电脑小保养
  5. Microsoft Enterprise Library 5.0 系列(四) Logging Application Block
  6. 数据处理能力相差 2.4 倍?Flink 使用 RocksDB 和 Gemini 的性能对比实验
  7. 2016年3例严重工控安全事故经验教训总结
  8. 封装BackgroundWorker控件(提供源代码下载,F5即可见效果)
  9. 【详细教程】抓包神器:Charles
  10. 汉字笔顺字帖在线生成器网站源码
  11. 深入创新,共建原生 | 「DaoCloud 道客」与华钦科技签署合作备忘录
  12. IDEA显示树状目录结构
  13. ACM模板 | 学习笔记 树相关
  14. CentOS磁盘空间爆满问题排查
  15. 解决自己的小问题sizeof(ages) / sizeof(ages[0])是干嘛的
  16. 3D游戏建模真的很累吗?前景怎么样?需要什么基础?
  17. DNS信息查询 ,子域名爆破工具
  18. 地震-电离层耦合机理
  19. [AHK]双击^键为ctrl+o,单击^输出6,三击。。。功能你想吧
  20. 少不读水浒——揭秘水浒传

热门文章

  1. python成语接龙源代码,基于Tkinter,带成语解释
  2. 八分量基于区块链技术赋能我国工业互联网建设
  3. Windows Server 2016搭建文件服务器
  4. 网易NEC命名规范笔记
  5. minisys-单周期cpu(一) 数据通路设计
  6. word试题模板设计总结
  7. 与运算,或运算,异或运算
  8. Unity Bolt插件 基本使用
  9. AsyncTask 用法
  10. 国产化替代加速升温,智和信通着力信创技术再迎突破