我一直在寻找C4.5算法的C++实现,但至今未能找到。我找到了Quinlan的C4.5 Release 8,但它是用C语言编写的……有没有人见过C4.5算法的开源C++实现?
如果找不到开源的C++实现,我在考虑移植J48源代码(或者简单地在C版本上编写一个包装器),但我希望不必这样做!如果你见过该算法的C++实现,请告诉我。
更新
我一直在考虑为C5.0算法的C实现编写一个轻量级C++包装器(C5.0是C4.5的改进版本)。我下载并编译了C5.0算法的C实现,但看起来它不容易移植到C++。C实现使用了大量的全局变量,仅仅在C函数上编写一个轻量级的C++包装器并不会产生面向对象的设计,因为每个类实例都会修改相同的全局参数。换句话说:我将没有封装性,而这是我非常需要的基本功能。
为了获得封装性,我需要对C代码进行全面的移植到C++,这与将Java版本(J48)移植到C++大致相同。
更新2.0
以下是一些具体要求:
- 每个分类器实例必须封装其自己的数据(即除了常量之外没有全局变量)。
- 支持分类器的并发训练和并发评估。
这里有一个好的场景:假设我在进行10折交叉验证,我希望并发训练10个决策树,每个决策树使用训练集的相应部分。如果我为每个部分运行C程序,我将不得不运行10个进程,这还不算太糟。然而,如果我需要实时分类数千个数据样本,那么我将不得不为每个我想分类的样本启动一个新进程,这效率不高。
回答:
我可能找到了一个C5.0(See5.0)的可能C++“实现”,但我还没有深入研究源代码,无法确定它是否真的如宣传的那样工作。
重申我最初的担忧,该移植的作者对C5.0算法发表了以下看法:
See5Sam [C5.0]的另一个缺点是无法同时拥有多个应用程序树。每次运行可执行文件时,都会从文件中读取应用程序,并将其存储在全局变量中。
一旦我有时间研究源代码,我会更新我的答案。
更新
看起来相当不错,这是C++接口:
class CMee5{ public: /** 从树/规则文件创建一个See 5引擎。 \param pcFileStem See 5文件系统的词干。引擎初始化将查找以下文件: - pcFileStem.names 普通See 5名称文件(必需) - pcFileStem.tree 或 pcFileStem.rules 普通See 5树或规则文件(必需) - pcFileStem.costs 普通See 5成本文件(必需) */ inline CMee5(const char* pcFileStem, bool bUseRules); /** 释放为此引擎分配的内存。 */ inline ~CMee5(); /** 接受数据记录的一般分类例程。 */ inline unsigned int classifyDataRec(DataRec Case, float* pOutConfidence); /** 显示用于分类最后一个案例的规则。 Classify() 将设置 RulesUsed[] 为 试验0的活动规则数量, 第一个活动规则,第二个活动规则,...,最后一个活动规则, 试验1的活动规则数量, 第一个活动规则,第二个活动规则,...,最后一个活动规则, 依此类推。 */ inline void showRules(int Spaces); /** 以给定的扩展名打开文件进行读/写,使用实际的文件词干。 */ inline FILE* GetFile(String Extension, String RW); /** 从文件Df读取一个原始案例。 对于每个属性,从文件中读取属性值。 如果它是离散值属性,查找与此属性值相关联的编号(如果值未知,则为0)。 返回属性值数组。 */ inline DataRec GetDataRec(FILE *Df, Boolean Train); inline DataRec GetDataRecFromVec(float* pfVals, Boolean Train); inline float TranslateStringField(int Att, const char* Name); inline void Error(int ErrNo, String S1, String S2); inline int getMaxClass() const; inline int getClassAtt() const; inline int getLabelAtt() const; inline int getCWtAtt() const; inline unsigned int getMaxAtt() const; inline const char* getClassName(int nClassNo) const; inline char* getIgnoredVals(); inline void FreeLastCase(void* DVec);}
我认为这是我迄今为止找到的最佳替代方案。