@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;
}