好久没写博客了,最近搞了一个文本分类器,在此记录一下:
简介:
支持向量机,因其英文名为support vector machine,故一般简称SVM,通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。
1 “机” —— Classification Machine,分类器
2 “支持向量” —— 他们就是离分界线最近的向量。也就是说分界面是靠这些向量确定的,他们支撑着分类面。名字就是这么来的...(就是离最优分类平面最近的离散点,也可以称为向量)
spark自带了一个svm实现的dome,该dome直接读取保存libsvm所需稀疏向量的文件,但是并未提供向量化方法,需自己调用HashingTF、IDF转换为稀疏向量
代码:
-
/**
-
* SVM分类对象
-
* @author wangzengxu
-
*/
-
object SVM{
-
-
def main(args: Array[String]){
-
-
val Array(
-
rightPath, // 正面训练集路径
-
negativePath, // 负面训练集路径
-
waitData, // 待分类数据存放路径
-
vectorsLocl, // 向量存放路径
-
iterativeNum // 迭代次数
-
) = args
-
-
var sparkconf = new SparkConf().setAppName("wzx_svm_classificationsV2")
-
var sc = new SparkContext(sparkconf)
-
-
sc.addJar("/usr/wzx/spark/svm/SVM_WZX_lib/IKAnalyzer2012_u6.jar");
-
sc.addJar("/usr/wzx/spark/svm/SVM_WZX_lib/lucene-analyzers-common-4.3.0.jar");
-
sc.addJar("/usr/wzx/spark/svm/SVM_WZX_lib/lucene-core-4.3.0.jar");
-
sc.addJar("/usr/wzx/spark/svm/SVM_WZX_lib/lucene-queryparser-4.3.0.jar");
-
-
val train_vectors_local = vectorsLocl+"/train-"+DateUtils.getNowDate() //训练向量存放目录
-
val wait_vectors_local = vectorsLocl+"/wait-"+DateUtils.getNowDate() //待分向量存放目录
-
-
val data_path_right = rightPath //正面训练集文章路径文件 每行一篇
-
val data_path_negative = negativePath //负面训练集文章路径文件 每行一篇
-
val data_path_wait = waitData //待分数据存放路径
-
val iterative_number = iterativeNum.toInt //训练模型迭代次数
-
-
/***********************start 分词******************************************/
-
-
val right_data = sc.textFile(data_path_right)
-
-
val negative_data = sc.textFile(data_path_negative)
-
-
val wait_data = sc.textFile(data_path_wait)
-
-
//去停用词
-
-
val right_text = right_data.map { x =>
-
val str = IKUtils.participle(x)
-
(1,str) //正面1
-
}
-
-
val negative_text = negative_data.map { x =>
-
val str = IKUtils.participle(x)
-
(0,str) //负面0
-
}
-
-
val wait_text = wait_data.map { x =>
-
val str = IKUtils.participle(x)
-
(2,str) //待分2
-
}
-
-
val data_all_train = right_text.++(negative_text) //训练集RDD合并
-
-
/***********************end 分词******************************************/
-
-
-
-
/***********************start 向量化******************************************/
-
-
val hashingTF = new HashingTF(Math.pow(2, 18).toInt)
-
-
//训练集TF向量化
-
val documents_train = data_all_train.map{
-
case(num,str) =>
-
(num,str.split(" ").toSeq)
-
}
-
-
val tf_num_pairs_train = documents_train.map {
-
case (num,seq) =>
-
val tf = hashingTF.transform(seq)
-
(num,tf)
-
}
-
-
//待分类TF向量化
-
val documents_wait = wait_text.map{
-
case(num,str) =>
-
(num,str.split(" ").toSeq)
-
}
-
-
val tf_num_pairs_wait = documents_wait.map {
-
case (num,seq) =>
-
val tf = hashingTF.transform(seq)
-
(num,tf)
-
}
-
-
tf_num_pairs_train.cache()
-
tf_num_pairs_wait.cache()
-
-
-
//利用训练集TF构建IDF MODEL
-
val idf = new IDF().fit(tf_num_pairs_train.values)
-
-
-
//将训练集tf向量转换成tf-idf向量
-
val num_idf_pairs_train = tf_num_pairs_train.mapValues(v => idf.transform(v))
-
//将待分类数据集tf向量转换成tf-idf向量
-
val num_idf_pairs_wait = tf_num_pairs_wait.mapValues(v => idf.transform(v))
-
-
//格式转换
-
val trainCollection = num_idf_pairs_train.map{
-
case(num,vector) =>
-
val vectorStr = num +" "+VectorToStr.change(vector)
-
vectorStr
-
}
-
-
val waitCollection = num_idf_pairs_wait.map{
-
case(num,vector) =>
-
val vectorStr = num +" "+VectorToStr.change(vector)
-
vectorStr
-
}
-
-
//落地 (后期可参看MLUtils源码来直接转换为LabeledPoint避免落地)
-
trainCollection.coalesce(1).saveAsTextFile(train_vectors_local)
-
waitCollection.coalesce(1).saveAsTextFile(wait_vectors_local)
-
-
/***********************end 向量化******************************************/
-
-
/***********************start SVM模型训练******************************************/
-
-
val vectors_train = MLUtils.loadLibSVMFile(sc,train_vectors_local).cache()
-
val vectors_wait = MLUtils.loadLibSVMFile(sc,wait_vectors_local).cache()
-
-
-
//1 新建SVM模型,并设置训练参数
-
-
val numIterations = iterative_number //迭代次数,并非越大越好,需根据训练集不断调整来确定该值
-
-
val stepSize = 1
-
-
val miniBatchFraction = 1.0 //步长
-
-
val model = SVMWithSGD.train(vectors_train, numIterations, stepSize, miniBatchFraction)
-
/***********************start SVM模型训练******************************************/
-
-
-
/***********************start 分类******************************************/
-
-
//4 对待分类数据向量进行分类
-
-
println("---------------训练完成------------------------")
-
-
val prediction_wait = model.predict(vectors_wait.map(_.features))
-
-
println("---------------分类完成------------------------")
-
-
prediction_wait.saveAsTextFile("/user/wzx/cs1")
-
-
println("---------------保存完成------------------------")
-
-
/***********************end 分类******************************************/
-
-
-
}
-
}
-
-
/**
-
* IK分词 去掉停用词处理
-
* @author wangzengxu
-
*
-
*/
-
public class IKUtils {
-
-
-
-
public static String participle(String text){
-
StringBuffer result = new StringBuffer();
-
//读入停用词文件
-
BufferedReader StopWordFileBr = new BufferedReader(new InputStreamReader(IKUtils.class.getResourceAsStream("/stopword.dic"))); //注意jar包路径问题
-
//用来存放停用词的集合
-
Set<String> stopWordSet = new HashSet<String>();
-
//初如化停用词集
-
String stopWord = null;
-
try {
-
for(; (stopWord = StopWordFileBr.readLine()) != null;){
-
stopWordSet.add(stopWord);
-
}
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
//创建分词对象
-
StringReader sr=new StringReader(text);
-
IKSegmenter ik=new IKSegmenter(sr, false);
-
Lexeme lex=null;
-
//分词
-
try {
-
while((lex=ik.next())!=null){
-
//去除停用词
-
if(stopWordSet.contains(lex.getLexemeText())) {
-
continue;
-
}
-
result.append(lex.getLexemeText()+" ");
-
}
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
//关闭流
-
try {
-
StopWordFileBr.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
return result.toString();
-
}
-
-
}
dome中提供了评分代码,在模型训练时需要根据评分来不断调整迭代次数等来达到满意的精度。当然,这个dome还有很多优化空间
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29754888/viewspace-1967758/
,如需转载,请注明出处,否则将追究法律责任。