Weka是新西兰Waikato大学开发的一款开源的基于Java的数据挖掘工具,其官方网址为http://www.cs.waikato.ac.nz/ml/weka/。Weka作为一个公共的数据挖掘的平台,集成了大量的机器学习的算法,包括对数据进行预处理、分类、聚类、回归关联规则等。Weka支持可视化界面操作以及API方式的调用,本文采用API调用方式,基于Weka中集成的KNN算法进行文本分类。
1.语料预处理
文本分类作为监督学习的一种需要提供训练语料,对每一个输入语料文本进行分词处理。
2.特征属性的选取
对于所有的输入语料中的词语,计算其TF*IDF数值,并对每一个词语根据其TF*IDF的数值由高到低排序,选取TOP N(此处N=200)的词语作为特征词语。
3.每一篇语料文档的处理
根据上面统计处理的特征词语,计算每一篇文章中特征词语的TF*IDF数值。
4.CSV文件的生产
CSV文件中每一个语料文本作为一行,形如下图所示:
其中第一行的数据为特征属性,第一列为语料的类别属性。
5.CSV文件转为ARFF文件
在此Weka最终接收的格式为ARFF文件,因此我先把CSV文件转为ARFF文件。ARFF文件格式如下:
其中@relation traindata表示关心的名称 ,@attribute class {food,military,sports,computer,economy}表示类别属性可以的取值,@attribute 农夫山 numeric表示类别属性,@data以下的内容表示对应特征属性的取值。
首先生成ARFF文件的属性信息
InputStreamReader isr = new InputStreamReader(new FileInputStream(csvFile), "UTF-8");
BufferedReader in = new BufferedReader(isr);
String lineStr = in.readLine();
FastVector atts = new FastVector();
List attsList = new ArrayList<Attribute>();
int attrLen = 0;
FastVector attVals = new FastVector();
File clsTypeFile = new File(GlobalUtil.CORPUS_CLS_TYPE);
List<String> clsTypeList = readCorpusFileList(clsTypeFile);
List<String> attrList = new ArrayList<String>();//存放数据所有的属性
if(lineStr!= null){
String[] attr = lineStr.split(",");
attrList = Arrays.asList(attr);
for(String clsType : clsTypeList){
attVals.addElement(clsType);
}
String clsAttr = attr[0];
Attribute classAtts = new Attribute(clsAttr, attVals);
atts.addElement(classAtts);
attsList.add(classAtts);
for(int i = 1;i < attr.length; i++){
Attribute headAtts = new Attribute(attr[i]);
atts.addElement(headAtts);
attsList.add(headAtts);
}
}
读取CSV文件中第一行的内容(特征属性所在行),依次生成每一个特征属性。
下面的代码生成Instance实例,设置关系名称以及类别属性所在列。
Instances instances = new Instances("traindata", atts, 0);
instances.setClassIndex(0);
然后依次读取每一篇语料文本的特征值,为对应的特征属性赋值。
while (lineStr != null) {
if (!lineStr.trim().equals("")) {
logger.info("当前处理的数据是: "+lineStr);
Instance inst = new Instance(attrLen);
String[] dataValue = lineStr.split(",");
Attribute firstAtt = attsList.get(0);
String firstVal = dataValue[0];
inst.setValue(firstAtt, firstVal);
for(int k = 1; k < attrLen; k++ ){
Attribute numAttr = attsList.get(k);
double numVal = Double.parseDouble(dataValue[k]);
inst.setValue(numAttr, numVal);
}
instances.add(inst);
}
lineStr = in.readLine();
}
6.采用Weka中的KNN算法处理ARFF文件
KNN算法在Weka中对应的类名称为IBK,首先读取ARFF文件
File inputFile = new File(GlobalUtil.ARFF_FILE_NAME);// 训练语料文件
ArffLoader arffLoader = new ArffLoader();
arffLoader.setFile(inputFile);
加载KNN,设置需要考察的最近邻的数目,进行分类处理。
IBk classifier = (IBk)Class.forName("weka.classifiers.lazy.IBk").newInstance();//KNN算法分类器
classifier.setKNN(GlobalUtil.NEIGHBOR_NUMS);
classifier.buildClassifier(instancesTrain);
此处我将生成的分类信息保存为模型文件储存起来,方便下次直接进行分类处理,而不必再次进行分类器的训练。
SerializationHelper.write(GlobalUtil.MODEL_FILE_NAME , classifier);//将训练结果保存为模型文件
也可以直接进行分类处理,以当前文件为训练文件,另外选取测试文件进行分类结果测试。
for (int i = 0; i < sum; i++){// 测试分类结果
int preIndex = i + 1;
logger.info("第"+ preIndex +"个样本的判断结果是:" + classifier.classifyInstance(instancesTest.instance(i)));
logger.info("第"+ preIndex +"个样本的类别属性是:" + instancesTest.instance(i).classValue());
boolean flag = false;
if (classifier.classifyInstance(instancesTest.instance(i)) == instancesTest.instance(i).classValue()){// 如果预测值和答案值相等(测试语料中的分类列提供的须为正确答案,结果才有意义)
right++;// 正确值加1
flag = true;
}
logger.info("第"+ preIndex +"个样本的判断结果是否正确:" + flag);
}
System.out.println("KNN classification precision:" + (right / sum));
至此分类处理完成。