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));
至此分类处理完成。