Python机器学习及实践——进阶篇1(特征提升之特征抽取)

Posted Lenskit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python机器学习及实践——进阶篇1(特征提升之特征抽取)相关的知识,希望对你有一定的参考价值。

在前面的一系列文章中,已经介绍了大量经典的机器学习模型,并且使用python语言分析这些模型在许多不同现实数据上的性能表现。细心的读者会发现一个问题,我们之前使用的数据几乎都经过了规范化处理,而且模型也大多只是采用了默认的初始化配置。换言之,尽管我们使用经过处理后的数据,在默认配置下学得一套可以拟合数据的参数,并用这些参数和默认配置取得了一些看似良好的性能表现;但是我们无法解决最为关键的问题:实际研究和工作中的数据并不是这样规整以及默认配置的参数并不是最佳。在后续,我们会解答这两个问题,帮助大家掌握如何通过抽取或者筛选数据特征,优化模型配置,进一步提升经典模型的性能表现。

但不得不说的是,随着近些年机器学习研究的快速发展,经典模型渐渐无法满足日益增长的数据量和复杂的数据需求。因此越来越多更加高效而且强力的学习模型以及对于的程序库正逐渐被涉及和编写。这些模型和程序库包括:用于自然语言处理的NLTK程序包;词向量技术Word2Vec;能够提供强大预测能力的XGBoost模型,以及Google发布的用户深度学习的TensorFlow框架等等。更加令人振奋的是,以上这些最为流行的程序库和模型,不但提供了Python的编程接口API,而且有些成为了Python编程语言的工具包。

模型提升技巧

我们会发现,一旦我们确定使用某个模型,我们就可以依靠默认配置学习到模型所需要的参数;接下来,我们便可以利用参数指导模型在测试数据集上进行预测,进而对模型的表现性能进行评价。

但是这套方案并不能保证:1)所有用户训练的数据特征都是最好;2)学习得到的参数一定是最优的;3)默认配置下的模型总是最佳的。也就是说,我们可以从多个角度对在前面所有使用过的模型进行性能提升。本篇将向大家介绍多种提升模型性能的方式,包括如何预处理数据、控制参数以及优化模型配置等方法。

1、特征提升

早期机器学习的研究受限于模型种类和运算能力的限制。因此,大部分研发人员把更多的精力放在对数据的预处理上。他们期望通过对数据特征的抽取或者筛选来达到提升模型性能的目的。所谓特征抽取,就是逐条将原始数据转化为特征向量的形式,这个过程同时涉及对数据特征的量化表示;而特征筛选则更进一步,在高维度、已量化的特征向量中选择对指定任务更有效的特征组合,进一步提升模型性能。

1.1、特征抽取

原始数据种类有很多,除了数字化的信号数据(声纹、图像),还有大量符号化的文本。然而,我们无法直接将符号化的文字本身用户计算任务,而且需要通过某些处理手段,预先将文本向量化为特征向量。

有些用符号表示的数据特征已经相对结构化,并且以字典这种数据结构进行存储。这时,我们使用DictVectorizer对特征进行抽取和向量化。如代码1:

# 定义一组字典列表,用来表示多个数据样本(每个字典代表一个数据样本)。
measurements = ['city': 'Dubai', 'temperature': 33., 'city': 'London', 'temperature': 12., 'city': 'San Fransisco', 'temperature': 18.]
# 从sklearn.feature_extraction 导入 DictVectorizer
from sklearn.feature_extraction import DictVectorizer
# 初始化DictVectorizer特征抽取器
vec = DictVectorizer()
# 输出转化之后的特征矩阵。
print vec.fit_transform(measurements).toarray()
# 输出各个维度的特征含义。
print vec.get_feature_names()

[[  1.   0.   0.  33.]

 [  0.   1.   0.  12.]

 [  0.   0.   1.  18.]]

['city=Dubai', 'city=London', 'city=San Fransisco', 'temperature']

从代码输出可以看到:在特征向量化的过程中,DictVectorizer对于类别型与数值型特征的处理方式有很大差异。由于类别型特征无法直接数字化表示,因此需要借助原特征的名称,组合产生新的特征,并采用0/1二值方式进行量化;而数值型特征的转化则相对方便,一般情况下只需要维持原始特征值即可。

另外一些文本数据则表现得更为原始,几乎没有使用特殊的数据结构进行存储,只是一系列字符串。我们处理这些数据,比较常用的文本特征表示方法为词袋法:不考虑词语出现的顺序,只是将训练文本中的每个出现过的词汇单独视作一列特征。我们称这些不重复的词汇集合为词表,于是每条训练文本都可以在高维度的词表上映射出一个特征向量。特征数值的常见计算方式有两种:CountVectorizer和TfidfVectorizer。(可自行搜索这两种方式的不同)

我们通常称在每条文本中都出现的常用词汇为停用词,如英文的the、a等。这些停用词通常以黑名单的方式过滤掉,并且用来提升模型的性能表现。我们用下面的代码重新对“20类新闻文本分类”问题进行分析处理,这次的重点在于列举上述两种文本特征量化模型的使用方法,并比较他们的性能差异,代码2:

# 从sklearn.datasets里导入20类新闻文本数据抓取器。
from sklearn.datasets import fetch_20newsgroups
# 从互联网上即时下载新闻样本,subset='all'参数代表下载全部近2万条文本存储在变量news中。
news = fetch_20newsgroups(subset='all')

# 从sklearn.cross_validation导入train_test_split模块用于分割数据集。
from sklearn.cross_validation import train_test_split
# 对news中的数据data进行分割,25%的文本用作测试集;75%作为训练集。
X_train, X_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25, random_state=33)

# 从sklearn.feature_extraction.text里导入CountVectorizer
from sklearn.feature_extraction.text import CountVectorizer
# 采用默认的配置对CountVectorizer进行初始化(默认配置不去除英文停用词),并且赋值给变量count_vec。
count_vec = CountVectorizer()

# 只使用词频统计的方式将原始训练和测试文本转化为特征向量。
X_count_train = count_vec.fit_transform(X_train)
X_count_test = count_vec.transform(X_test)

# 从sklearn.naive_bayes里导入朴素贝叶斯分类器。
from sklearn.naive_bayes import MultinomialNB
# 使用默认的配置对分类器进行初始化。
mnb_count = MultinomialNB()
# 使用朴素贝叶斯分类器,对CountVectorizer(不去除停用词)后的训练样本进行参数学习。
mnb_count.fit(X_count_train, y_train)

# 输出模型准确性结果。
print 'The accuracy of classifying 20newsgroups using Naive Bayes (CountVectorizer without filtering stopwords):', mnb_count.score(X_count_test, y_test)
# 将分类预测的结果存储在变量y_count_predict中。
y_count_predict = mnb_count.predict(X_count_test)
# 从sklearn.metrics 导入 classification_report。
from sklearn.metrics import classification_report
# 输出更加详细的其他评价分类性能的指标。
print classification_report(y_test, y_count_predict, target_names = news.target_names)

The accuracy of classifying 20newsgroups using Naive Bayes (CountVectorizer without filtering stopwords): 0.839770797963

                          precision    recall  f1-score   support

             alt.atheism       0.86      0.86      0.86       201

           comp.graphics       0.59      0.86      0.70       250

 comp.os.ms-windows.misc       0.89      0.10      0.17       248

comp.sys.ibm.pc.hardware       0.60      0.88      0.72       240

   comp.sys.mac.hardware       0.93      0.78      0.85       242

          comp.windows.x       0.82      0.84      0.83       263

            misc.forsale       0.91      0.70      0.79       257

               rec.autos       0.89      0.89      0.89       238

         rec.motorcycles       0.98      0.92      0.95       276

      rec.sport.baseball       0.98      0.91      0.95       251

        rec.sport.hockey       0.93      0.99      0.96       233

               sci.crypt       0.86      0.98      0.91       238

         sci.electronics       0.85      0.88      0.86       249

                 sci.med       0.92      0.94      0.93       245

               sci.space       0.89      0.96      0.92       221

  soc.religion.christian       0.78      0.96      0.86       232

      talk.politics.guns       0.88      0.96      0.92       251

   talk.politics.mideast       0.90      0.98      0.94       231

      talk.politics.misc       0.79      0.89      0.84       188

      talk.religion.misc       0.93      0.44      0.60       158

             avg / total       0.86      0.84      0.82      4712

从上面代码的输出,我们可以知道使用CountVectorizer在不去掉停用词的条件下对训练和测试文本进行特征量化,并利用默认配置的朴素贝叶斯分类器,在测试文本上可以得到83.977%的预测准确性。而且平均精度、召回率和F1指标,分别是0.86、0.84以及0.82。

接下来,我们使用相同的训练和测试数据,在不去掉停用词的情况下利用TfidfVectorizer进行特征量化,并且评估模型性能。代码3:

# 从sklearn.feature_extraction.text里分别导入TfidfVectorizer。
from sklearn.feature_extraction.text import TfidfVectorizer
# 采用默认的配置对TfidfVectorizer进行初始化(默认配置不去除英文停用词),并且赋值给变量tfidf_vec。
tfidf_vec = TfidfVectorizer()

# 使用tfidf的方式,将原始训练和测试文本转化为特征向量。
X_tfidf_train = tfidf_vec.fit_transform(X_train)
X_tfidf_test = tfidf_vec.transform(X_test)

# 依然使用默认配置的朴素贝叶斯分类器,在相同的训练和测试数据上,对新的特征量化方式进行性能评估。
mnb_tfidf = MultinomialNB()
mnb_tfidf.fit(X_tfidf_train, y_train)
print 'The accuracy of classifying 20newsgroups with Naive Bayes (TfidfVectorizer without filtering stopwords):', mnb_tfidf.score(X_tfidf_test, y_test)
y_tfidf_predict = mnb_tfidf.predict(X_tfidf_test)
print classification_report(y_test, y_tfidf_predict, target_names = news.target_names)

The accuracy of classifying 20newsgroups with Naive Bayes (TfidfVectorizer without filtering stopwords): 0.846349745331

                          precision    recall  f1-score   support

             alt.atheism       0.84      0.67      0.75       201

           comp.graphics       0.85      0.74      0.79       250

 comp.os.ms-windows.misc       0.82      0.85      0.83       248

comp.sys.ibm.pc.hardware       0.76      0.88      0.82       240

   comp.sys.mac.hardware       0.94      0.84      0.89       242

          comp.windows.x       0.96      0.84      0.89       263

            misc.forsale       0.93      0.69      0.79       257

               rec.autos       0.84      0.92      0.88       238

         rec.motorcycles       0.98      0.92      0.95       276

      rec.sport.baseball       0.96      0.91      0.94       251

        rec.sport.hockey       0.88      0.99      0.93       233

               sci.crypt       0.73      0.98      0.83       238

         sci.electronics       0.91      0.83      0.87       249

                 sci.med       0.97      0.92      0.95       245

               sci.space       0.89      0.96      0.93       221

  soc.religion.christian       0.51      0.97      0.67       232

      talk.politics.guns       0.83      0.96      0.89       251

   talk.politics.mideast       0.92      0.97      0.95       231

      talk.politics.misc       0.98      0.62      0.76       188

      talk.religion.misc       0.93      0.16      0.28       158

             avg / total       0.87      0.85      0.84      4712

由上述输出可知,在使用TfidfVectorizer不去掉停用词的条件下进行特征量化,并利用默认配置的朴素贝叶斯分类器,在测试文本上可以得到比CountVectorizer更加高的预测准确性,即从83.977%提升到84.635%。而且,平均精度、召回率和F1指标也都得到了提升。这证明了“在训练文本较多的时候,利用TfidfVectorizer压制常用词汇对分类决策的干扰,往往可以起到提升模型性能的作用。

最后我们在验证另一个观点:去掉停用词可以提高模型的性能表现。代码4:

# 继续沿用代码56与代码57中导入的工具包(在同一份源代码中,或者不关闭解释器环境),分别使用停用词过滤配置初始化CountVectorizer与TfidfVectorizer。
count_filter_vec, tfidf_filter_vec = CountVectorizer(analyzer='word', stop_words='english'), TfidfVectorizer(analyzer='word', stop_words='english')

# 使用带有停用词过滤的CountVectorizer对训练和测试文本分别进行量化处理。
X_count_filter_train = count_filter_vec.fit_transform(X_train)
X_count_filter_test = count_filter_vec.transform(X_test)

# 使用带有停用词过滤的TfidfVectorizer对训练和测试文本分别进行量化处理。
X_tfidf_filter_train = tfidf_filter_vec.fit_transform(X_train)
X_tfidf_filter_test = tfidf_filter_vec.transform(X_test)

# 初始化默认配置的朴素贝叶斯分类器,并对CountVectorizer后的数据进行预测与准确性评估。
mnb_count_filter = MultinomialNB()
mnb_count_filter.fit(X_count_filter_train, y_train)
print 'The accuracy of classifying 20newsgroups using Naive Bayes (CountVectorizer by filtering stopwords):', mnb_count_filter.score(X_count_filter_test, y_test)
y_count_filter_predict = mnb_count_filter.predict(X_count_filter_test)

# 初始化另一个默认配置的朴素贝叶斯分类器,并对TfidfVectorizer后的数据进行预测与准确性评估。
mnb_tfidf_filter = MultinomialNB()
mnb_tfidf_filter.fit(X_tfidf_filter_train, y_train)
print 'The accuracy of classifying 20newsgroups with Naive Bayes (TfidfVectorizer by filtering stopwords):', mnb_tfidf_filter.score(X_tfidf_filter_test, y_test)
y_tfidf_filter_predict = mnb_tfidf_filter.predict(X_tfidf_filter_test)

# 对上述两个模型进行更加详细的性能评估。
from sklearn.metrics import classification_report
print classification_report(y_test, y_count_filter_predict, target_names = news.target_names)
print classification_report(y_test, y_tfidf_filter_predict, target_names = news.target_names)

The accuracy of classifying 20newsgroups using Naive Bayes (CountVectorizer by filtering stopwords): 0.863752122241

The accuracy of classifying 20newsgroups with Naive Bayes (TfidfVectorizer by filtering stopwords): 0.882640067912

                          precision    recall  f1-score   support

             alt.atheism       0.85      0.89      0.87       201

           comp.graphics       0.62      0.88      0.73       250

 comp.os.ms-windows.misc       0.93      0.22      0.36       248

comp.sys.ibm.pc.hardware       0.62      0.88      0.73       240

   comp.sys.mac.hardware       0.93      0.85      0.89       242

          comp.windows.x       0.82      0.85      0.84       263

            misc.forsale       0.90      0.79      0.84       257

               rec.autos       0.91      0.91      0.91       238

         rec.motorcycles       0.98      0.94      0.96       276

      rec.sport.baseball       0.98      0.92      0.95       251

        rec.sport.hockey       0.92      0.99      0.95       233

               sci.crypt       0.91      0.97      0.93       238

         sci.electronics       0.87      0.89      0.88       249

                 sci.med       0.94      0.95      0.95       245

               sci.space       0.91      0.96      0.93       221

  soc.religion.christian       0.87      0.94      0.90       232

      talk.politics.guns       0.89      0.96      0.93       251

   talk.politics.mideast       0.95      0.98      0.97       231

      talk.politics.misc       0.84      0.90      0.87       188

      talk.religion.misc       0.91      0.53      0.67       158

             avg / total       0.88      0.86      0.85      4712

                          precision    recall  f1-score   support

             alt.atheism       0.86      0.81      0.83       201

           comp.graphics       0.85      0.81      0.83       250

 comp.os.ms-windows.misc       0.84      0.87      0.86       248

comp.sys.ibm.pc.hardware       0.78      0.88      0.83       240

   comp.sys.mac.hardware       0.92      0.90      0.91       242

          comp.windows.x       0.95      0.88      0.91       263

            misc.forsale       0.90      0.80      0.85       257

               rec.autos       0.89      0.92      0.90       238

         rec.motorcycles       0.98      0.94      0.96       276

      rec.sport.baseball       0.97      0.93      0.95       251

        rec.sport.hockey       0.88      0.99      0.93       233

               sci.crypt       0.85      0.98      0.91       238

         sci.electronics       0.93      0.86      0.89       249

                 sci.med       0.96      0.93      0.95       245

               sci.space       0.90      0.97      0.93       221

  soc.religion.christian       0.70      0.96      0.81       232

      talk.politics.guns       0.84      0.98      0.90       251

   talk.politics.mideast       0.92      0.99      0.95       231

      talk.politics.misc       0.97      0.74      0.84       188

      talk.religion.misc       0.96      0.29      0.45       158

             avg / total       0.89      0.88      0.88      4712

上面的依旧证明TfidfVectorizer的特征抽取和量化方法更加具备优势;同时,通过与代码2和3的性能比较,我们发现对停用词进行过滤的文本特征抽取方法,平均比不过滤停用词的模型综合性能高出3%~4%。

以上是关于Python机器学习及实践——进阶篇1(特征提升之特征抽取)的主要内容,如果未能解决你的问题,请参考以下文章

Python机器学习及实践——进阶篇2(特征提升之特征筛选)

Python机器学习及实践——进阶篇2(特征提升之特征筛选)

Python机器学习及实践——进阶篇5(模型检验)

Python机器学习及实践——进阶篇5(模型检验)

Python机器学习及实践——进阶篇5(模型检验)

Python机器学习及实践——基础篇12(集成模型)