赵走x博客
网站访问量:151582
首页
书籍
软件
工具
古诗词
搜索
登录
深入浅出Python机器学习:31、自动特征选择
深入浅出Python机器学习:30、数据“升维”
深入浅出Python机器学习:29、数据表达
深入浅出Python机器学习:28、聚类算法
深入浅出Python机器学习:27、特征提取
深入浅出Python机器学习:26、数据降维
深入浅出Python机器学习:25、数据预处理
深入浅出Python机器学习:24、神经网络实例一一手写识别
深入浅出Python机器学习:23、神经网络的原理及使用
深入浅出Python机器学习:22、神经网络的前世今生
深入浅出Python机器学习:21、SVM 实例一一波士顿房价回归分析
深入浅出Python机器学习:20、SVM 的核函数与参数选择
深入浅出Python机器学习:19、支持向量机SVM 基本概念
深入浅出Python机器学习:18、随机森林实例一一要不要和中目亲对象进一步发展
深入浅出Python机器学习:17、随机森林
深入浅出Python机器学习:16、决策树
深入浅出Python机器学习:15、朴素贝叶斯实战一一判断肿瘤是良性还是恶性
深入浅出Python机器学习:14、朴素贝叶斯算法的不同方法
深入浅出Python机器学习:13、朴素贝叶斯基本概念
深入浅出Python机器学习:12、使用L1 正则化的线性模型一一套索回归
深入浅出Python机器学习:11、使用L2 正则化的线性模型一一岭回归
深入浅出Python机器学习:10、最基本的线性模型一一线性回归
深入浅出Python机器学习:9、线性模型的墓本概念
深入浅出Python机器学习:8、K 最近邻算法项目实战一一酒的分类
深入浅出Python机器学习:7、K最近邻算法用于回归分析
深入浅出Python机器学习:6、K最近邻算法处理多元分类任务
深入浅出Python机器学习:5、k最近邻算法在分类任务中的应用
深入浅出Python机器学习:4、K 最近邻算法的原理
深入浅出Python机器学习:3、一些必需库的安装及功能简介
深入浅出Python机器学习:2、基于python i吾言的环境配置
深入浅出Python机器学习:1、概述
人脸数据集加载faces = fetch_lfw_people()报错
31、直方图
74、插件开发:Android端API实现
Python3之socket编程--3:基于UDP的套接字
15、使用 jQuery 处理 Ajax 请求
深入浅出Python机器学习:30、数据“升维”
资源编号:75937
人工智能
深入浅出Python机器学习
热度:112
在实际应用中,常常会遇到数据集的特征不足的情况。要解决这个问题,就需要对数据集的特征进行扩充。这里我们介绍两种在统计建模中常用的方法一一交互式特征Clnteraction Features )和多项式特征( Polynomial Features ) 。现在这两种方法在机器学习领域也非常普遍。
# 1、向数据集添加交互式特征 在实际应用中,常常会遇到数据集的特征不足的情况。要解决这个问题,就需要对数据集的特征进行扩充。这里我们介绍两种在统计建模中常用的方法一一交互式特征Clnteraction Features )和多项式特征( Polynomial Features ) 。现在这两种方法在机器学习领域也非常普遍。 首先我们先来介绍一下“交互式特征”,顾名思义,交互式特征是在原始数据特征中添加交互项, 使特征数量增加。在Python 中,我们可以通过Numpy 的hstack 函数来对数据集添加交互项,下面我们先通过一段代码了解一下hstack 函数的原理。在JupyterNotebook 中输入代码如下: ``` # 手工生成两个数组 array_1 = [1, 2, 3, 4, 5] array_2 = [6, 7, 8, 9, 0] # 使用hstack 将两个数组进行堆叠 array_3 = np.hstack((array_1, array_2)) # 打印结果 print('将数组2添加到数据1中后得到:{}'.format(array_3)) ``` 这段代码中,我们先建立了一个数组array_1 ,并且赋值为一个1 ~ 5 的列表,然后又建立了另一个数组array_2 , 赋值为一个6 ~ 0 的列表之后我们使用np.hstack 函数将两个数组堆叠到一起, 运行结果: ``` 将数组2添加到数据1中后得到:[1 2 3 4 5 6 7 8 9 0] ``` [结果分析} 从结果中看到,原来两个5 维数组被堆放到一起,形成了一个新的十维数组。也就是说我们使array_1 和array_2 产生了交互。假如array_1和array 2 分别代表两个数据点的特征,那么我们生成的array_3 就是它们的交互特征。 接下来我们继续用之前生成的数据集来进行实验, 看对特征进行交互式操作会对模型产生什么样的影响。在Jupyter Notebook 中输入代码如下: ``` # 导人numpy import numpy as np # 生成随机数列 rnd = np.random.RandomState(38) x = rnd.uniform(-5, 5, size=50) # 向数据中添加噪声 y_no_noise = (np.cos(6 * x) + x) X = x.reshape(-1, 1) y = (y_no_noise + rnd.normal(size=len(x))) / 2 # 设置箱体数为11 bins = np.linspace(-5, 5, 11) # 将数据进行装箱操作 target_bin = np.digitize(X, bins=bins) # 导入独热编码 from sklearn.preprocessing import OneHotEncoder onehot = OneHotEncoder(sparse=False) onehot.fit(target_bin) # 使用独热编码转化数据 X_in_bin = onehot.transform(target_bin) # 将原始数据和装箱后的数据说行堆叠 X_stack = np.hstack([X, X_in_bin]) print(X_stack.shape) ``` 在这段代码中,我们把数据集中的原始特征和装箱后的特征堆叠在一起,形成了一个新的特征X stack , 运行结果: ``` (50, 11) ``` 从结果可以看到, X_stack 的数量仍然是50 个,而特征数量变成了11 。下面我们要用新的特征X_stack 来训练模型。输入代码如下: ``` # 导入神经网络 from sklearn.neural_network import MLPRegressor import matplotlib.pyplot as plt # 生成一个等差数列 line = np.linspace(- 5, 5, 1000, endpoint=False).reshape(-1, 1) # 使用独热编码进行数据表达 new_line = onehot.transform(np.digitize(line, bins=bins)) # 将数据进行堆叠 line_stack = np.hstack([line, new_line]) # 重新训练模型 mlpr_interact = MLPRegressor().fit(X_stack, y) # 绘制图形 plt.plot(line, mlpr_interact.predict(line_stack), label='MLP for interaction') plt.ylim(-4, 4) for vline in bins: plt.plot([vline, vline], [-5, 5], ':', c='k') plt.legend(loc='lower right') plt.plot(X, y, 'o', c='r') # #显示图形 plt.show() ``` 运行代码,会得到如图10 - 11 所示的结果:  [结果分析]对比图10-11 和图10-8 中的MLP 模型,我们会发现在每个数据的箱体中,图10- 6 中的模型是水平的,而图10-11 中的模型是倾斜的,也就是说,在添加了交互式特征之后, 在每个数据所在的箱体中, MLP 模型增加了斜率。相比图10- 8 中的模型来说,图10-11 中的模型复杂度是有所提高的。 但是,这样的操作方式让每个箱体中模型的斜率都是一样的,这还不是我们想要的结果,我们希望达到的效果是,每个箱体中都有各自的截距和斜率。所以要换一种数据处理的方式,在Jupyter Notebook 中输入下面的代码: ``` # 使用新的堆叠方式处理数据 X_multi=np.hstack([X_in_bin,X*X_in_bin]) # 打印结果 print(X_multi.shape) print(X_multi[0]) ``` 运行结果: ``` (50, 20) [ 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. -0. -0. -0. -1.1522688 -0. -0. -0. -0. -0. -0. ] ``` [结果分析] 从结果中看到,经过以上的处理,新的数据集特征X_multi 变成了每个样本有20 个特征值的形态。试着打印出第一个样本,你会发现20 个特征中大部分数值是0 ,而在之前的X_in_bin 中数值为1 的特征,与原始数据中X 的第一个特征值一1.1522688 保留了下来。 下面用处理过的数据集训练神经网络,看看模型的结果会有什么不同。在Jupyter Noteboo k 中输入代码如下: ``` # 重新训练模型 mlpr_multi=MLPRegressor().fit(X_multi,y) line_multi=np.hstack([new_line,line*new_line]) # 绘制图形 plt.plot(line,mlpr_multi.predict(line_multi),label='MLP Regressor') for vline in bins: plt.plot([vline,vline],[-5,5],":",c='gray') plt.plot(X,y,'o',c='r') plt.legend(loc='lower right') # 显示图形 # plt.show() plt.savefig('30-2-2.jpg') ``` 运行代码,将会得到如图10-13 所示的结果。  [结果分析] 通过这样的处理之后,大家会发现,每个箱子中模型的“截距”和“斜率”都不一样了。而这种数据处理的目的, 主要是为了让比较容易出现欠拟合现象的模型能有更好的表现。例如,我们曾在第4 章介绍过的线性模型,线性模型在高维数据集中有良好的性能,但是在低维数据集中却表现一般,因此我们需要用上面的方法来进行特征扩充,以便给数据集“升维”,从而提升线性模型的准确率。 当然对数据装箱只是其中一种方式,下面我们再来看另外一种方法: 多项式特征。 # 2、向数据集添加多项式特征 首先回顾一下什么是多项式,在数学中,多项式指的是多个单项式相加所组成的代数式。当然如果是减号的话,可以看作加上这个单项式的相反数。下面是一个典型的多项式: $$ax^4+bx^3+cx^2+dx+e$$ 而其中的$$ax^4,bx^3,cx^2,dx,e$$都是单项式。在机器学习当中,常用的扩展样本特征的方式就是将特征X 进行乘方,如$$X^5,X^4,X^3$$ 等。你可能觉得这有点儿麻烦,不过没有关系,在scikit-leam 中内置了一个功能,称为PolynomialFeatures , 使用这个功能可以轻松地将原始数据集的特征进行扩展。下面来看代码: ``` # 导人numpy import numpy as np # 生成随机数列 rnd = np.random.RandomState(38) x = rnd.uniform(-5, 5, size=50) # 向数据中添加噪声 y_no_noise = (np.cos(6 * x) + x) X = x.reshape(-1, 1) y = (y_no_noise + rnd.normal(size=len(x))) / 2 # 导人多项式特征工具 from sklearn.preprocessing import PolynomialFeatures # 向数据集添加多项式特征 poly= PolynomialFeatures(degree=20 , include_bias =False) X_poly = poly . fit_transform(X) # 打印结果 print (X_poly.shape) ``` 在这段代码中,首先我们指定了Po lynomialFeatures 的degree 参数为20 ,这样可以生成20 个特征。include_bias 设定为False ,如果设定为True 的话, PolynomialFeatures只会为数据集添加数值为1 的特征。运行代码,会得到如图10-14 所示的结果。 ``` (50, 20) ``` 图10-14 添加多项式特征后的数据形态 [结果分析]可以看到现在我们处理过的数据集中,仍然是50 个样本,但每个样本的特征数变成了20 个。 那么PoiynomialFeatures 对数据进行了怎样的调整呢?我们用下面的代码打印1 个样本的特征来看一下: ``` # 打印结果 print('原始数据集中的第一个样本特征:{}'.format(X[0])) print('n处理后的数据集中第一个样本特征:{}'.format(X_poly[0])) ``` 运行代码, 会得到如图10-15 所示的结果。 ``` 原始数据集中的第一个样本特征:[-1.1522688] n处理后的数据集中第一个样本特征:[ -1.1522688 1.3277234 -1.52989425 1.76284942 -2.0312764 2.34057643 -2.6969732 3.10763809 -3.58083443 4.1260838 -4.75435765 5.47829801 -6.3124719 7.27366446 -8.38121665 9.65741449 -11.12793745 12.82237519 -14.77482293 17.02456756] ``` 图10-15 经过多项式特征添加前后的样本特征对比 {结果分析]从结果中可以看到,原始数据集的样本只有一个特征,而处理后的数据集有20 个特征。如果你的口算能力很强的话,大概可以看出处理后样本的第一个特征就是原始数据样本特征,而第二个特征是原始数据特征的2 次方,第三个特征是原始数据特征的3 次方,以此类推。 究竟是不是这样?我们可以用下面这一行代码来验证一下: ``` # 打印多项式特征处理的方式 print('PolynomialFeatures对原始数据的处理:{}'.format(poly.get_feature_names())) ``` 运行代码,会得到如图10-16 所示的结果。 ``` PolynomialFeatures对原始数据的处理:['x0', 'x0^2', 'x0^3', 'x0^4', 'x0^5', 'x0^6', 'x0^7', 'x0^8', 'x0^9', 'x0^10', 'x0^11', 'x0^12', 'x0^13', 'x0^14', 'x0^15', 'x0^16', 'x0^17', 'x0^18', 'x0^19', 'x0^20'] ``` 图10-16 多项式特征处理的方式 [结果分析] 没错, PolynomialFeatures 确实是把原始数据样本进行了从1 到20 的乘方处理。 经过这样处理之后,机器学习的模型会有什么变化呢?让我们用线性回归来实验一下,输入代码如下: ``` # 导入线性回归 from sklearn . linear_model import LinearRegression import matplotlib.pyplot as plt # 生成一个等差数列 line = np.linspace(- 5, 5, 1000, endpoint=False).reshape(-1, 1) # 使用处理后的数据训练线性回归模型 LNR_poly = LinearRegression() .fit(X_poly, y) line_poly=poly.transform(line) # 绘制图形 plt.plot(line,LNR_poly.predict(line_poly),label='Linear Regressor') plt . xlim(np . min(X) - 0.5 , np.max(X)+0.5) plt . ylim(np.min(y)-0.5 , np . max(y)+0.5 ) plt.plot(X,y,'o',c='r') plt.legend(loc='lower right') # 显示图形 plt.savefig('30-3-1.jpg',dpi=500) ``` 运行代码,会得到如图10-17 所示的结果。  图10-17 对经过PolynomialFeatures 处理的数据进行线性回归 [结果分析]我知道这对读者朋友们对于线性模型的认知有一点冲击一一本该是一条耿直的直线,现在变得分外妖挠。当然, 从图10-17 中可以得到这样的结论: 对于低维数据集, 线性模型常常会出现欠拟合的问题。而我们将数据集进行多项式特征扩展后,可以在一定程度上解决线性模型欠拟合的问题。 >⚠️:在上面的内容中,我们使用了一些对数据集特征进行扩展的方法,从而提升了线性模型或者是神经网络模型的回归分析性能,这种方法尤其在数据特征与目标呈现非线性关系时效果格外明显。当然,除了我们上面用到的PolynomialFeatures 这种将特征值转化为多项式的方法之外,我们还可以用类似正弦函数sin ()、对数函数log (),或是指数函数exp ()等来进行相似的操作。