特征缩放 (Feature Scaling)
在使用机器学习算法前,经常需要进行特征缩放(feature scaling),将所有特征都缩放到相同的尺度 ([0,1]的范围)。
下面是进行特征缩放的一种方式:
1 | def featureScaling(arr): |
使用sklearn:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import numpy
from sklearn.preprocessing import MinMaxScaler
train_data = numpy.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]])
test_data = numpy.array([[2, 2]])
# create the scaler
scaler = MinMaxScaler()
# compute the minimum and maximum to be used for later scaling.
scaler.fit(train_data)
# scaling features
print(scaler.transform(train_data))
print(scaler.transform(test_data))
对许多机器学习算法,特征缩放将影响最终的效果,如SVM和K-Means等(影响计算距离时各特征的比重)。
此外,特征缩放通常可以加速(大部分)机器学习算法的训练过程。
文本特征
文本分析是机器学习算法的一个重要应用领域,然而原始的文本数据很难直接作为大部分算法的输入,为此 scikit-learn 提供了许多方法从文本中提取特征向量。
词袋 (Bag of Words)
词袋(Bag-of-Words, BOW)模型是文本向量化的一种方式,主要关注文档中单词的出现频率,舍弃了单词中的所有顺序信息。
任何文档都可以编码成一个固定长度的向量,该向量表示词汇表中每个单词在文档中的计数或频率,长度为从所有文档中抽取的单词构成的词汇表的大小。
1 | from sklearn.feature_extraction.text import CountVectorizer |
StopWords
并非所有文字都拥有相同的信息量,在文本分析前,我们通常需要进行预处理,去除停用词 (StopWords, 通常指那些低信息量高频率的词) ,从而简化语料库 (corpus) 。
从 NLTK 中获取停止词:1
2import nltk
nltk.download("stopwords")
1 | from nltk.corpus import stopwords |
词干提取
可能有许多单词都表示同一个意思,在得到词袋之前,可以先将这些词打包进行词干分析,即可得到合并后的词汇,从而简化语料库。
可以使用 NLTK 提供的词干提取器 (Stemmer) 进行词干化。
1 | from nltk.stem.snowball import SnowballStemmer |
应该在创建词袋之前先进行词干化:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from sklearn.feature_extraction.text import CountVectorizer
# split the text string into individual words
document = "Text Analysis is a major application field for machine learning algorithms."
vectorizer = CountVectorizer()
analyze = vectorizer.build_analyzer()
wordlist = analyze(document)
# stem each word
from nltk.stem.snowball import SnowballStemmer
stemmer = SnowballStemmer("english")
stemedlist = [stemmer.stem(word) for word in wordlist]
# join the stemmed word to words
words = " ".join(stemedlist)
print words
Tf–idf
单词的出现频率不能完全代表单词的权重,替代的方法是统计单词权重,其中流行的方法是 TF-IDF (Term Frequency–Inverse Document, 词频 - 逆文档频率),代表一个词对于一个文档的重要程度。
TF-IDF 在统计单词权重时会综合考虑(加权)词频和逆文档频率。
词频 (Term Frequency) : 给定的某一个词在一篇文档中出现的次数,词频越高 TF 值越高。
逆文档频率 (Inverse Document Frequency) : 单词在所有文档中出现的频率越高,IDF 值则下降,越罕见的词可能有更高的 IDF 值。
TF-IDF 会把文档中更有代表意义的单词标注出来,例如仅在某篇文档中出现频率较高,而不是所有文档中都频繁出现的词。
如果已经用 CountVectorizer 得到了向量,可以使用 TfidfTransformer 转换为 TF-IDF 表示。1
2
3
4
5
6
7from sklearn.feature_extraction.text import TfidfTransformer
# use TfidfTransformer to compute the tf-idfs
# X is generated by a CountVectorizer
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(X)
print tfidf.toarray()
也可以直接使用 TfidfVectorizer 对文档进行向量化。1
2
3
4
5from sklearn.feature_extraction.text import TfidfVectorizer
# TfidfVectorizer combines all the options of CountVectorizer and TfidfTransformer in a single model
vectorizer = TfidfVectorizer(stop_words="english") # set parameters to remove stop words
X = vectorizer.fit_transform(corpus)
HashingVectorizer
当语料库很庞大时,将需要巨大的向量来编码文档,对内存要求很高,而且会减慢算法的速度。
HashingVectorizer 结合了特征哈希和 CountVectorizer ,可以用来解决上面的问题。
由于使用了单向的哈希方法,哈希化后的编码将无法转回单词的表达。
1 | from sklearn.feature_extraction.text import HashingVectorizer |
特征选择 (Feature Selection)
选择合适的特征是机器学习算法中很关键的一环。通常,我们需要用尽量少的特征来表达尽量多的数据中包含的信息。以下是选择特征时常见的两个操作:
- 欠拟合时需要加入新的特征来表示某些数据中重要的模式,添加新特征很多时候依赖于直觉与经验。
- 找出最合适的特征,去除多余的特征。需要去除的特征有些是含有噪音,不利于模型训练,还有些可能与其他特征高度相关,导致重复的信息等等。此外,过多的特征也可能导致过拟合,还会造成训练速度缓慢。
注意:警惕有BUG的特征,有时候某个特征对准确率提升特别明显,此时需要警惕是真的找到了关键特征还是引入了不合理的特征(如特征很多样本很少,此时本该过拟合反而准确率很高)。sklearn 中某些分类器如 DecisionTreeClassifier 可以通过属性查看各特征的重要性, 可以仔细筛查重要性非常高的特征是否存在问题:1
2
3
4
5from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf.fit(features_train, labels_train)
print clf.feature_importances_
sklearn 中有多种辅助方法帮助自动选择特征。多数方法都属于单变量特征选择的范畴,即独立对待每个特征并询问其在分类或回归中的能力。
sklearn 中有两大单变量特征选择工具:SelectPercentile 和 SelectKBest。 两者之间的区别从名字就可以看出:SelectPercentile 选择最有用的 x% 的特征,而 SelectKBest 选择 k 个最有用的特征。
1 | from sklearn.feature_selection import SelectPercentile, f_classif |
此外,使用 TfidfVectorizer 进行文本向量化时, 也有控制参数可以进行特征简化,下例中,max_df=0.5 表示如果单词出现在超过50%的文档中,将不加入词汇表:1
2
3
4# max_df - When building the vocabulary
# ignore terms that have a document frequency
# strictly higher than the given threshold
vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5, stop_words='english')
套索回归 (Lasso Regression)
Lasso算法是一种同时进行特征选择和正则化的回归分析方法。
其优化的目标函数如下:
使用 sklearn 中的 Lasso 算法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from sklearn.linear_model import Lasso
X_train = [[0, 0], [1, 1]]
y_train = [0, 1]
X_test = [[1, 1]]
# create the Lasso model and fit on the training data
reg = Lasso(alpha = 0.1)
reg.fit(X_train, y_train)
# The coefficients
print('Coefficients: ', reg.coef_)
# predict labels for the test data
pred = reg.predict(X_test)
print pred
参考资料
http://scikit-learn.org/stable/modules/preprocessing.html#scaling-features-to-a-range
http://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction
http://scikit-learn.org/stable/modules/feature_extraction.html#tfidf-term-weighting
http://scikit-learn.org/stable/modules/feature_extraction.html#feature-hashing
http://scikit-learn.org/stable/modules/feature_selection.html
http://scikit-learn.org/stable/modules/linear_model.html#lasso