通常,在网上找到的mahout的naive bayes的例子跟官网的例子,都是针对20 newsgroup. 而且通常是命令行版本。虽然能得出预测、分类结果,但是对于Bayes具体是如何工作,以及如何处理自己的数据会比较茫然。
在努力了差不多一个星期之后,终于有点成果。
这个例子就是使用mahout 0.9 对kddcup 1999 的数据进行分析。
第一步: 下载数据。
地址: http://kdd.ics.uci.edu/databases/kddcup99/
关于数据的一些简单的预处理,我们会在第二步进行。细心的你可能发现,有些数据是2007年上传的!这是因为有一些数据原来的标记有错误,后来进行了更正。
第二步: 将原始文件转换成Hadoop使用的sequence 文件。
我们从官网知道,Bayes在mahout之中只有基于map-reduce的实现。 参考: https://mahout.apache.org/users/basics/algorithms.html 所以我们必须要将csv文件转换成hadoop使用的sequence文件
先贴一下代码:(注意:这里列的代码,仅仅用于说明流程,并没有注意性能方面的考虑。处理过大的文件的时候,需要有针对性的自行进行调整~)
package experiment.kdd99_bayes; import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.SequenceFile; import org.apache.hadoop.io.Text; import org.apache.mahout.math.RandomAccessSparseVector; import org.apache.mahout.math.Vector; import org.apache.mahout.math.VectorWritable; import au.com.bytecode.opencsv.CSVReader; import com.google.common.collect.Lists; import com.google.common.collect.Maps; public class Kdd99CsvToSeqFile { private String csvPath; private Path seqPath; private SequenceFile.Writer writer; private Configuration conf = new Configuration(); private Map<String, Long> word2LongMap = Maps.newHashMap(); private List<String> strLabelList = Lists.newArrayList(); private FileSystem fs = null; public Kdd99CsvToSeqFile(String csvFilePath, String seqPath) { this.csvPath = csvFilePath; this.seqPath = new Path(seqPath); } public Map<String, Long> getWordMap() { return word2LongMap; } public List<String> getLabelList() { return strLabelList; } /** * Show out the already sequenced file content */ public void dump() { try { fs = FileSystem.get(conf); SequenceFile.Reader reader = new SequenceFile.Reader(fs, this.seqPath, conf); Text key = new Text(); VectorWritable value = new VectorWritable(); while (reader.next(key, value)) { System.out.println( "reading key:" + key.toString() +" with value " + value.toString()); } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { try { fs.close(); fs = null; } catch (IOException e) { e.printStackTrace(); } } } /** * Sequence target csv file. * @param labelIndex * @param hasHeader */ public void parse(int labelIndex, boolean hasHeader) { CSVReader reader = null; try { fs = FileSystem.getLocal(conf); if(fs.exists(this.seqPath)) fs.delete(this.seqPath, true); writer = SequenceFile.createWriter(fs, conf, this.seqPath, Text.class, VectorWritable.class); reader = new CSVReader(new FileReader(this.csvPath)); String[] header = null; if(hasHeader) header = reader.readNext(); String[] line = null; Long l = 0L; while((line = reader.readNext()) != null) { if(labelIndex > line.length) break; l++; List<String> tmpList = Lists.newArrayList(line); String label = tmpList.get(labelIndex); if(!strLabelList.contains(label)) strLabelList.add(label); // Text key = new Text("/" + label + "/" + l); Text key = new Text("/" + label + "/"); tmpList.remove(labelIndex); VectorWritable vectorWritable = new VectorWritable(); Vector vector = new RandomAccessSparseVector(tmpList.size(), tmpList.size());//??? for(int i = 0; i < tmpList.size(); i++) { String tmpStr = tmpList.get(i); if(StringUtils.isNumeric(tmpStr)) vector.set(i, Double.parseDouble(tmpStr)); else vector.set(i, parseStrCell(tmpStr)); } vectorWritable.set(vector); writer.append(key, vectorWritable); } } catch (IOException e) { e.printStackTrace(); } finally { try { fs.close(); fs = null; writer.close(); reader.close(); } catch (IOException e) { e.printStackTrace(); } } } private Long parseStrCell(String str) { Long id = word2LongMap.get(str); if( id == null) { id = (long) (word2LongMap.size() + 1); word2LongMap.put(str, id); } return id; } }
说明一下这个代码的工作流程:
1. 初始化hadoop,比如Configuration 、 FileSystem。
2. 通过Hadoop的 Sequence.Writer进行sequence文件的写入。其中的key/value 分别是Text 跟VectorWritable类型。
3. 通过CSVReader读入CSV文件,然后逐行遍历。如果是带标题的,则先略过第一行。
4. 对于每一行,将Array转成List方便操作。将label列从list之中删除~
5. 对于sequencefile, key为label + row number, 并且,需要以"/"作为开头,否则在实际运行的时候会提示找不到key!
6. 对于sequencefile的value,使用一个Vector进行数据承载。在此使用的是RandomAccessSparseVector,可以试着使用DenseVector进行测试,看看是否在性能上会有所改善。
在用Bayes试过了好几种数据之后,感觉对于Bayes,最关键的一步其实是在这里,因为选择那些feature、原始数据如何预处理就在这里进行了,剩下的都是模板一样的代码~ 即使命令行也一样。
第三步: 训练Bayes
在这里仅仅先贴出训练部分的代码,整体的代码最后上传
public static void train() throws Throwable { System.out.println("~~~ begin to train ~~~"); Configuration conf = new Configuration(); FileSystem fs = FileSystem.getLocal(conf); TrainNaiveBayesJob trainNaiveBayes = new TrainNaiveBayesJob(); trainNaiveBayes.setConf(conf); String outputDirectory = "/home/hadoop/DataSet/kdd99/bayes/output"; String tempDirectory = "/home/hadoop/DataSet/kdd99/bayes/temp"; fs.delete(new Path(outputDirectory),true); fs.delete(new Path(tempDirectory),true); // cmd sample: mahout trainnb -i train-vectors -el -li labelindex -o model -ow -c trainNaiveBayes.run(new String[] { "--input", trainSeqFile, "--output", outputDirectory, "-el", "--labelIndex", "labelIndex", "--overwrite", "--tempDir", tempDirectory }); // Train the classifier naiveBayesModel = NaiveBayesModel.materialize(new Path(outputDirectory), conf); System.out.println("features: " + naiveBayesModel.numFeatures()); System.out.println("labels: " + naiveBayesModel.numLabels()); }
从上面的代码可以看到,熟悉命令行之后,在实际java代码编写的时候,传入进去的也是一些命令行参数。
(可能有其他方法,只是目前我还不了解~)
命令行:
// cmd sample: mahout trainnb -i train-vectors -el -li labelindex -o model -ow -c
Java代码:
trainNaiveBayes.run
最后一步: 使用测试数据进行性能验证。
public static void test() throws IOException { System.out.println("~~~ begin to test ~~~"); AbstractVectorClassifier classifier = new ComplementaryNaiveBayesClassifier(naiveBayesModel); CSVReader csv = new CSVReader(new FileReader(testFile)); csv.readNext(); // skip header String[] line = null; double totalSampleCount = 0.; double correctClsCount = 0.; while((line = csv.readNext()) != null) { totalSampleCount ++; Vector vector = new RandomAccessSparseVector(40,40);//??? for(int i = 0; i < 40; i++) { if(StringUtils.isNumeric(line[i])) { vector.set(i, Double.parseDouble(line[i])); } else { Long id = strOptionMap.get(line[i]); if(id != null) vector.set(i, id); else { System.out.println(StringUtils.join(line, ",")); continue; } } } Vector resultVector = classifier.classifyFull(vector); int classifyResult = resultVector.maxValueIndex(); if(StringUtils.equals(line[41], strLabelList.get(classifyResult))) { correctClsCount++; } else { System.out.println("Correct=" + line[41] + "\tClassify=" + strLabelList.get(classifyResult) ); } } System.out.println("Correct Ratio:" + (correctClsCount / totalSampleCount)); }
可以看到上面的加粗部分,用的是ComplementaryNaiveBayesClassifier,另外一个贝叶斯分类器就是
StandardNaiveBayesClassifier
最后运算的结果不太好,仅有约63%的正确率~
大家可以参考下面使用Bayes对Tweet进行分类的例子,正确率能有98%这样!当然,需要各位有过功夫网的本领了~
PS: 全部java代码已经在附件之中,感兴趣的还请自取~
相关推荐
- **分类**:包括朴素贝叶斯(Naive Bayes)、决策树(Decision Trees)等,用于将数据分配到预定义的类别中。 - **聚类**:如K-Means算法,用于将数据点分成多个群组,使同组内的数据点相互接近,而不同组的数据...
- mahout-core-0.9.jar:作为最新版本,它集成了更多的改进和新特性,包括算法的优化、API的调整以及对大数据处理的进一步支持。 4. **API变化**: 随着版本的更新,Mahout的API可能会发生变化,比如引入新的接口...
1. **数据预处理**:首先,我们需要对文本数据进行预处理,包括分词(tokenize)、去除停用词、词干提取等。在这个案例中,`tokenize`可能就是预处理过程中分词的表示,将原始文本分解成有意义的词汇单元。 2. **...
3. **分类(Classification)**:如随机森林(Random Forest)、朴素贝叶斯(Naive Bayes)等,用于根据已知特征对数据进行分类。这些模型在垃圾邮件过滤、情感分析等方面表现出色。 三、分布式计算与Hadoop集成 ...
【朴素贝叶斯文本分类器】是机器学习...对于压缩包文件"naive-bayes-text-classifier-master",可能包含了实现该分类器的源代码、样例数据和相关文档,通过深入研究这些内容,你可以更深入地理解和应用朴素贝叶斯方法。
2. **聚类**:包括K-Means、Fuzzy K-Means和Canopy Clustering等算法,可以对数据集进行无监督学习,将相似的数据点分组到一起,形成不同的簇。 3. **分类**:支持如Naive Bayes和Random Forest等监督学习算法,...
2. **分类与回归**:Mahout支持决策树(如C4.5)、随机森林和感知机等算法,用于对数据进行分类和预测。 3. **聚类**:包括K-Means、Fuzzy K-Means、Canopy Clustering、DBSCAN等算法,可用于将相似的数据点分组到...
【推荐算法】是一种重要的机器学习...通过对Chubbyjiang在GitHub上分享的数据集进行分析和处理,我们可以深入理解Mahout的协同过滤算法以及MapReduce在大数据环境下的工作原理,从而构建出更高效、更精准的推荐系统。
**正文** 《Mahout文本训练测试...通过对这些数据进行处理和建模,我们可以提升对Mahout的理解,同时也能掌握如何处理大规模文本数据的技巧,这对于任何涉足大数据和人工智能领域的专业人士来说都是至关重要的技能。
- **分类(Classification)**: Mahout包含了多种分类算法,如朴素贝叶斯(Naive Bayes)、决策树(Decision Trees)和随机森林(Random Forests),这些算法常用于文本分类和垃圾邮件过滤等场景。 - **聚类...
"mahout-distribution-0.9含jar包" 是一个包含了Mahout项目0.9版本的预编译二进制文件集合,其中不包含源代码,适合那些希望直接使用Mahout功能而不需要进行编译或开发的用户。 在Mahout 0.9版本中,你可以找到以下...
4. **预处理数据**:如果需要,可以使用Mahout的工具对数据进行预处理,例如规范化或归一化。 5. **运行K-Means**:使用Mahout提供的命令行接口,指定输入数据、K值(预定义的群组数量)、迭代次数和其他参数。 6. *...
在使用Mahout时,开发者可以利用Hadoop进行分布式计算,处理大规模数据集。这使得Mahout成为大数据背景下理想的机器学习平台。此外,Mahout还与Apache Spark集成,提高了算法的执行效率。 总的来说,Apache Mahout...
这个"apache-mahout-distribution-0.10.2"压缩包包含的是Mahout的0.10.2版本,该版本是2014年发布的一个稳定版本,旨在帮助大数据研发人员构建和实现复杂的机器学习模型。 在大数据领域,机器学习是关键的技术之一...
《Apache Maven与Mahout实战:基于maven_mahout_template-mahout-0.8的探索》 Apache Maven是一款强大的项目管理和依赖管理工具,广泛应用于Java开发领域。它通过一个项目对象模型(Project Object Model,POM)来...
在Mahout Taste Webapp工程中,需要添加对mahout-examples的依赖,这一步骤是必须的,因为示例代码提供了实际运行推荐系统所必需的组件。 6. 配置推荐引擎的属性 在Mahout Taste Webapp的recommender.properties...
- **分类(Classification)**: Mahout 提供了多种监督学习算法,如朴素贝叶斯(Naive Bayes)、决策树(Decision Trees)和随机森林(Random Forests),用于预测目标变量的值。 - **聚类(Clustering)**: 包括K-...
2. 解压`mahout-distribution-0.7-src.zip`文件到本地目录。 3. 进入解压后的源码目录,执行`mvn clean install`命令进行编译。这会下载依赖项,构建Mahout的jar包。 4. 编译完成后,可以在`target`目录下找到编译...
mahout-examples-0.11.1 mahout-examples-0.11.1-job mahout-h2o_2.10-0.11.1 mahout-h2o_2.10-0.11.1-dependency-reduced mahout-hdfs-0.11.1 mahout-integration-0.11.1 mahout-math-0.11.1 mahout-math-0.11.1 ...