当前位置: 首页 > 后端技术 > Python

基于决策树

时间:2023-03-26 17:02:31 Python

原则的简单验证码识别的核心思想:相似的输入会产生相似的输出。原理:先从训练样本矩阵中选择第一个特征进行划分,使得每个子表中特征的值都相同(比如第一个特征是男性和女性,那么两个子表表可以分,男,女),然后在每个子表中选择下一个特征,继续按照同样的规则划分更小的子表(比如第二个特征是年龄,我可以分三个)分表(当然根据情况不同),小于18,大于18和小于60,大于60,男表和女表分三个分表,特征值每个子表下都是相同的),重复直到所有特征用完,然后得到所有样本具有相同特征值的叶级子表表。解释:决策树是一种分类方法,用来对样本的特征进行分类。分类完成后,结果是同一类(或表)的所有特征基本相同,然后根据某一类的所有样本进行平均(回归)或投票(分类)得到一个输出.然后,当有新的待预测样本需要预测输出时,我只需要知道样本属于哪个类(表)即可。工程优化(剪枝):不需要用完所有的特征。叶级子表中允许混合不同的特征值,从而在可接受牺牲精度的前提下,减少决策树的层数,提高模型的性能。通常,可以优先选择最能降低信息熵的特征作为分表的依据。(说白了,有些特征值是不区分的,比如第一个特征是男的和女的,我不分两张表,而是放在一张表里。在这种情况下,男和女的特征haslittleeffectontheoutput.),如何区分有用的特征和无用的特征或影响很小的特征?它以信息熵或基尼指数来区分。也可以使用PCA、ICA等方法对特征进行降维操作。sklearnapiclasssklearn.tree.DecisionTreeClassifier()参数criterion:value{"gini","entropy"},即Gini指数和信息熵,默认'gini'splitter:value{'best','random'},default'best',random是为了防止过拟合max_depth:树的最大深度,如果不给出,将使用所有特征来构建树,或者在满足参数min_samples_split时停止min_samples_split:节点分裂的最小样本数,可以是int和float,float表示ceil(min_samples_split*n_samples),即小数是占总样本的比例min_samples_leaf:每个节点的最小样本数,可以是int和floatmin_weight_fraction_leaf:float,默认值=0.0,在所有叶节点(所有输入样本的权重总和中的最小加权分数)。如果未提供sample_weight,则样本的权重等于max_features:考虑的最大特征数,int、float或{"auto"、"sqrt"、"log2"}如果为int,max_features考虑每次拆分时的特征。如果是浮点数,则max_features是小数,并且在每次拆分时都会考虑特征。int(max_features*n_features)如果是“auto”,那么max_features=sqrt(n_features)。如果是“sqrt”,则max_features=sqrt(n_features)。如果是“log2”,则max_features=log2(n_features)。如果没有,则max_features=n_features。random_state:随机种子,int或RandomState。为了防止过拟合,原理不知道max_leaf_nodes:最大叶子节点数,具体值根据情况调整min_impurity_decrease:限制信息增益的大小,信息增益小于设定值的分支不会发生。min_impurity_split:0.19之前使用,现在被min_impurity_decrease取代class_weight:样本权重ccp_alpha:看不懂属性classes_:标签数组feature_importances_:特征重要性(基于基尼指数和信息熵)max_features_:最大使用特征数的推断值n_classes_按模型:样本数n_features_:特征数n_outputs_:tree_:树对象方法apply(X[,check_input]):返回X的预测叶索引cost_complexity_pruning_path(X,y[,...]):没有理解decision_path(X[,check_input]):返回树中的决策路径fit(X,y[,sample_weight,…]):trainsget_depth():获取模型深度get_n_leaves():获取模型叶子数get_params([deep]):获取模型参数predict(X[,check_input]):预测predict_log_proba(X):预测X的对数概率predict_proba(X[,check_input]):预测X的概率score(X,y[,sample_weight]):重新转动预测y和输出y正确率比set_params(params):设置模型参数验证码识别前面用到的验证码特征和类别太明显,所以我们选择另外一个接口的验证码,即70x25的尺寸,如下:虽然也很简单,但是添加了字符。至于预处理,和数字验证码一样,普通验证码->灰度图->二值化->切割->标注。但是经过测试发现无论我怎么调整参数,准确率都是比较低的。看完所有的字,我发现虽然图中的字没有歪斜变形,但是有粗细之分,而且我在标注的时候并没有严格让粗细的样本数相同。而且人物的位置也不在画面的中间,人物的大小也不一样,有的高,有的低,有的小,有的大。即使relabeling的准确度也很难达到我想要的标准。对于这种有明显分界线和字符边缘的验证码,我们可以从截取的图片中提取字符,也就是去掉边缘以外的空白,然后调整到一样大小。这样就去除了字符位置和大小对算法的干扰。至于粗体和细体,只要两者的训练样本数相同即可。代码如下:defimg_preprocess(file):img1=Image.open(file)pix=np.array(img1)pix=(pix>180)*255width,height=pix.shapeforiinrange(width):ifnp.sum(pix[i]==0):xstart=ibreakforiinrange(width-1,0,-1):ifnp.sum(pix[i]==0):xend=i+1breakforiinrange(height):ifnp.sum(pix[:,i]==0):ystart=ibreakforiinrange(height-1,0,-1):如果np.sum(pix[:,i]==0):yend=i+1breaknew_pix=pix[xstart:xend,ystart:yend]img=Image.fromarray(new_pix).convert('L')ifnew_pix。size!=(8,10):img=img.resize((8,10),resample=Image.NEAREST)img.save(file)然后我们使用决策树重新训练样本并调整参数。让我们先看看max_depth参数。代码如下:fromsklearn.treeimportDecisionTreeClassifierimportosfromPILimportImageimportnumpyasnpiimportmatplotlib.pyplotasmpdeffunc(k):x=[]y=[]forlabelinos.listdir('train'):对于os.listdir(f'train/{label}')中的文件:im=Image.open(f'train/{label}/{file}')pix=np.array(im)pix=(pix>180)*1pix=pix.ravel()x.append(list(pix))y.append(label)train_x=np.array(x)train_y=np.array(y)模型=DecisionTreeClassifier(max_depth=k)model.fit(train_x,train_y)x=[]y=[]forlabelinos.listdir('test'):forfileinos.listdir(f'test/{label}'):im=Image.open(f'test/{label}/{file}')pix=np.array(im)pix=(pix>180)*1pix=pix.ravel()x.append(list(pix))y.append(label)test_x=np.array(x)test_y=np.array(y)score=model.score(test_x,test_y)如果__name__=="__main__":os.chdir('G:\\knn\\字符验证码\\')x=list(range(1,15))y=[func(i)foriinx]mp.scatter(x,y)mp.show()运行结果:可以看到当max_depth=8时,准确率已经很接近1了,所以我们可以直接将max_depth设置为8。由于识别准确率已经接近1,其他参数好像调整与否。不重要,但是因为这是验证码的标识,不容易过拟合。在其他情况下,如果准确率接近1,则需要调整随机参数(random_state和splitter)和剪枝参数(min_samples_leaf等)来防止过拟合。后面也尝试调整了其他参数,发现模型的精度变化不大,默认就可以了。训练和测试数据集:https://www.lanzous.com/i8joo0f最后在学习一些机器学习算法,需要分享的一些内容记录在博客和微信上公众号(python成长之路),欢迎关注。平时,我一般会分享一些爬虫或者Python的内容。