包括分句、分词和词干化,使用nltk可以实现。
实现分两个版本:1. scikit-learn版本 2. MLLIB版本
主要是因为运行效率的问题,基于spark的mllib采用分布式的训练算法,速度快很多。
tf-idf是基本的文本分类特征提取方法,它是词袋模型的一个信息量衡量方式,也是常用的基准方法。本文就是用tf-idf来构建文本特征,后面会提到使用word2vec进行改进。
sklearn库提供tf-idf类,很方便就可以将文本转为向量,还可以定义许多参数,如ngram、最小df、停用词、分词器等
stopword_list = ["it", "this"] # example
vectorizer = TfidfVectorizer(min_df=2, ngram_range=(1,2),
stop_words=stopword_list)
X = vectorizer.fit_transform(corpus).toarray()
mllib上许多api都仿照sklearn,所以对sklearn熟悉的人都很容易上手。在这里,我们使用Python语言进行Spark(1.4.1)代码的编写。
from pyspark import SparkContext
from pyspark.mllib.feature import HashingTF
sc = SparkContext()
# Load documents (one per line).
documents = sc.textFile("...").map(lambda line: line.split(" "))
hashingTF = HashingTF()
tf = hashingTF.transform(documents)
from pyspark.mllib.feature import IDF
tf.cache()
idf = IDF(minDocFreq=2).fit(tf)
tfidf = idf.transform(tf)
好的特征选择方式能够减少特征的数量,提高训练的效率和分类效果。
对于文本向量来说,未进行特征选择的向量维度为 ∥V∥ ,一般为数万维,这对于一些分类器来说,无疑是灾难,训练时间久又不见得效果好。
常用的特征选择方法有(可参考sklearn的model_selection模块):
1. 卡方检验
2. 删除变化小的特征
3. L1正则
4. 基于树的模型
具体实现方法可以浏览sklearn官网。
这里就是用卡方检验方法:
sklearn:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
X_new = SelectKBest(chi2, k=5000).fit_transform(X, y)
mllib:
selector = ChiSqSelector(numTopFeatures=1, featuresCol="features",
outputCol="features2", labelCol="label")
result = selector.fit(df).transform(df)
这里选择LR和Native Bayes,也可以用其他,只是做个例子。
sklearn:
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
LR = LogisticRegression(C=1.0, penalty="l2")
nb = MultinomialNB()
mllib:
from pyspark.mllib.classification import LogisticRegressionWithLBFGS
from pyspark.mllib.regression import LabeledPoint
from numpy import array
# Build the model
model = LogisticRegressionWithLBFGS.train(parsedData)
sklearn:
scores = cross_val_score(LR, features, targets, cv=5, scoring="f1")
print scores
print "F1: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2)
scores = cross_val_score(nb, features, targets, cv=5, scoring="f1")
print scores
print "F1: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2)
mllib:
labelsAndPreds = parsedData.map(lambda p: (p.label, model.predict(p.features)))
trainErr = labelsAndPreds.filter(lambda (v, p): v != p).count() / float(parsedData.count())
print("Training Error = " + str(trainErr))
http://scikit-learn.org/stable/index.html
http://spark.apache.org/docs/1.4.1/mllib-guide.html