天天看點

weka之NB算法

@Override
    public void buildClassifier(Instances data) throws Exception 
    {
        //檢測分類器能否處理資料
        getCapabilities().testWithFail(data);
        //删除具有類别缺失值的執行個體
        data=new Instances(data);
        data.deleteWithMissingClass();
        //儲存類别的數量
        m_NumClasses=data.numClasses();
        //複制訓練集
        m_Instances=new Instances(data);
        //如果指定,就對資料進行離散化
        if(m_UseDiscretization)
        {
            m_Disc=new weka.filters.supervised.attribute.Discretize();
            m_Disc.setInputFormat(data);
            m_Instances=weka.filters.Filter.useFilter(m_Instances, m_Disc);
        }
        else
        {
            m_Disc=null;
        }

        //為機率分布預留白間
        //類别條件機率分布P(X|Y)
        m_Distributions=new Estimator[m_Instances.numAttributes()-][m_Instances.numClasses()];
        //類别分布P(Y)
        m_ClassDistribution=new DiscreteEstimator(m_Instances.numClasses(), true);
        int attIndex=;
        Enumeration enumeration=m_Instances.enumerateAttributes();
        //循環處理每一個屬性
        while(enumeration.hasMoreElements())
        {
            Attribute attribute=(Attribute) enumeration.nextElement();

            //如果屬性是數值型,根據相鄰值之間的差異,測定估計器數值精度
            double numPrecision=DEFAULT_NUM_PRECISION;
            if(attribute.type()==Attribute.NUMERIC)
            {
                //根據目前屬性的值對資料集排序
                m_Instances.sort(attribute);
                //排序之後,目前屬性缺失值的執行個體就排到最前
                //這樣,判斷第一個樣本是否有缺失值,就知道整體樣本是否有缺失值
                //如果有,就沒有必要執行if後面的代碼塊
                if((m_Instances.numInstances()>) && !m_Instances.instance().isMissing(attribute))
                {
                    //lastVal為後一個執行個體的目前屬性值
                    double lastVal=m_Instances.instance().value(attribute);
                    //currentVal,為每個執行個體的目前屬性值,deltaSum為內插補點
                    double currentVal,deltaSum=;
                    //distinct為目前屬性取不同值的數量
                    int distinct=;
                    for(int i=;i<m_Instances.numInstances();i++)
                    {
                        Instance currentInst=m_Instances.instance(i);
                        if(currentInst.isMissing(attribute))
                        {
                            break;
                        }
                        currentVal=currentInst.value(attribute);
                        //如果目前值與最後值不相等,則相減并将內插補點累加到deltaSum
                        if(currentVal!=lastVal)
                        {
                            deltaSum+=currentVal-lastVal;
                            lastVal=currentVal;
                            distinct++;
                        }
                    }
                    //最終的numPrecision就是deltaSum/distinct
                    if(distinct>)
                    {
                        numPrecision=deltaSum/distinct;
                    }
                }
            }

            //循環處理每一個類别标簽
            for(int j=;j<m_Instances.numClasses();j++)
            {
                //判斷目前屬性的類型
                switch(attribute.type())
                {
                //如果為連續的數值型屬性,根據是否使用核估計器的選項,選擇建構Kernelstimator對象還是NormalEstimator對象
                //兩者的構造函數都是使用numPrecision作為參數
                case Attribute.NUMERIC:
                    if(m_UseKernelEstimator)
                    {
                        m_Distributions[attIndex][j]=new KernelEstimator(numPrecision);
                    }
                    else
                    {
                        m_Distributions[attIndex][j]=new NormalEstimator(numPrecision);
                    }
                    break;
                case Attribute.NOMINAL:
                    m_Distributions[attIndex][j]=new DiscreteEstimator(attribute.numValues(), true);
                    break;
                default:
                    throw new Exception("Attribute type unkown to my NB");
                }
            }
            attIndex++;
        }

        //統計每一個執行個體
        Enumeration enumInsts=m_Instances.enumerateInstances();
        while (enumInsts.hasMoreElements()) 
        {
            Instance instance=(Instance) enumInsts.nextElement();
            //調用updateClassifier方法,用執行個體更新分離器
            updateClassifier(instance);
        }

        //節省空間
        m_Instances=new Instances(m_Instances,);
    }

    public void updateClassifier(Instance instance) 
    {
        if(!instance.classIsMissing())
        {
            Enumeration enumAtts=m_Instances.enumerateAttributes();
            int attIndex=;
            //循環處理沒一個屬性
            while (enumAtts.hasMoreElements()) 
            {
                Attribute attribute = (Attribute) enumAtts.nextElement();
                if(!instance.isMissing(attribute))
                {
                    //m_Distributons第一個下标記為當親屬性下标記,第二個下标為類别值
                    //統計樣本執行個體對應類别屬性值的分布
                    //調用Estimator的AddValue方法将新資料值加入到目前評估器中
                    m_Distributions[attIndex][(int)instance.classValue()].addValue(instance.value(attribute),
                            instance.weight());
                }
                attIndex++;
            }
            //統計類别分布
            m_ClassDistribution.addValue(instance.classValue(), instance.weight());
        }
    }

    public double[] distributionForInstance(Instance instance) throws Exception
    {
        //如果使用useSupervisedDiscretization選項,就對執行個體進行離散化
        if(m_UseDiscretization)
        {
            m_Disc.input(instance);
            instance=m_Disc.output();
        }
        //類别的機率P(Y)
        double probs[]=new double[m_NumClasses];
        //循環得到每個類别的機率
        for(int j=;j<m_NumClasses;j++)
        {
            probs[j]=m_ClassDistribution.getProbability(j);
        }
        Enumeration enumAtts=instance.enumerateAttributes();
        int attIndex=;
        //循環處理每個屬性
        while(enumAtts.hasMoreElements())
        {
            Attribute attribute=(Attribute) enumAtts.nextElement();
            if(!instance.isMissing(attribute))
            {
                //temp為臨時機率,max為目前最大機率
                double temp,max=;
                for (int j = ; j < m_NumClasses; j++)
                {
                    //計算每個類别的條件機率P(X|Y)
                    temp=Math.max(, Math.pow(m_Distributions[attIndex][j].getProbability(instance.value(attribute)), 
                            m_Instances.attribute(attIndex).weight()));
                    probs[j]*=temp;
                    //更新最大機率值
                    if(probs[j]>max)
                    {
                        max=probs[j];
                    }
                    if(Double.isNaN(probs[j]))
                    {
                        throw new Exception(
                                "Nan returned from estimator for atrribute "+
                                attribute.name()+":\n"+
                                m_Distributions[attIndex][j].toString());
                    }
                }
                if(max> && max<)
                {
                    //防止機率下溢的危險
                    for(int j=;j<m_NumClasses;j++)
                    {
                        probs[j]*=;
                    }
                }
            }
            attIndex++;
        }

        //機率規範化
        Utils.normalize(probs);
        return probs;
    }
           

繼續閱讀