用Python进行机器学习(附代码、学习资源)

136 阅读9分钟
原文链接: click.aliyun.com

93dfde970ede39196c0ec1615928c61ea51b33ae

使用Python库、流水线功能以及正则化方法对非线性数据进行建模。

在数据科学和分析领域中,对非线性数据进行建模是一项常规任务。但找到一个结果随自变量线性变化的自然过程很不容易。因此,需要有一种简便并且稳健的方法来快速将测量数据集与一组变量进行拟合。我们假定测量数据可能包含了一种复杂的非线性函数关系。这应该是数据科学家或机器学习工程师常用的工具。

我们要考虑以下几个相关的问题:

d47e62d2b349aca45e42305ed6714efbe5ed61d9怎么确定拟合多项式的顺序?是否需要为多变量回归加上交叉耦合项?有没有简单的方法将这一过程自动化?
d47e62d2b349aca45e42305ed6714efbe5ed61d9怎样判断模型是否过拟合?
d47e62d2b349aca45e42305ed6714efbe5ed61d9如何得知模型在面对噪声时够不够稳健?
d47e62d2b349aca45e42305ed6714efbe5ed61d9模型能不能轻松拓展到更高维度或更大的数据集上?

如何确定拟合多项式的顺序?

“我们能不能画出数据图形直接得到结论?”

数据如果能清楚的可视化表示(即特征维度为1或2)时,方法可行。一旦数据的特征维度等于3或者更多,这事儿就麻烦了。而且如果对结果产生影响的特征存在交叉耦合,这么做就完全是在浪费时间。下面我们画个图来感受一下:

f2026a598763785db3d9d07776f8c7b3741c3b58

很明显,直接画图的方法最多也只能做到上面这种程度。对那些更高维度并且变量相互作用的数据集,如果你试图每次只查看单个输入变量和输出之间的关系,会得出完全错误的结论。而且目前没有什么好办法同时显示两个以上的变量。所以,我们必须采用某种机器学习的技术来拟合多维数据集。

实际上,已经有了不少好的解决方案。

在你看到“...但这些是高维非线性数据集...”这句话发出尖叫之前,线性回归应该是头一个能找到的工具。注意一点:线性回归模型中的“线性”二字指的是系数,而不是特征。特征(即自变量)可以是任意多维度的,甚至可以是指数、对数、正弦这些函数。更厉害的是,可以使用这些变换和线性模型(近似)对令人惊讶的大量自然现象进行建模。

来看看下边这个有三个特征、单输出的数据集。我们再一次使用了前边提到的画图方法,很明显它表现的差强人意。

d45ff5f8afffc8109752dd46f29f60194feaf95f

因此,我们决定学习一个具有高阶多项式项线性模型来拟合数据集。那么问题来了:

d47e62d2b349aca45e42305ed6714efbe5ed61d9怎样确定什么多项式是有用的?
d47e62d2b349aca45e42305ed6714efbe5ed61d9如果我们开始将一次项、二次项、三次项...逐个进行组合,什么时候停止比较合适呢?
d47e62d2b349aca45e42305ed6714efbe5ed61d9我们怎么判定哪些交叉耦合的项是重要的?比如:是只需要_X_1²、_X_2³还是需要有_X_1._X_2以及_X_1².X3这种项?
d47e62d2b349aca45e42305ed6714efbe5ed61d9最后,我们是不是必须手动将这些多项式转换的方程/函数式写出来并且应用到数据集上?

强大的Python机器学习库来帮忙

幸运的是,有一个很厉害的机器学习库--scikit-learn提供了很多成熟的类/对象来解决上边说的这些问题。

这儿有一个对使用scikit-learn进行线性回归进行概述的资料(原文中说是视频,但打开链接看了一下是这个库的使用文档,故直接翻译为了资料)

http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html#sklearn.linear_model.LinearRegression

还有一篇很好的文章供大家查看。

https://towardsdatascience.com/simple-and-multiple-linear-regression-in-python-c928425168f9?gi=69160943145f

但本文要介绍的不仅仅是一个简单的线性拟合,请大家接着往下看。(原文有一句提到代码在作者的GitHub,但是发现链接已经404,所以没加)

我们从引入scikit-learn中相关的包开始:

from sklearn.cross_validation#引入函数进行训练集和测试集的划分

import train_test_split

#引入函数自动生成多项式特征

from sklearn.preprocessing import PolynomialFeatures

# 引入线性回归和一个正则化的回归函数

from sklearn.linear_model import LinearRegression

from sklearn.linear_model import LassoCV

from sklearn.pipeline import make_pipeline

下面快速说明一下我们等会儿要用到的一些概念。

训练/测试集划分:表示将已有的单独数据集划分为两个子集。其中一个(训练集)用来建立模型,另外一个(测试集)用来评估模型的准确性和稳定性。这个步骤对任何一个机器学习任务来说都是必不可少的。经过处理,我们没有用所有的数据建立出一个看似异常准确的模型。(因为模型接触到所有的数据,当然会拟合的很好)这个模型通常在新数据(未知)数据上表现很差。

模型在测试集上的准确性比其在训练集上的准确性更有说服力。这儿有一篇关于这个话题延伸的文章,有兴趣的读者可以看看。https://towardsdatascience.com/train-test-split-and-cross-validation-in-python-80b61beca4b6

下面你会看到Google car的先驱Sebastion Thrun对这个概念的说法。

多项式特征自动生成

Scikit-learn提供了一个从一组线性特征中生成多项式特征的方法。你需要做的就是传入线性特征列表,并指定希望生成的多项式项的最大阶数。它还可以让你选择是生成所有交叉耦合项还是只生成主要特征的阶数。这里有一个Python代码进行演示。

http://scikit-learn.org/stable/auto_examples/linear_model/plot_polynomial_interpolation.html#sphx-glr-auto-examples-linear-model-plot-polynomial-interpolation-py

正则化回归

正则化的重要性不言而喻,它是机器学习的一个中心概念。在建立线性模型时,最基本的想法是对模型的系数进行“惩罚”,使它们不会变得太大而过拟合数据(对噪声数据过于敏感)。有两个广泛使用的正则化方法,其中我们要用的被称为LASSO。下边这篇文章对两种正则化方法做了很好的概述。

https://www.analyticsvidhya.com/blog/2016/01/complete-tutorial-ridge-lasso-regression-python/

机器学习流水线

一个机器学习项目几乎不会是单一的建模任务。它最常见的形式包括数据生成、数据清洗、数据转换、模型拟合、交叉验证、模型准确性评估和最终的部署。

列举一些相关的学习资料如下:

d47e62d2b349aca45e42305ed6714efbe5ed61d9对上述概念总结的一个Quora回答:

https://www.quora.com/What-is-a-pipeline-and-baseline-in-machine-learning-algorithms

d47e62d2b349aca45e42305ed6714efbe5ed61d9另外一篇关于机器学习流水线的总结:

https://medium.com/@yanhann10/a-brief-view-of-machine-learning-pipeline-in-python-5f50b941fca8

d47e62d2b349aca45e42305ed6714efbe5ed61d9对piplines在实践中重要性作出阐述:

https://www.oreilly.com/ideas/building-and-deploying-large-scale-machine-learning-pipelines

d47e62d2b349aca45e42305ed6714efbe5ed61d9Scikit-learn提供了一个流水线功能,可以将多个模型和数据预处理类组合在一起,把原始数据转换为可用模型。

http://scikit-learn.org/stable/tutorial

/statistical_inference/putting_together.html

怎样最终整合并建立一个稳健的模型?

在这里,我们提供了一些代码样例,你可以对它进行修改,应用在你自己的数据集上。

# LASSO回归的参数设置

lasso_eps = 0.0001

lasso_nalpha=20

lasso_iter=5000

# 多项式特征项的最大、最小阶数

degree_min = 2

degree_max = 8

# 训练集、测试集划分

X_train, X_test, y_train, y_test =

train_test_split(df['X'], df['y'],test_size=test_set_fraction)

# 建立一个流水线模型

for degree in range(degree_min,degree_max+1):

model=make_pipeline(PolynomialFeatures(degree, interaction_only=False),LassoCV(eps=lasso_eps,

n_alphas=lasso_nalpha,max_iter=lasso_iter,

normalize=True,cv=5))

model.fit(X_train,y_train)

test_pred = np.array(model.predict(X_test))

RMSE=np.sqrt(np.sum(np.square(test_pred-y_test)))

test_score = model.score(X_test,y_test)

不过这些冷冰冰的代码是给机器看的,我们还准备了有详细注释的版本。

为了进一步提炼它,下面是更精简的流程图:

e47924a161fa5e9b30fb956ce30f9706b648b602

为了进一步提炼它,下面是更精简的流程图:

2cc8ba47e96d7b0bdb808d26999a40fd1aa2f705

让我们来讨论讨论结果

对于所有的模型,我们给出了测试误差、训练误差(均方根)还有R²系数作为模型准确性的度量。然后把它们画出来:

cf83cfa05e5df5f1393ce75412f63a0c6678a937

这些图回答了最早提出的两个问题。

可以看出,我们需要四阶和五阶的多项式项来进行拟合。线性、二次甚至三次模型对这个数据来说都不够复杂。

同时,我们也没必要使阶数超过5,这会使得模型过于复杂。

967e3df85764ad9b1a7541648fa1497103ac03a1

等等!问题来了:在这条曲线中,我们熟悉的表现出偏差和方差之间权衡(即过拟合与欠拟合)的形状在哪?为什么测试误差没有随着模型复杂度的增加急剧升高?

答案在于,使用LASSO回归之后,我们基本消除了复杂模型中的高阶项。对于更细节的东西,比如这个结果到底是怎么出现的,可以参考这篇文章。

https://dataorigami.net/blogs/napkin-folding/79033923-least-squares-regression-with-l1-penalty

实际上,这正是LASSO回归和L1正则的关键优势之一,它不是仅仅将模型中的部分系数减小,而是将它们直接变为零。这相当于提供了“自动特征选择”的功能。即便你一开始使用了很复杂的模型来拟合数据,经过这种处理后,也可以让那些不重要的特征自动被忽略。

为了进行对比,我们这次不做正则化处理,并且使用一个简单的线性模型来拟合数据。下边是得出的结果。这次可以看到那条熟悉的偏差/方差权衡曲线了(补充:表示训练误差及测试误差随着模型复杂度增长的变化,体现过拟合及欠拟合)

499c2d91c5941e433b6e449fd7c7bbc5f233447c

噪声数据会发生什么?

(这里作者有提到自己的代码,同样因为GitHub地址失效没有加进来)

数据中的噪声会让模型很难变得准确,甚至还会产生过拟合。因为模型会试图解释噪声,而不是发掘真正的模式。基本上,简单的线性回归模型在这种情况下都会失败,而正则化模型仍然表现良好。不过即便这样,在模型足够复杂时,过拟合现象也会现出端倪。

下面是总结:

54375db828ef5f847db151004ec8c72d811c4237

结语

简而言之,本文讨论了一个拟合多变量回归模型的方法,它适用于高度非线性、具有耦合项并且含有噪声的数据集。我们知道了如何利用Python的机器学习库来生成多项式特征、对数据进行正则化处理,防止模型中的系数变得过大、画图来评估模型的准确性及稳定性等。

对于更高级的具有非多项式特征的模型,你可以看看sklearn中关于核回归或支持向量机的内容。还有这篇文章有对高斯核回归的介绍。


原文发布时间为:2018-06-4本文作者:Tirthajyoti Sarkar本文来自云栖社区合作伙伴“数据派THU”,了解相关信息可以关注“ 数据派THU”。