總體思路
- 文本預處理
- 提取特徵
- 特徵選擇
- 選擇分類算法
- 訓練和評估
預處理
包括分句、分詞和詞幹化,使用nltk可以實現。
實現分兩個版本:1. scikit-learn版本 2. MLLIB版本
主要是因爲運行效率的問題,基於spark的mllib採用分佈式的訓練算法,速度快很多。
特徵提取
tf-idf是基本的文本分類特徵提取方法,它是詞袋模型的一個信息量衡量方式,也是常用的基準方法。本文就是用tf-idf來構建文本特徵,後面會提到使用word2vec進行改進。
scikit-learn特徵提取
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特徵提取
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)
特徵選擇
好的特徵選擇方式能夠減少特徵的數量,提高訓練的效率和分類效果。
對於文本向量來說,未進行特徵選擇的向量維度爲
常用的特徵選擇方法有(可參考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))
Reference
http://scikit-learn.org/stable/index.html
http://spark.apache.org/docs/1.4.1/mllib-guide.html