多项式回归就是数据的分布不满足线性关系,而是二次曲线或者更高维度的曲线。此时只能使用多项式回归来拟合曲线。比如如下数据,使用线性函数来拟合就明显不合适了。

接下来要做的就是升维,上面的真实函数是:$ y = 0.5x^2 + 2x + 5\(。而样本数据的形式是(x, y),以这种方式只能训练出\)y = ax + b\(。所以,手动构造\)x^2\(项,让样本的形式变为:\)(x, x^2, y)\(。这样,增加了一个\)x^2$特征,再使用线性回归就可以得到形如 \(y = ax^2 + bx + c\) 的拟合曲线。

使用线性回归取拟合这个二次曲线,当然,结果一定是欠拟合:

  1. from sklearn.linear_model import LinearRegression
  2. reg = LinearRegression()
  3. reg.fit(x, y)
  4. y_predict = reg.predict(x)
  5. plt.scatter(x, y)
  6. plt.plot(np.sort(x), y_predict, color="b")
  7. plt.show()

增加\(x^2\)作为新的特征,再拟合,效果还不错:

  1. new_cow = x ** 2
  2. x_new = np.hstack([x, new_cow]) # 将x^2放在最后一列
  3. reg_2 = LinearRegression()
  4. reg_2.fit(x_new, y)
  5. y_predict2 = reg_2.predict(x_new)

使用sklearn中的多项式回归

  1. from sklearn.preprocessing import PolynomialFeatures
  2. poly_feature = PolynomialFeatures(degree = 2) # 最高为2阶多项式
  3. poly_feature.fit(X)
  4. X_poly = poly_feature.transform(X)

PolynomialFeatures用于将x的所有可能的幂次都算出来

\(x=(a, b)\), degree=3,transform(X)会返回6个值,分别表示(1, a, b, \(a^2\), ab, \(b^2\))

  1. xx = np.arange(0, 100)
  2. xx = xx.reshape(50, 2) # 两个特征
  3. print(xx[:3])
  4. poly_feature = PolynomialFeatures(degree = 2) # 最高次幂为2
  5. poly_feature.fit_transform(xx[:3])

结果是:

  1. [[0 1]
  2. [2 3]
  3. [4 5]]
  4. [[ 1., 0., 1., 0., 0., 1.],
  5. [ 1., 2., 3., 4., 6., 9.],
  6. [ 1., 4., 5., 16., 20., 25.]]

使用 PolynomialFeatures和LinearRegression进行多项式回归

  1. from sklearn.linear_model import LinearRegression
  2. from sklearn.preprocessing import PolynomialFeatures
  3. # 数据集
  4. x = np.random.uniform(-3, 3, size=100)
  5. y = 0.5 * (x ** 2) + 2 * x + 5 + np.random.normal(0, 1, 100)
  6. X = x.reshape(-1, 1)
  7. poly_feature = PolynomialFeatures(degree = 2) # 最高为2阶多项式
  8. reg_poly = LinearRegression()
  9. # 转换参数,升维
  10. poly_feature.fit(X)
  11. X_poly = poly_feature.transform(X)
  12. # 进行多项式回归
  13. reg_poly.fit(X_poly, y)
  14. y_predict = reg_poly.predict(X_poly)

效果如下:

使用Pipeline 封装拟合的细节

  1. poly_pipeline = Pipeline([
  2. ("poly", PolynomialFeatures(degree=2)),
  3. ("std_scaler", StandardScaler()),
  4. ("line_reg", LinearRegression())
  5. ])

如此,创建了一个具有特征转换、数据归一化、线性拟合为一体的pipeline。使用方式和 LinearRegression一样。只是此时已经不需要收到的将x转换为多项式形式,也不需要手动的进行数据归一化。

  1. poly_pipeline.fit(X, y)
  2. y_predict = poly_pipeline.predict(X)

过拟合 & 欠拟合

对pipeline进行简单的封装,以下方法只需要传入一个参数就可以得到一个可用的多项式回归对象。

  1. # 使用多项式回归,只需要传入一个参数degree
  2. def PolynomialRegression(degree):
  3. return Pipeline([
  4. ("poly", PolynomialFeatures(degree)),
  5. ("std_scaler", StandardScaler()),
  6. ("line_reg", LinearRegression())
  7. ])

还是之前的数据,进行2阶多项式拟合,使用均方误差评估算法:

  1. poly_reg = PolynomialRegression(2)
  2. poly_reg.fit(X, y)
  3. y_predict = poly_reg.predict(X)
  4. plt.scatter(x, y)
  5. plt.plot(np.sort(x), y_predict[np.argsort(x)])
  6. # 均方误差: 1.117776648943851

尝试更高维的数据:

10阶:

均方误差: 1.082746862641965

100阶:

均方误差: 0.4988841593798084

使用如下方式绘制100阶曲线更准确(使x等距,而不是随机):

  1. xx = np.linspace(-3, 3, 100)
  2. xx = xx.reshape(-1,1)
  3. yy = poly_reg100.predict(xx)
  4. plt.scatter(xx, yy)
  5. plt.axis([-3, 3, 0, 10])
  6. plt.plot(np.sort(xx), y_predict100[np.argsort(x)], color="r")

均方误差越来越小,拟合程度越来越高,但是毫无意义。算法对过多的噪音数据进行了过拟合。实际上模型的泛化效果很差。

学习曲线

如果训练数据有m个,那么循环m次,每次都计算对于训练数据和测试数据的MSE,观察变化的趋势。

  1. def plot_learning_curve(reg, X_train, X_test, y_train, y_test):
  2. # 使用线性回归绘制学习曲线
  3. train_score = []
  4. test_score = []
  5. for i in range(1, len(X_train)):
  6. reg.fit(X_train[:i], y_train[:i])
  7. y_train_predict = reg.predict(X_train[:i])
  8. y_test_predict = reg.predict(X_test)
  9. train_score.append(mean_squared_error(y_train_predict, y_train[:i]))
  10. test_score.append(mean_squared_error(y_test_predict, y_test))
  11. plt.axis([0,75,0, 10])
  12. plt.plot([i for i in range(1, len(X_train))], np.sqrt(train_score), label="train")
  13. plt.plot([i for i in range(1, len(X_train))], np.sqrt(test_score), label="test")
  14. plt.legend()
  15. plt.show()

线性回归的学习曲线

  1. reg_line = LinearRegression()
  2. plot_learning_curve(reg_line, X_train, X_test, y_train, y_test)

二阶线性回归的学习曲线

  1. reg_2 = PolynomialRegression(2) # 使用pipeline
  2. plot_learning_curve(reg_2, X_train, X_test, y_train, y_test)

20阶线性回归的学习曲线

  1. reg_2 = PolynomialRegression(20) # 使用pipeline
  2. plot_learning_curve(reg_2, X_train, X_test, y_train, y_test)

分析

没有对比就没有伤害。前两个都收敛,但是二阶的MSE更低,所以线性回归得到的使欠拟合的曲线。20阶的训练数据表现很好,但是测试数据表现不行,所以使过拟合(其实也还要,用更高阶的函数可能会更明显)

手动寻找最优参数

就是遍历所有参数,找score最高的参数。

  1. from sklearn.neighbors import KNeighborsClassifier
  2. best_k, best_p, best_score = 0, 0, 0
  3. for k in range(2, 11):
  4. for p in range(1, 6):
  5. knn_clf = KNeighborsClassifier(weights="distance", n_neighbors=k, p=p)
  6. knn_clf.fit(X_train, y_train)
  7. score = knn_clf.score(X_test, y_test)
  8. if score > best_score:
  9. best_k, best_p, best_score = k, p, score
  10. print("Best K =", best_k)
  11. print("Best P =", best_p)
  12. print("Best Score =", best_score)

交叉验证

k-折交叉验证(k-fold cross validation),之前随机选取的叫简单交叉验证(hold -out cross validation)。k折,就是将训练集分为k份,每次只用k-1组数据训练,用剩下的一组计算score。

原来的测试集就完全不使用,等到模型训练完毕后,再使用测试集计算模型的性能。简单交叉验证用测试集计算score,测试集中的数据也影响了参数的选择。有可能会导致模型对训练数据和测试数据的过拟合。

使用 k-折交叉验证得到的score是一个数组,因为需要进行k次拟合。

  1. from sklearn.model_selection import cross_val_score
  2. knn_clf = KNeighborsClassifier()
  3. cross_val_score(knn_clf, X_train, y_train, cv=3)
  4. # array([0.98895028, 0.97777778, 0.96629213])

网格搜索(待定)

实际上也是使用CV寻找最优参数,其实只是做了封装。

  1. from sklearn.model_selection import GridSearchCV
  2. param_grid = [
  3. {
  4. 'weights': ['distance'],
  5. 'n_neighbors': [i for i in range(2, 11)],
  6. 'p': [i for i in range(1, 6)]
  7. }
  8. ]
  9. grid_search = GridSearchCV(knn_clf, param_grid, verbose=1)
  10. grid_search.fit(X_train, y_train)
  11. grid_search.best_score_ # 最好的score
  12. grid_search.best_params_ # 最好的模型参数
  13. best_knn_clf = grid_search.best_estimator_ # 最好的模型的实例
  14. best_knn_clf.score(X_test, y_test)

多项式回归 & pipeline & 学习曲线 & 交叉验证的更多相关文章

  1. Spark2.0机器学习系列之2:基于Pipeline、交叉验证、ParamMap的模型选择和超参数调优

    Spark中的CrossValidation Spark中采用是k折交叉验证 (k-fold cross validation).举个例子,例如10折交叉验证(10-fold cross valida ...

  2. 机器学习- Sklearn (交叉验证和Pipeline)

    前面一节咱们已经介绍了决策树的原理已经在sklearn中的应用.那么这里还有两个数据处理和sklearn应用中的小知识点咱们还没有讲,但是在实践中却会经常要用到的,那就是交叉验证cross_valid ...

  3. 机器学习——交叉验证,GridSearchCV,岭回归

    0.交叉验证 交叉验证的基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set or test set) ...

  4. Spark机器学习——模型选择与参数调优之交叉验证

    spark 模型选择与超参调优 机器学习可以简单的归纳为 通过数据训练y = f(x) 的过程,因此定义完训练模型之后,就需要考虑如何选择最终我们认为最优的模型. 如何选择最优的模型,就是本篇的主要内 ...

  5. sklearn中的交叉验证(Cross-Validation)

    这个repo 用来记录一些python技巧.书籍.学习链接等,欢迎stargithub地址sklearn是利用python进行机器学习中一个非常全面和好用的第三方库,用过的都说好.今天主要记录一下sk ...

  6. 普通交叉验证(OCV)和广义交叉验证(GCV)

    普通交叉验证OCV OCV是由Allen(1974)在回归背景下提出的,之后Wahba和Wold(1975)在讨论 了确定多项式回归中多项式次数的背景,在光滑样条背景下提出OCV. Craven和Wa ...

  7. MATLAB曲面插值及交叉验证

    在离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点.插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值.曲面插值是对三维数据进行离 ...

  8. 交叉验证(Cross Validation)原理小结

    交叉验证是在机器学习建立模型和验证模型参数时常用的办法.交叉验证,顾名思义,就是重复的使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏. ...

  9. scikit-learn一般实例之一:绘制交叉验证预测

    本实例展示怎样使用cross_val_predict来可视化预测错误: # coding:utf-8 from pylab import * from sklearn import datasets ...

随机推荐

  1. 给博客添加个充电按钮(仿B站)

    今天我准备吧B站的充电按钮移植到本博客,开始- 上代码: HTML <html> <head> <link href="./space.8.f69f7d6f8f ...

  2. day29--Java泛型02

    Java泛型02 5.自定义泛型 5.1自定义泛型类 基本语法: class 类名<T,R...>{//-表示可以有多个泛型 成员 } 注意细节: 普通成员可以使用泛型(属性.方法) 使用 ...

  3. 第四篇:理解vue代码

    解释以下代码: 实现输入框中能够打字的功能 <el-input v-model="input" placeholder="在这打字"></el ...

  4. windows清理必看

    清理缓存 代码如下 介绍此文件夹都是缓存文件全选删除即可 ctrl+A全选shift+del强制删除(不会添加到回收站) %temp% 找到C盘右击属性选择想要删除的文件进行清理即可 清理完点击清理系 ...

  5. C#winform中使用Cef的ChromiumWebBrowser内嵌谷歌内核,调用前端js方法

    1.在winform中调用js方法: --调js中的方法无 入参形式 webBrowser1.ExecuteJavascript("logout()"); --调js中的方法给js ...

  6. 【全网最全】springboot整合JSR303参数校验与全局异常处理

    一.前言 我们在日常开发中,避不开的就是参数校验,有人说前端不是会在表单中进行校验的吗?在后端中,我们可以直接不管前端怎么样判断过滤,我们后端都需要进行再次判断,为了安全.因为前端很容易拜托,当测试使 ...

  7. Kubernetes实践技巧:升级为集群

    高可用 前面我们课程中的集群是单 master 的集群,对于生产环境风险太大了,非常有必要做一个高可用的集群,这里的高可用主要是针对控制面板来说的,比如 kube-apiserver.etcd.kub ...

  8. Centos7新增静态路由

    文章转载自:https://blog.51cto.com/loong576/2417561 环境说明: 一.临时方式 1. 查看路由和ip [root@centos7 ~]# route -n Ker ...

  9. Python 类型提示简介

    Python 3.6+ 版本加入了对"类型提示"的支持. 这些"类型提示"是一种新的语法(在 Python 3.6 版本加入)用来声明一个变量的类型. 通过声明 ...

  10. 在客户端电脑使用 kubectl 远程管理 Kubernetes

    日常工作中,可能需要在自己的笔记本电脑上执行 kubectl 命令以管理远程 Linux 服务器上的 Kubernetes 集群.通过调用 kubernetes API 来实现对 Kubernetes ...