(update 2012.12.28 关于本项目下载及运行的常见问题 FAQ见 newsgroup18828文本分类器、文本聚类器、关联分析频繁模式挖掘算法的Java实现工程下载及运行FAQ )
本文主要内容如下:
对newsgroup文档集进行预处理,提取出30095 个特征词
计算每篇文档中的特征词的TF*IDF值,实现文档向量化,在KNN算法中使用
用JAVA实现了KNN算法及朴素贝叶斯算法的newsgroup文本分类器
1、Newsgroup文档集介绍
Newsgroups最早由Lang于1995收集并在[Lang 1995]中使用。它含有20000篇左右的Usenet文档,几乎平均分配20个不同的新闻组。除了其中4.5%的文档属于两个或两个以上的新闻组以外,其余文档仅属于一个新闻组,因此它通常被作为单标注分类问题来处理。Newsgroups已经成为文本分及聚类中常用的文档集。美国MIT大学Jason Rennie对Newsgroups作了必要的处理,使得每个文档只属于一个新闻组,形成Newsgroups-18828。
2、Newsgroup文档预处理
要做文本分类首先得完成文本的预处理,预处理的主要步骤如下
STEP ONE:
英文词法分析,去除数字、连字符、标点符号、特殊 字符,所有大写字母转换成小写,可以用正则表达式
String res[] = line.split("[^a-zA-Z]");
STEP TWO:
去停用词,过滤对分类无价值的词
STEP THRE:
词根还原stemming,基于Porter算法
文档预处理类
DataPreProcess.java如下
package com.pku.yangliu;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
/**
* Newsgroups文档集预处理类
*/
public class DataPreProcess {
/**输入文件调用处理数据函数
* @param strDir newsgroup文件目录的绝对路径
* @throws IOException
*/
public void doProcess(String strDir) throws IOException{
File fileDir = new File(strDir);
if(!fileDir.exists()){
System.out.println("File not exist:" + strDir);
return;
}
String subStrDir = strDir.substring(strDir.lastIndexOf('/'));
String dirTarget = strDir + "/../../processedSample_includeNotSpecial"+subStrDir;
File fileTarget = new File(dirTarget);
if(!fileTarget.exists()){//注意processedSample需要先建立目录建出来,否则会报错,因为母目录不存在
fileTarget.mkdir();
}
File[] srcFiles = fileDir.listFiles();
String[] stemFileNames = new String[srcFiles.length];
for(int i = 0; i < srcFiles.length; i++){
String fileFullName = srcFiles[i].getCanonicalPath();
String fileShortName = srcFiles[i].getName();
if(!new File(fileFullName).isDirectory()){//确认子文件名不是目录如果是可以再次递归调用
System.out.println("Begin preprocess:"+fileFullName);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(dirTarget + "/" + fileShortName);
createProcessFile(fileFullName, stringBuilder.toString());
stemFileNames[i] = stringBuilder.toString();
}
else {
fileFullName = fileFullName.replace("\\","/");
doProcess(fileFullName);
}
}
//下面调用stem算法
if(stemFileNames.length > 0 && stemFileNames[0] != null){
Stemmer.porterMain(stemFileNames);
}
}
/**进行文本预处理生成目标文件
* @param srcDir 源文件文件目录的绝对路径
* @param targetDir 生成的目标文件的绝对路径
* @throws IOException
*/
private static void createProcessFile(String srcDir, String targetDir) throws IOException {
// TODO Auto-generated method stub
FileReader srcFileReader = new FileReader(srcDir);
FileReader stopWordsReader = new FileReader("F:/DataMiningSample/stopwords.txt");
FileWriter targetFileWriter = new FileWriter(targetDir);
BufferedReader srcFileBR = new BufferedReader(srcFileReader);//装饰模式
BufferedReader stopWordsBR = new BufferedReader(stopWordsReader);
String line, resLine, stopWordsLine;
//用stopWordsBR够着停用词的ArrayList容器
ArrayList<String> stopWordsArray = new ArrayList<String>();
while((stopWordsLine = stopWordsBR.readLine()) != null){
if(!stopWordsLine.isEmpty()){
stopWordsArray.add(stopWordsLine);
}
}
while((line = srcFileBR.readLine()) != null){
resLine = lineProcess(line,stopWordsArray);
if(!resLine.isEmpty()){
//按行写,一行写一个单词
String[] tempStr = resLine.split(" ");//\s
for(int i = 0; i < tempStr.length; i++){
if(!tempStr[i].isEmpty()){
targetFileWriter.append(tempStr[i]+"\n");
}
}
}
}
targetFileWriter.flush();
targetFileWriter.close();
srcFileReader.close();
stopWordsReader.close();
srcFileBR.close();
stopWordsBR.close();
}
/**对每行字符串进行处理,主要是词法分析、去停用词和stemming
* @param line 待处理的一行字符串
* @param ArrayList<String> 停用词数组
* @return String 处理好的一行字符串,是由处理好的单词重新生成,以空格为分隔符
* @throws IOException
*/
private static String lineProcess(String line, ArrayList<String> stopWordsArray) throws IOException {
// TODO Auto-generated method stub
//step1 英文词法分析,去除数字、连字符、标点符号、特殊字符,所有大写字母转换成小写