数据预处理与特征工程
缺失值处理
缺失值处理通常有如下的方法:
对于unknown值数量较少的变量,包括job和marital,删除这些变量是缺失值(unknown)的行;
如果预计该变量对于学习模型效果影响不大,可以对unknown值赋众数,这里认为变量都对学习模型有较大影响,不采取此法;
可以使用数据完整的行作为训练集,以此来预测缺失值,变量housing,loan,education和default的缺失值采取此法。由于sklearn的模型只能处理数值变量,需要先将分类变量数值化,然后进行预测。本次实验使用随机森林预测缺失值
def fill_unknown(data, bin_attrs, cate_attrs, numeric_attrs):
# fill_attrs = ['education', 'default', 'housing', 'loan']
fill_attrs = []
for i in bin_attrs+cate_attrs:
if data[data[i] == 'unknown']['y'].count() < 500:
# delete col containing unknown
data = data[data[i] != 'unknown']
else:
fill_attrs.append(i)
data = encode_cate_attrs(data, cate_attrs)
data = encode_bin_attrs(data, bin_attrs)
data = trans_num_attrs(data, numeric_attrs)
data['y'] = data['y'].map({'no': 0, 'yes': 1}).astype(int)
for i in fill_attrs:
test_data = data[data[i] == 'unknown']
testX = test_data.drop(fill_attrs, axis=1)
train_data = data[data[i] != 'unknown']
trainY = train_data[i]
trainX = train_data.drop(fill_attrs, axis=1)
test_data[i] = train_predict_unknown(trainX, trainY, testX)
data = pd.concat([train_data, test_data])
return data
Feature Extractors(特征提取)
TF-IDF
TF(词频Term Frequency):HashingTF与CountVectorizer都可以用于生成词频TF矢量。
HashingTF是一个转换器(Transformer),它可以将特征词组转换成给定长度的(词频)特征向量组。在文本处理中,“特征词组”有一系列的特征词构成。HashingTF利用hashing trick将原始的特征(raw feature)通过哈希函数映射到低维向量的索引(index)中。这里使用的哈希函数是murmurHash 3。词频(TF)是通过映射后的低维向量计算获得。通过这种方法避免了直接计算(通过特征词建立向量term-to-index产生的)巨大特征数量。(直接计算term-to-index 向量)对一个比较大的语料库的计算来说开销是非常巨大的。但这种降维方法也可能存在哈希冲突:不同的原始特征通过哈希函数后得到相同的值( f(x1) = f(x2) )。为了降低出现哈希冲突的概率,我们可以增大哈希值的特征维度,例如:增加哈希表中的bucket的数量。一个简单的例子:通过哈希函数变换到列的索引,这种方法适用于2的幂(函数)作为特征维度,否则(采用其他的映射方法)就会出现特征不能均匀地映射到哈希值上。默认的特征维度是 218=262,144218=262,144 。一个可选的二进制切换参数控制词频计数。当设置为true时,所有非零词频设置为1。这对离散的二进制概率模型计算非常有用。
CountVectorizer可以将文本文档转换成关键词的向量集。请阅读英文原文CountVectorizer了解更多详情。
IDF(逆文档频率):IDF是的权重评估器(Estimator),用于对数据集产生相应的IDFModel(不同的词频对应不同的权重)。 IDFModel对特征向量集(一般由HashingTF或CountVectorizer产生)做取对数(log)处理。直观地看,特征词出现的文档越多,权重越低(down-weights colume)。
spark代码
package ml
import java.util
import org.apache.spark.ml.feature.HashingTF
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SQLContext}
import org.apache.spark.sql.types.{DataTypes, StructField}
import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer}
/**
* Created by Administrator on 2017/6/6.
*/
object TFIDF {
def main(args: Array[String]) {
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sql = new SQLContext(sc);
val fields = new util.ArrayList[StructField];
fields.add(DataTypes.createStructField("label", DataTypes.DoubleType, true));
fields.add(DataTypes.createStructField("sentence", DataTypes.StringType, true));
val data = sc.parallelize(Seq(
(0.0, "Hi I heard about Spark"),
(0.0, "I wish Java could use case classes"),
(1.0, "Logistic regression models are neat")
))
val structType = DataTypes.createStructType(fields);
val row = data.map {
row => Row(row._1, row._2)
}
val df: DataFrame = sql.createDataFrame(row, structType)
df.printSchema()
df.show()
val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words")
val wordsData = tokenizer.transform(df)
val hashingTF = new HashingTF()
.setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(20)
val featurizedData = hashingTF.transform(wordsData)
// alternatively, CountVectorizer can also be used to get term frequency vectors
val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
val idfModel = idf.fit(featurizedData)
val rescaledData = idfModel.transform(featurizedData)