C4.5决策树代码详细解析以及C4.5程序调用(正确的代码!!!)_c语言训练决策树回归器代码-程序员宅基地

技术标签: C4.5  

正确的代码传上来了,对上一篇博客中刚提到的几点错误做了更改,都是一些比较小的细节,可能不仔细看看不出来,可以和上文对比一下....不过本次用了新的数据集用来生成决策树,亲测正确!数据集也会放上来.....

C4.5代码:

    function test_targets = Use_C4_5(train_patterns, train_targets, test_patterns, inc_node, Nu)  
      
    % Classify using Quinlan's C4.5 algorithm  
    % Inputs:  
    %   training_patterns   - Train patterns 训练样本  每一列代表一个样本 每一行代表一个特征
    %   training_targets    - Train targets  1×训练样本个数 每个训练样本对应的判别值
    %   test_patterns       - Test  patterns 测试样本,每一列代表一个样本  
    %   inc_node            - Percentage of incorrectly assigned samples at a node  一个节点上未正确分配的样本的百分比
    %   inc_node为防止过拟合,表示样本数小于一定阈值结束递归,可设置为5-10
    %   注意inc_node设置太大的话会导致分类准确率下降,太小的话可能会导致过拟合  
    %  Nu is to determine whether the variable is discrete or continuous (the value is always set to 10)  
    %  Nu用于确定变量是离散还是连续(该值始终设置为10)
    %  这里用10作为一个阈值,如果某个特征的无重复的特征值的数目比这个阈值还小,就认为这个特征是离散的
    % Outputs  
    %   test_targets        - Predicted targets 1×测试样本个数 得到每个测试样本对应的判别值
    %   也就是输出所有测试样本最终的判别情况
      
    %NOTE: In this implementation it is assumed that a pattern vector with fewer than 10 unique values (the parameter Nu)  
    %is discrete, and will be treated as such. Other vectors will be treated as continuous  
    % 在该实现中,假设具有少于10个无重复值的特征向量(参数Nu)是离散的。 其他向量将被视为连续的
  
    [Ni, M]     = size(train_patterns); %M是训练样本数,Ni是训练样本维数,即是特征数目
    inc_node    = inc_node*M/100;  % 5*训练样本数目/100
      
    %Find which of the input patterns are discrete, and discretisize the corresponding dimension on the test patterns  
    %查找哪些输入模式(特征)是离散的,并离散测试模式上的相应维
    discrete_dim = zeros(1,Ni); %用于记录每一个特征是否是离散特征,初始化都记为0,代表都是连续特征,
    %如果后面更改,则意味着是离散特征,这个值会更改为这个离散特征的无重复特征值的数目 
    for i = 1:Ni  %遍历每个特征
        Ub = unique(train_patterns(i,:));  %取每个特征的不重复的特征值构成的向量 
        Nb = length(Ub);    %得到无重复的特征值的数目
        if (Nb <= Nu)  %如果这个特征的无重复的特征值的数目比这个阈值还小,就认为这个特征是离散的  
            %This is a discrete pattern  
            discrete_dim(i) = Nb; %得到训练样本中,这个特征的无重复的特征值的数目 存放在discrete_dim(i)中,i表示第i个特征
%             dist            = abs(ones(Nb ,1)*test_patterns(i,:) - Ub'*ones(1, size(test_patterns,2))); 
%             %前面是把测试样本中,这个特征的那一行复制成Nb行,Nb是训练样本的这个特征中,无重复的特征值的数目
%             %后面是把这几个无重复的特征值构成的向量复制成测试样本个数列
%             %求这两个矩阵相应位置差的绝对值
%             [m, in]         = min(dist);  %找到每一列绝对差的最小值,构成m(1×样本数目)   并找到每一列绝对差最小值所在行的位置,构成in(1×样本数目)
%             %其实,这个in的中每个值就是代表了每个测试样本的特征值等于无重复的特征值中的哪一个或者更接近于哪一个
%             %如=3,就是指这个特征值等于无重复的特征值向量中的第3个或者更接近于无重复的特征值向量中的第3个
%             test_patterns(i,:)  = Ub(in);  %得到这个离散特征
        end  
    end  
      
    %Build the tree recursively  递归地构造树
    disp('Building tree')  
    tree            = make_tree(train_patterns, train_targets, inc_node, discrete_dim, max(discrete_dim), 0);  
    
    %加入悲观剪枝的操作
    %在完全生长的决策树的基础上,对生长后分类效果不佳的子树进行修剪,减小决策树的复杂度,降低过拟合的影响
%     treeplot(tree);
    
    %Classify test samples  
    disp('Classify test samples using the tree')  
    test_targets    = use_tree(test_patterns, 1:size(test_patterns,2), tree, discrete_dim, unique(train_targets));  
    %1:size(test_patterns,2)其实是索引
    %END  Use_C4_5
      
    
    function targets = use_tree(patterns, indices, tree, discrete_dim, Uc)  
    %Classify recursively using a tree  
      
    targets = zeros(1, size(patterns,2)); %设置每个样本的初始预测标签都是0 
      
    if (tree.dim == 0)  %这说明达到了树的叶子节点
        %Reached the end of the tree  
        targets(indices) = tree.child;  %得到样本对应的标签是tree.child
        return  
    end  
      
    %This is not the last level of the tree, so:  
    %First, find the dimension we are to work on  
    dim = tree.dim;  %得到分裂特征
    dims= 1:size(patterns,1);  %得到特征索引
      
    %And classify according to it  根据得到的决策树对测试样本进行分类
    if (discrete_dim(dim) == 0) %如果当前分裂特征是个连续特征 
        %Continuous pattern  
        in              = indices(find(patterns(dim, indices) <= tree.split_loc));  %找到当前测试样本中这个特征的特征值<=分裂值的样本索引
        targets     = targets + use_tree(patterns(dims, :), in, tree.child(1), discrete_dim(dims), Uc);  %对这部分样本再分叉
        in              = indices(find(patterns(dim, indices) >  tree.split_loc));  %找到当前测试样本中这个特征的特征值>分裂值的样本索引
        targets     = targets + use_tree(patterns(dims, :), in, tree.child(2), discrete_dim(dims), Uc);  %对这部分样本再分叉 
    else  %如果当前分裂特征是个离散特征
        %Discrete pattern  
        Uf              = unique(patterns(dim,:)); %得到这个样本集中这个特征的无重复特征值
        for i = 1:length(Uf)  %遍历每个特征值  
            if any(Uf(i) == tree.Nf)  %tree.Nf为树的分类特征向量 当前所有样本的这个特征的特征值
                in      = indices(find(patterns(dim, indices) == Uf(i)));  %找到当前测试样本中这个特征的特征值==分裂值的样本索引
                targets = targets + use_tree(patterns(dims, :), in, tree.child(find(Uf(i)==tree.Nf)), discrete_dim(dims), Uc);%对这部分样本再分叉 
            end  
        end  
    end       
    %END use_tree  
      
    
    function tree = make_tree(patterns, targets, inc_node, discrete_dim, maxNbin, base)  
%         make_tree(train_patterns, train_targets, inc_node, discrete_dim, max(discrete_dim), 0);  
    %Build a tree recursively   递归地构造树
      
    [Ni, L]                     = size(patterns);  %%L为当前的样本总数,Ni为特征数目
    Uc                          = unique(targets);  %训练样本对应的判别标签   无重复的取得这些标签  也就是得到判别标签的个数
    tree.dim                    = 0;  %初始化树的分裂特征为第0个
    %tree.child(1:maxNbin)  = zeros(1,maxNbin);  
    tree.split_loc              = inf;  %初始化分裂位置是inf
      
    if isempty(patterns) 
        return  
    end  
      
    %When to stop: If the dimension is one or the number of examples is small 
    % inc_node为防止过拟合,表示样本数小于一定阈值结束递归,可设置为5-10
    if ((inc_node > L) | (L == 1) | (length(Uc) == 1)) %如果剩余训练样本太小(小于inc_node),或只剩一个,或只剩一类标签,退出  
        H                   = hist(targets, length(Uc));  %统计样本的标签,分别属于每个标签的数目    H(1×标签数目)
        [m, largest]    = max(H); %得到包含样本数最多的那个标签的索引,记为largest 包含多少个样本,记为m
        tree.Nf         = [];  
        tree.split_loc  = [];  
        tree.child      = Uc(largest);%姑且直接返回其中包含样本数最多一类作为其标签 
        return  
    end  
      
    %Compute the node's I  
    for i = 1:length(Uc) %遍历判别标签的数目 
        Pnode(i) = length(find(targets == Uc(i))) / L;  %得到当前所有样本中 标签=第i个标签 的样本的数目  占样本总数的比例  存放在Pnode(i)中
    end  
%   计算当前的信息熵(分类期望信息)
% 	例如,数据集D包含14个训练样本,9个属于类别“Yes”,5个属于类别“No”,Inode = -9/14 * log2(9/14) - 5/14 * log2(5/14) = 0.940
    Inode = -sum(Pnode.*log(Pnode)/log(2));  
      
    %For each dimension, compute the gain ratio impurity %对于每维,计算杂质的增益比  对特征集中每个特征分别计算信息熵
    %This is done separately for discrete and continuous patterns     %对于离散和连续特征,分开计算
    delta_Ib    = zeros(1, Ni);  %Ni是特征维数  用于记录每个特征的信息增益率
    split_loc   = ones(1, Ni)*inf;  %初始化每个特征的分裂值是inf
      
    for i = 1:Ni %遍历每个特征  
        data    = patterns(i,:);  %得到当前所有样本的这个特征的特征值
        Ud      = unique(data);   %得到无重复的特征值构成向量Ud
        Nbins   = length(Ud);     %得到无重复的特征值的数目
        if (discrete_dim(i)) %如果这个特征是离散特征 
            %This is a discrete pattern  
            P   = zeros(length(Uc), Nbins);  %Uc是判别标签的个数   判别标签个数×无重复的特征值的数目
            for j = 1:length(Uc) %遍历每个标签  
                for k = 1:Nbins %遍历每个特征值  
                    indices     = find((targets == Uc(j)) & (patterns(i,:) == Ud(k)));  
                    % &适用于矩阵间的逻辑运算 &&不适用,只能用于单个元素 &的意思也是与
                    %找到 (样本标签==第j个标签  并且 当前所有样本的这个特征==第k个特征值) 的样本个数
                    P(j,k)  = length(indices);  %记为P(j,k)
                end  
            end  
            Pk          = sum(P);  %取P的每一列的和,也就是得到当前所有样本中,这个特征的特征值==这个特征值的样本数目   Pk(1×特征值数目)表示这个特征的特征值等于每个特征值的样本数目
            P1          = repmat(Pk, length(Uc), 1);  %把Pk复制成 判别标签个数 行
            P1          = P1 + eps*(P1==0);  %这主要在保证P1作被除数时不等于0
            P           = P./P1;  %得到当前所有样本中,这个特征的值等于每个特征值且标签等于每个标签的样本,占当前这个特征值中的样本的比例
            Pk          = Pk/sum(Pk);  %得到当前所有样本中,这个特征的值等于每个特征值的样本,占当前样本总数的比例
            info        = sum(-P.*log(eps+P)/log(2));  %对特征集中每个特征分别计算信息熵  info(1×特征值数目)
            delta_Ib(i) = (Inode-sum(Pk.*info))/(-sum(Pk.*log(eps+Pk)/log(2))); %计算得到当前特征的信息增益率
            %计算信息增益率(GainRatio),公式为Gain(A)/I(A),
            %其中Gain(A)=Inode-sum(Pk.*info)就是属性A的信息增益
            %其中I(A)=-sum(Pk.*log(eps+Pk)/log(2))为属性A的所包含的信息
        else   %对于连续特征(主要要找到合适的分裂值,使数据离散化)
            %This is a continuous pattern  
            P   = zeros(length(Uc), 2);  %   P(判别标签数目×2)  列1代表前..个样本中的标签分布情况   列2代表除前..个样本之外的标签分布情况  这个..就是各个分裂位置
      
            %Sort the patterns  
            [sorted_data, indices] = sort(data);  %data里存放的是当前所有训练样本的这个特征的特征值   从小到大排序  sorted_data是排序好的数据 indices是索引
            sorted_targets = targets(indices);  %当然,判别标签也要随着样本顺序调整而调整
      
            %Calculate the information for each possible split  计算分裂信息度量
              I = zeros(1,Nbins);
              delta_Ib_inter    = zeros(1, Nbins);
              for j = 1:Nbins-1
                  P(:, 1) = hist(sorted_targets(find(sorted_data <= Ud(j))) , Uc);  %记录<=当前特征值的样本的标签的分布情况
                  P(:, 2) = hist(sorted_targets(find(sorted_data > Ud(j))) , Uc);  %记录>当前特征值的样本的标签的分布情况
                  Ps      = sum(P)/L;  %sum(P)是得到分裂位置前面和后面各有样本数占当前样本总数的比例
                  P       = P/L;  %占样本总数的比例
                  Pk      = sum(P);   %%sum(P)是得到分裂位置前面和后面各有多少个样本 比例 
                  P1      = repmat(Pk, length(Uc), 1);  %把Pk复制成 判别标签个数 行
                  P1      = P1 + eps*(P1==0);  
                  info    = sum(-P./P1.*log(eps+P./P1)/log(2));  %计算信息熵(分类期望信息)
                  I(j)    = Inode - sum(info.*Ps);  %Inode-sum(info.*Ps)就是以第j个样本分裂的的信息增益   
                  delta_Ib_inter(j) =  I(j)/(-sum(Ps.*log(eps+Ps)/log(2))); %计算得到当前特征值的信息增益率
              end

            [~, s] = max(I);  %找到信息增益最大的划分方法  delta_Ib(i)中存放的是对于当前第i个特征而言,最大的信息增益作为这个特征的信息增益  s存放这个划分方法
            delta_Ib(i) = delta_Ib_inter(s);  %得到这个分类特征值对应的信息增益率
            split_loc(i) = Ud(s);  %对应特征i的划分位置就是能使信息增益最大的划分值
        end  
    end  
      
    %Find the dimension minimizing delta_Ib    %找到当前要作为分裂特征的特征
    [m, dim]    = max(delta_Ib);  %找到所有特征中最大的信息增益对应的特征,记为dim
    dims        = 1:Ni;  %Ni特征数目
    tree.dim    = dim;  %记为树的分裂特征
      
    %Split along the 'dim' dimension  
    Nf      = unique(patterns(dim,:));  %得到选择的这个作为分裂特征的特征的那一行  也就是得到当前所有样本的这个特征的特征值
    Nbins   = length(Nf);  %得到这个特征的无重复的特征值的数目
    tree.Nf = Nf;  %记为树的分类特征向量 当前所有样本的这个特征的特征值
    tree.split_loc      = split_loc(dim);  %把这个特征的划分位置记为树的分裂位置  可是如果选择的是一个离散特征,split_loc(dim)是初始值inf啊???
      
    %If only one value remains for this pattern, one cannot split it.  
    if (Nbins == 1)  %无重复的特征值的数目==1,即这个特征只有这一个特征值,就不能进行分裂
        H               = hist(targets, length(Uc));  %统计当前所有样本的标签,分别属于每个标签的数目    H(1×标签数目)
        [m, largest]    = max(H);  %得到包含样本数最多的那个标签的索引,记为largest 包含多少个样本,记为m
        tree.Nf         = [];  %因为不以这个特征进行分裂,所以Nf和split_loc都为空
        tree.split_loc  = [];  
        tree.child      = Uc(largest);  %姑且将这个特征的标签就记为包含样本数最多的那个标签
        return  
    end  
      
    if (discrete_dim(dim))  %如果当前选择的这个作为分裂特征的特征是个离散特征 
        %Discrete pattern  
        for i = 1:Nbins   %遍历这个特征下无重复的特征值的数目
            indices         = find(patterns(dim, :) == Nf(i));  %找到当前所有样本的这个特征的特征值为Nf(i)的索引们
            tree.child(i)   = make_tree(patterns(dims, indices), targets(indices), inc_node, discrete_dim(dims), maxNbin, base);%递归
            %因为这是个离散特征,所以分叉成Nbins个,分别针对每个特征值里的样本,进行再分叉
        end  
    else  
        %Continuous pattern  %如果当前选择的这个作为分裂特征的特征是个连续特征 
        indices1            = find(patterns(dim,:) <= split_loc(dim));  %找到特征值<=分裂值的样本的索引们
        indices2            = find(patterns(dim,:) > split_loc(dim));   %找到特征值>分裂值的样本的索引们
        if ~(isempty(indices1) | isempty(indices2))  %如果<=分裂值 >分裂值的样本数目都不等于0  
            tree.child(1)   = make_tree(patterns(dims, indices1), targets(indices1), inc_node, discrete_dim(dims), maxNbin, base+1);%递归 
            %对<=分裂值的样本进行再分叉
            tree.child(2)   = make_tree(patterns(dims, indices2), targets(indices2), inc_node, discrete_dim(dims), maxNbin, base+1);%递归 
            %对>分裂值的样本进行再分叉
        else  
            H               = hist(targets, length(Uc));  %统计当前所有样本的标签,分别属于每个标签的数目    H(1×标签数目)
            [m, largest]    = max(H);   %得到包含样本数最多的那个标签的索引,记为largest 包含多少个样本,记为m
            tree.child      = Uc(largest);  %姑且将这个特征的标签就记为包含样本数最多的那个标签  
            tree.dim                = 0;  %树的分裂特征记为0
        end  
    end  



仍然用上文的train_and_test_with_C4_5.m的数据集,得到的决策树和上文是不一样的,亲测这个是正确的.....



于是,我又用了一个新的数据集,如下:



这个数据集既有离散属性,也有连续属性,而且属性值涉及到了文字,所以需要在生成决策树之前,对数据进行处理,处理之后效果是图中这样的,不同属性类别用不同数字代替,涉及到的代码generate_for_data_with_C4_5.m如下:


clear all;
clc;
% 因为数据中既包含数字,又包含文字,所以获取到cell中,在进行处理;
% [~,~,rawdata] = xlsread('Training_data',1,'A2:F16');  %sheet1中的样本
[~,~,rawdata] = xlsread('Training_data',2,'B2:F15');  %sheet2中的样本
Training_data = inf(size(rawdata));  %一会儿用于存储最终要用的训练样本
judge = cell(1,size(rawdata,2)); %用于存储数据是否为数字,一会儿把不是文字的转换成数字
for i = 1:size(rawdata,2)
    judge{1,i} = rawdata{1,i};        
end
judge_num_ornot = cellfun(@(x)isnumeric(x),judge);%此时1代表对应的那一列属性为数字   0代表对应的那一列属性为文字
numer_index = find(judge_num_ornot == 1); %找到数值属性对应的列的索引
Text_index = find(judge_num_ornot == 0);%找到文字属性对应的列的索引
for i = 1:length(numer_index)
    trans_before = cell2mat(rawdata(:,numer_index(i)));
    Training_data(:,numer_index(i)) = trans_before; %数值属性不用处理,直接存到最终的Training_data中就可以了
end
% native2unicode([186 186])
%其实对文字属性的处理有问题,就是通过cell2mat这个函数只能获取每个属性值的第一个汉字或字符,后面都获取不到
% for i = 1:length(Text_index)
%     text_length = inf(1,size(rawdata,1));  %用于一会儿放每个属性值的文字有多长,如果一个属性中的属性值不一样长,还得处理
%     tmp = rawdata(:,Text_index(i));
%     for v = 1:length(tmp)
%         text_length(v) = length(tmp{v});  %记录当前属性的每个属性值的长度
%     end
%     if length(unique(text_length)) == 1     %如果一个属性中的属性值一样长,就可以用cell2mat这个函数
%          trans_before = cell2mat(tmp);
%     else   %如果一个属性中的属性值不一样长,比如,‘买’ ‘不买’ 这时需要以最长的字符串为标准,补全短的字符串
%         max_length = max(text_length);
% %         add_num=repmat(max_length,[1,length(tmp)])-text_length; %计算需要补充的空字符的个数
%         deal_index = find(text_length ~= max_length);
%         for u = 1:length(deal_index)
%             add_num = max_length - text_length(deal_index(u));
%             tmp(deal_index(u)) = cellfun(@strcat, tmp(deal_index(u)), cellstr(repmat('a',[1,add_num])),'Unif',0);
%         end
%         trans_before = cell2mat(tmp);    
%     end
%     trans_after = inf(size(rawdata,1),1);
%     a_num = unique(trans_before(:,Text_index(i)),'rows');
%     for j = 1:length(a_num)
%         index = find(rawdata(:,Text_index(i)) == a_num{j});
%         trans_after(index) = mark;     
%         fprintf('属性%d中的属性值"%s"用%d表示\n',Text_index(i),a_num(j),mark);
%         mark = mark+1;
%     end
%     Training_data(:,Text_index(i)) = trans_after;
% end
%以上内容是在对读入的数据作处理,因为有些属性是文字,要转换成不同的数字
for i = 1:length(Text_index)
    trans_after = inf(size(rawdata,1),1);
    a_num = unique(rawdata(:,Text_index(i)));
%     a_num = unique(trans_before,'rows'); %得到这个属性的不重复的属性值  文字属性一般都是离散属性
    mark = 1:length(a_num);
    for j = 1:length(a_num)
        for v = 1:size(rawdata,1)
            if strcmp(rawdata{v,Text_index(i)},a_num{j}) %两个字符串比较只能用strcmp,不能用==
                trans_after(v) = mark(j);
            end
        end
        fprintf('属性%d中的属性值"%s"用%d表示\n',Text_index(i),a_num{j},mark(j));
    end
    Training_data(:,Text_index(i)) = trans_after;
end



 train_patterns=Training_data(:,1:(size(Training_data,2)-1));  %得到训练样本
 train_targets=Training_data(:,size(Training_data,2))';   %得到训练样本的标签   1×训练样本数目
 test_patterns=[];
 test_targets_predict = Use_C4_5(train_patterns', train_targets, test_patterns', 5, 5);  
 

由此生成的决策树是这样的:


然后,又用了另一个数据集:


之前注释掉的代码在这里不太试用,主要是因为属性值的文字是被送入不同的cell中,这样就导致对不同文字属性值的识别只考虑到了第一个字母或者汉字,当然这里面没有涉及到两个不同属性值首字母相同的情况,这样的情况之前注释掉的代码是判断不出来的,所以修改了一下,也就是上面注释掉的一大段代码后面的几行,不知道说清楚了没有,看一下这个例子可能更明白一些:



得到的决策树是这样的:



决策树本身就是100%完美拟合训练样本的产物(尤其我设置的停止阈值比较小....),但是这会带来一个问题,如果训练样本中包含了一些错误,按照这种算法,这些错误也会100%一点不留得被决策树学习了,也就是产生了“过拟合”,所以需要进行剪枝。C4.5采用的是悲观剪枝,看完了很多博客都介绍的悲观剪枝的算法原理,不过我还没有用程序实现出来.....本系列待续.....QAQ

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sgfmby1994/article/details/52963021

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签