特征选择

RFormula

RFormula是一个很方便,也很强大的Feature选择(自由组合的)工具。 
输入string 进行独热编码(见下面例子country) 
输入数值型转换为double(见下面例子hour) 
label为string,也用StringIndexer进行编号

RFormula produces a vector column of features and a double or string
column of label. Like when formulas are used in R for linear regression,
string input columns will be one-hot encoded, and numeric columns will be
cast to doubles. If the label column is of type string, it will be first
transformed to double with StringIndexer. If the label column does not exist
in the DataFrame, the output label column will be created from the specified
response variable in the formula.
如输入数据为
+---+-------+----+------+-------+
| id|country|hour|salary|clicked|
+---+-------+----+------+-------+
| | US| |2500.0| 1.0|
| | CA| |1500.0| 0.0|
| | NZ| |1250.0| 0.0|
| | US| |3200.0| 1.0|
+---+-------+----+------+-------+
使用RFormula:
RFormula formula = new RFormula()
.setFormula("clicked ~ country + hour + salary")
//clicked作为label,~之后的三个为选择的特征
.setFeaturesCol("features")
.setLabelCol("label");
+---------------------+-----+
|features |label|
+---------------------+-----+
|[1.0,0.0,18.0,2500.0]|1.0 |
|[0.0,0.0,12.0,1500.0]|0.0 |
|[0.0,1.0,15.0,1250.0]|0.0 |
|[1.0,0.0,10.0,3200.0]|1.0 |
+---------------------+-----+
[1.0,0.0]为"US"的独热编码,以此类推

卡方独立检验

ChiSqSelector 
参考: 
http://www.blogjava.net/zhenandaci/archive/2008/08/31/225966.html 
里面举得例子很好理解(原文真的很通俗易懂,直接参考原文吧,瞬间明白的感觉)。

在Spark中似乎非常慢???

ChiSqSelector chiSqSelector=new ChiSqSelector()
.setFeaturesCol("TF")
.setOutputCol("features")
.setLabelCol("label")
.setNumTopFeatures();
Dataset<Row> wordsChiSq=chiSqSelector.fit(wordsTF).transform(wordsTF);

文本转换及特征提取

英文分词

中文分词

中文分词工具比较多,Java,Python版本都有,这里以IKAnalyzer2012+Java版本为例说明。 
     使用时参考IKAnalyzer2012自带的中文帮助文档(有比较详细的用法)。 
     IKAnalyzer2012它 的 安 装 部 署 十 分 简 单 , 将 IKAnalyzer2012.jar 部 署 于 项 目 的 lib 目 录 中 ;IKAnalyzer.cfg.xml 与 stopword.dic 文件放置在 class 根目录。 
     依赖Lucene的类org.wltea.analyzer.luceneorg.wltea.analyzer,分词主类。

//创建分词对象
Analyzer anal=new IKAnalyzer(true);
StringReader reader=new StringReader(row.getString());
//分词
TokenStream ts=anal.tokenStream("", reader);
CharTermAttribute term=(CharTermAttribute) ts
.getAttribute(CharTermAttribute.class);
//遍历分词数据
String words="";
while(ts.incrementToken()){
words+=(term.toString()+"|");
}

正则表达式分词

word2vect

TF-IDF

去停用词

应用例子

下面是一个综合的实例子,用到了Spark的一些特征转换API。由于需要处理中文,还需要一个分词器。

准备语料

(I)首先准备一个数据集,谭松波老师收集的中文情感分析酒店评论语料 
从CSDN上可以下载:http://download.csdn.net/download/x_i_y_u_e/9273533 
1、-ChnSentiCorp-Htl-ba-2000: 平衡语料,正负类各1000篇。 
2、ChnSentiCorp-Htl-ba-4000: 平衡语料,正负类各2000篇。 
3、ChnSentiCorp-Htl-ba-6000: 平衡语料,正负类各3000篇。 
4、ChnSentiCorp-Htl-unba-10000: 非平衡语料,正类为7000篇。

(II) 在linux下是乱码的,需要转换: 
编码查看: 
%file -i neg.9.txt 
neg.9.txt: text/plain; charset=iso-8859-1 
需要转换为utf8 
%iconv -f gb18030 -t utf8 neg.9.txt -o neg.9.o.txt 
-f :from -t :to 
批量转如下: 
(1)复制文件目录 find ChnSen* -type d -exec mkdir -p utf/{} \; 
(2)转换 find ChnSen* -type f -exec iconv -f GBK -t UTF-8 {} -o utf/{} \; 
ChnSen*是单前文件夹下的目录,utf是输出目录

(III) python 处理文件,合并为一个文件,去掉一条评论中所有换行

# -*- coding: utf- -*-
#将所有评论读入到一个文件中,每个原始文件文件为一条评论,中间不要出现换行
#repalce("\r"," "),是将^M(window下产生的 linux不认识的换行)去掉
#输出csv格式 path_out="E:/data/utf/ChnSentiCorp_htl_ba_2000/all.csv"
fw=open(path_out,'w+') #负样本
for i in range(): path1="E:/data/utf/ChnSentiCorp_htl_ba_2000/neg."+str(i+)+".txt"
fr=open(path1)
lines=fr.readlines() fw.write("0.0,")#label for line in lines:
#repalce("\r"," "),是将^M(window下产生的 linux不认识的换行)去掉
#replace(",",""),是为输出CSV格式做准备
line=line.replace("\r",'').strip().replace(",","")
fw.write(line) fw.write("\n")
fr.close() #正样本
for i in range(): path2="E:/data/utf/ChnSentiCorp_htl_ba_2000/pos."+str(i+)+".txt"
fr=open(path2) fw.write("1.0,")#label lines=fr.readlines()
for line in lines:
line=line.replace("\r",'').strip().replace(",","")
fw.write(line)
fw.write("\n") fr.close() fw.close

完整流程

可参考论文(只是分词工具不同): 
基于 Spark 的文本情感分析 
http://www.ibm.com/developerworks/cn/cognitive/library/cc-1606-spark-seniment-analysis/index.html 
思路是一样的,不过我是用Java实现的,写起来远远不如Python简洁。

//初步完整的流程,还需要进一步优化
//IKAnalyzer2012分词->TF-IDF特征->NaiveBayes ML package my.spark.ml.practice.classification; import org.apache.spark.api.java.function.MapFunction;
import org.apache.spark.ml.classification.NaiveBayes;
import org.apache.spark.ml.classification.NaiveBayesModel; import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator; import org.apache.spark.ml.feature.HashingTF;
import org.apache.spark.ml.feature.IDF;
import org.apache.spark.ml.feature.IDFModel;
import org.apache.spark.ml.feature.RegexTokenizer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Encoder;
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import java.io.IOException;
import java.io.StringReader;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; //引用IKAnalyzer2012的类
import org.wltea.analyzer.lucene.IKAnalyzer; import my.spark.ml.practice.classification.LabelValue;; //文本处理,酒店评论
public class myHotelTextClassifer3 { public static void main(String[] args) throws IOException { SparkSession spark=SparkSession
.builder()
.appName("Chinese Text Processing")
.master("local[4]")
.config("spark.sql.warehouse.dir",
"file///:G:/Projects/Java/Spark/spark-warehouse" )
.getOrCreate(); //屏蔽日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN);
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);
//--------------------------(0)读入数据,数据预处理--------------------------------
//原始数据文件包含两行,一行是label,一行是sentence,csv格式的
Dataset<Row> raw=spark.read().format("csv")
.load("E:/data/utf/ChnSentiCorp_htl_ba_2000/all.csv"); //去掉空值,不然一定后面一定抛出nullpointer异常
//distinct数据去重 ,并打乱数据的顺序:不然数据是先负样本后正样本有规律排列的,预测效果偏高
Dataset<Row> rawFilterNaN=raw
.filter(raw.col("_c0").isNotNull())
.filter(raw.col("_c1").isNotNull())
.distinct(); //--------------------------(1)分词----------------------------------------
//为Map自定义了Class LabelValue,见后面
Encoder<LabelValue> LongStringEncoder=Encoders.bean(LabelValue.class);
Dataset<LabelValue> wordsDF=rawFilterNa.map(new MapFunction<Row,LabelValue>() {
@Override
public LabelValue call(Row row) throws Exception {
if (row!=null) {
LabelValue ret = new LabelValue();
double Label=1.0;
if (row.getString().equals("0.0")) {
Label=0.0;
}else{
Label=1.0;
}
ret.setLabel(Label); //-------------KAnalyzer分词--------------------
//创建分词对象
Analyzer anal=new IKAnalyzer(true);
StringReader reader=new StringReader(row.getString());
//分词
TokenStream ts=anal.tokenStream("", reader);
CharTermAttribute term=(CharTermAttribute) ts
.getAttribute(CharTermAttribute.class);
//遍历分词数据
String words="";
while(ts.incrementToken()){
words+=(term.toString()+"|");
}
ret.setValue(words);
reader.close(); return ret;
}
else {
return null;
}
} }, LongStringEncoder); //--------------------------(1)-2 RegexTokenizer分词器-----------------------------
RegexTokenizer regexTokenizer = new RegexTokenizer()
.setInputCol("value")
.setOutputCol("words")
.setPattern("\\|"); Dataset<Row> wordsDF2 = regexTokenizer.transform(wordsDF); //--------------------------(2) HashingTF训练词频矩阵--------------------------------- HashingTF tf=new HashingTF()
.setInputCol("words")
.setOutputCol("TF");
Dataset<Row> wordsTF=tf.transform(wordsDF2).select("TF","label");
wordsTF.show();wordsTF.printSchema();
Dataset<Row> wordsTF2=wordsTF
.filter(wordsTF.col("TF").isNotNull())
.filter(wordsTF.col("label").isNotNull()); //------------------------- (4)计算 TF-IDF 矩阵--------------------------------------
IDFModel idf=new IDF()
.setInputCol("TF")
.setOutputCol("features")
.fit(wordsTF2);
Dataset<Row> wordsTfidf=idf.transform(wordsTF2); //----------------------------(5)NaiveBayesModel ML---------------------
Dataset<Row>[] split=wordsTfidf.randomSplit(new double[]{0.6,0.4});
Dataset<Row> training=split[];
Dataset<Row> test=split[]; NaiveBayes naiveBayes=new NaiveBayes()
.setLabelCol("label")
.setFeaturesCol("features");
NaiveBayesModel naiveBayesModel=naiveBayes.fit(training); Dataset<Row> predictDF=naiveBayesModel.transform(test); //自定义计算accuracy
double total=(double) predictDF.count();
Encoder<Double> doubleEncoder=Encoders.DOUBLE(); Dataset<Double> accuracyDF=predictDF.map(new MapFunction<Row,Double>() {
@Override
public Double call(Row row) throws Exception {
if((double)row.get()==(double)row.get()){return 1.0;}
else {return 0.0;}
}
}, doubleEncoder); accuracyDF.createOrReplaceTempView("view");
double correct=(double) spark.sql("SELECT value FROM view WHERE value=1.0").count();
System.out.println("accuracy "+(correct/total)); //计算areaUnderRoc
double areaUnderRoc=new BinaryClassificationEvaluator()
.setLabelCol("label")
.setRawPredictionCol("prediction")
.evaluate(predictDF);
//(areaUnderROC|areaUnderPR) (default: areaUnderROC)
System.out.println("areaUnderRoc "+areaUnderRoc);
}
} //结果分析
//accuracy 0.7957860615883307
//areaUnderRoc 0.7873761854583772
//应该还有提升的空间 //Class LabelValue
package my.spark.ml.practice.classification; import java.io.Serializable; public class LabelValue implements Serializable {
private String value;
private double label; public String getValue() {
return value;
} public void setValue(String value) {
this.value = value;
} public double getLabel() {
return label;
} public void setLabel(double label) {
this.label = label;
}
}

先使用word2vect,然后将词产生的向量作为特征,分别用随机森林,GBTC, 
LogisticRegression,其中GBTC效果最好。但是普遍不如Naive-Bayes,可能还需要某些地方进行改进。

//转换为词向量,并进行标准化
Word2Vec word2Vec=new Word2Vec()
.setInputCol("words")
.setOutputCol("vect")
.setVectorSize();
Dataset<Row> vect=word2Vec
.fit(wordsDF2)
.transform(wordsDF2);
//vect.show();vect.printSchema();
//正则化
Dataset<Row> vect2=new MinMaxScaler()
.setInputCol("vect")
.setOutputCol("features")
.setMax(1.0)
.setMin(0.0)
.fit(vect)
.transform(vect);
//vect2.show();vect2.printSchema(); //GBTC分类
GBTClassifier gbtc=new GBTClassifier()
.setLabelCol("label")
.setFeaturesCol("vect")
.setMaxDepth()
.setMaxIter()
.setStepSize(0.1);
Dataset<Row> predictDF=gbtc.fit(training0).transform(test0);
//其余代码是一样的,可以尝试不同的参数组合。

Spark2.0 特征提取、转换、选择之二:特征选择、文本处理,以中文自然语言处理(情感分类)为例的更多相关文章

  1. Spark2.0 特征提取、转换、选择之一:数据规范化,String-Index、离散-连续特征相互转换

    数据规范化(标准化) 在数据预处理时,这两个术语可以互换使用.(不考虑标准化在统计学中有特定的含义). 下面所有的规范化操作都是针对一个特征向量(dataFrame中的一个colum)来操作的. 首先 ...

  2. Spark2.0机器学习系列之1: 聚类算法(LDA)

    在Spark2.0版本中(不是基于RDD API的MLlib),共有四种聚类方法:      (1)K-means      (2)Latent Dirichlet allocation (LDA)  ...

  3. Spark2.0机器学习系列之3:决策树

    概述 分类决策树模型是一种描述对实例进行分类的树形结构. 决策树可以看为一个if-then规则集合,具有“互斥完备”性质 .决策树基本上都是 采用的是贪心(即非回溯)的算法,自顶向下递归分治构造. 生 ...

  4. geotrellis使用(二十五)将Geotrellis移植到spark2.0

    目录 前言 升级spark到2.0 将geotrellis最新版部署到spark2.0(CDH) 总结 一.前言        事情总是变化这么快,前面刚写了一篇博客介绍如何将geotrellis移植 ...

  5. Spark2.0机器学习系列之2:基于Pipeline、交叉验证、ParamMap的模型选择和超参数调优

    Spark中的CrossValidation Spark中采用是k折交叉验证 (k-fold cross validation).举个例子,例如10折交叉验证(10-fold cross valida ...

  6. Spark2.0机器学习系列之5:随机森林

    概述 随机森林是决策树的组合算法,基础是决策树,关于决策树和Spark2.0中的代码设计可以参考本人另外一篇博客: http://www.cnblogs.com/itboys/p/8312894.ht ...

  7. 图文解析Spark2.0核心技术(转载)

    导语 Spark2.0于2016-07-27正式发布,伴随着更简单.更快速.更智慧的新特性,spark 已经逐步替代 hadoop 在大数据中的地位,成为大数据处理的主流标准.本文主要以代码和绘图的方 ...

  8. Spark2.0机器学习系列之12: 线性回归及L1、L2正则化区别与稀疏解

    概述 线性回归拟合一个因变量与一个自变量之间的线性关系y=f(x).       Spark中实现了:       (1)普通最小二乘法       (2)岭回归(L2正规化)       (3)La ...

  9. Spark2.0机器学习系列之9: 聚类(k-means,Bisecting k-means,Streaming k-means)

    在Spark2.0版本中(不是基于RDD API的MLlib),共有四种聚类方法:      (1)K-means      (2)Latent Dirichlet allocation (LDA)  ...

随机推荐

  1. 使用Navicat连接阿里云服务器上的MySQL数据库=======Linux 开放 /etc/hosts.allow

    使用Navicat连接阿里云服务器上的MySQL数据库   1.首先打开Navicat,文件>新建连接> 2,两张连接方法 1>常规中输入数据库的主机名,端口,用户名,密码 这种直接 ...

  2. php 的rabbitmq 扩展模块amqp安装

    php 的rabbitmq 扩展模块amqp安装 2017年10月08日 10:34:22 阅读数:240 使用PHP开发,要使用中间队列rabbitmq, 必须要安装PHP的扩展模块amqp, 服务 ...

  3. C++ 类中的const关键字

    //类中的const关键字 #include<iostream> using namespace std; class Point{ public: //这个const关键字本质上修饰的是 ...

  4. 若在逻辑上 A 是 B 的“一部分”(a part of)

    若在逻辑上 A 是 B 的“一部分”(a part of) ,则不允许 B 从 A 派生, 而是要用 A 和其它东西组合出 B. #include <iostream> /* run th ...

  5. C语言0长度数组(柔性数组)

    0长度数组,又称为柔性数组(flexible array).通经常使用来实现变长数组.常见于TLV(type-length-value)的数据结构中. 在标准 C 和 C++ 中,不同意用 0 长度数 ...

  6. IOS7开发~新UI学起(一)

    本文转载至:http://blog.csdn.net/lizhongfu2013/article/details/9124893 IOS7在UI方面发生了很大改变,所以感觉有必要重新审视的学习一下(新 ...

  7. 一 Android Studio 打包Egret App

    测试环境: Android Studio 2.3.2 Egret Engine 5.0.14 Egret Support5.0.12 官网教程:http://developer.egret.com/c ...

  8. [SharePoint 2010] 如何在小組網站內頁面上撥放影片或是音效檔

    在SharePoint 2010中, 我們可以像是Youtube一樣在網頁上撥放影片或是音效檔案. 影片或音效是採取串流的方式來撥放. 也就是說我們不需要把整個檔案都下載回來才開始撥放. 點選沒多久我 ...

  9. 170410、java Socket通信的简单例子(TCP)

    服务端代码: package com.bobohe.socket; import java.io.*; import java.net.*; import java.applet.Applet; pu ...

  10. JavaScript面向对象OOP思想Class系统

    JavaScript的Class模块,纯天然无依赖,只有2k大小,快速高效,让我们优雅的面向对象... | |目录 1源码:jClass.js 2源码:jClass.min.js 3构建一个类 4访问 ...