以前的文章裏寫到過Classififer的基本做用,它是Weka中分類器都須要實現的抽象類。 html
此次的AbstractClassifier即實現了Classifier,但並無實現所有方法,所以仍爲抽象類。 java
此外該類還實現了若干個接口,簡要介紹以下: 數組
// Cloneable:提供了一個複製特定類下實例的方法,實現該接口需重寫Object.clone app
//Serializable:保證了類的可序列化,需實現java.io.Serializable 接口 ide
//OptionHandler:對界面選項的描述 函數
//CapabilotiesHandler:查看對象的適用範圍 學習
//RevisionHandler:返回修訂信息 測試
//CapabilitiesIgnorer:設定或取得適用範圍信息 ui
public abstract class AbstractClassifier implements Classifier, Cloneable,
Serializable, OptionHandler,
CapabilitiesHandler, RevisionHandler,
CapabilitiesIgnorer lua
//顯式聲明瞭序列化,java對象序列化不只保留一個對象的數據,並且遞歸保存對象引用的每一個對象的數據。序列化運行時使用一個稱爲 serialVersionUID 的版本號與每一個可序列化類相關聯。學習自:http://blog.csdn.net/applehoney/article/details/2278086
private static final long serialVersionUID = 6502780192411755341L;
//是否在調試模式下運行
protected boolean m_Debug = false;
//是否預先檢查分類器適用範圍
protected boolean m_DoNotCheckCapabilities = false;
//做用:對測試實例進行分類
//參數:被分類的實例 返回值:實例被預測的分類或Utils.missingValue()(分類不成功)
//拋出異常:若是預測時發生錯誤
@Override
public double classifyInstance(Instance instance) throws Exception {
//調用distributionForInstance()方法
double[] dist = distributionForInstance(instance);
if (dist == null) {
throw new Exception("Null distribution predicted");
}
switch (instance.classAttribute().type()) {
case Attribute.NOMINAL:
double max = 0;
int maxIndex = 0;
//獲得最大的機率,即最可能的分類類別
for (int i = 0; i < dist.length; i++) {
if (dist[i] > max) {
maxIndex = i;
max = dist[i];
}
}
if (max > 0) {
return maxIndex;
} else {
return Utils.missingValue();
}
case Attribute.NUMERIC:
case Attribute.DATE:
return dist[0];//dist[0]中放置了分類信息
default:
return Utils.missingValue();
}
}
//做用:預測實例的類關係
//返回值:一個包含測試實例在每個可能分類上的分類機率的數組或者一個數值型的預測
//拋出異常:若是機率不能被成功計算
@Override
public double[] distributionForInstance(Instance instance) throws Exception {
double[] dist = new double[instance.numClasses()];//獲得instance類標號的數目並做爲數組長度
switch (instance.classAttribute().type()) {//以整形來判斷屬性的類型
case Attribute.NOMINAL://枚舉型
double classification = classifyInstance(instance);//返回instance的分類
if (Utils.isMissingValue(classification)) {
return dist;//全0數組
} else {
dist[(int) classification] = 1.0;//最可能分類位爲1,其他爲0的數組
}
return dist;
case Attribute.NUMERIC:
case Attribute.DATE:
dist[0] = classifyInstance(instance);//數字或日期型,直接將分類號放置在數組0位
return dist;
default:
return dist;
}
}
//設立一個自定義的分類器,給出名字及操做名稱
//參數:分類器名稱
//參數:操做名稱
//返回:可使用的分類器
//拋出異常:分類器名稱非法,或操做名格式不符不能被接收
public static Classifier forName(String classifierName, String[] options)
throws Exception {
return ((AbstractClassifier) Utils.forName(Classifier.class,
classifierName, options));
}
//使用序列化對分類器進行深拷貝(深、淺拷貝的區別學習自http://www.cnblogs.com/haiyang1985/archive/2009/01/13/1375017.html)
//參數model:將要拷貝的分類器
//返回:特定分類器的深拷貝
//拋出異常:若是發生錯誤
public static Classifier makeCopy(Classifier model) throws Exception {
return (Classifier) new SerializedObject(model).getObject();
}
//做用:用序列化的方法對給定的分類器進行給定數量的深拷貝。
//參數 model:被拷貝的分類器
//參數 num:拷貝的數量
//返回:分類器的數組
//異常:錯誤發生時
public static Classifier[] makeCopies(Classifier model, int num)
throws Exception {
if (model == null) {
throw new Exception("No model classifier set");
}
Classifier[] classifiers = new Classifier[num];
SerializedObject so = new SerializedObject(model);
for (int i = 0; i < classifiers.length; i++) {
classifiers[i] = (Classifier) so.getObject();
}
return classifiers;
}
//做用:返回對操做描述的枚舉
//返回:可用操做的枚舉
@Override
public Enumeration<Option> listOptions() {
Vector<Option> newVector = new Vector<Option>(2);
newVector.addElement(new Option(
"\tIf set, classifier is run in debug mode and\n"
+ "\tmay output additional info to the console", "output-debug-info",
0, "-output-debug-info"));
newVector
.addElement(new Option(
"\tIf set, classifier capabilities are not checked before classifier is built\n"
+ "\t(use with caution).", "-do-not-check-capabilities", 0,
"-do-not-check-capabilities"));
return newVector.elements();
}
//做用:依照給定的操做運行分類實例
//參數:分類器名
//參數:操做名稱
public static void runClassifier(Classifier classifier, String[] options) {
try {
System.out.println(Evaluation.evaluateModel(classifier, options));//輸出驗證後的結果
} catch (Exception e) {
if (((e.getMessage() != null) && (e.getMessage().indexOf(
"General options") == -1))
|| (e.getMessage() == null)) {
e.printStackTrace();
} else {
System.err.println(e.getMessage());
}
}
}
}
public static String evaluateModel()函數比較複雜,含有大量的判斷語句,涉及到模型驗證的許多參數,在這裏咱們暫且擱置。
AbstractClassifier類中其他的是一些簡單的getter和setter,還有一些提示語句,就不列出來了。雖然尚未接觸到具體的分類功能,程序已經變得很是複雜,學習的過程當中,也不能忘了向Weka的做者們致敬,感謝大家無私的付出!