ML--数据表达与特征工程

ML–数据表达与特征工程

主要涉及的知识点有:

  • 使用哑变量对类型特征进行转化
  • 对数据进行装箱处理
  • 几种常用的数据"升维"方法
  • 常用的自动特征选择方法

一.数据表达

1.使用哑变量转化类型特征

哑变量(Dummy Variables),也被称为虚拟变量,是一种在统计学和经济领域非常常用的,用来把某些类型变量转化为二值变量的方法,在回归分析中的使用尤其广泛

# 导入pandas
import pandas as pd
# 手工输入一个数据表
fruits=pd.DataFrame({'数值特征':[5,6,7,8,9],
                     '类型特征':['西瓜','香蕉','橘子','苹果','葡萄']
                    })

# 显示
display(fruits)
数值特征 类型特征
0 5 西瓜
1 6 香蕉
2 7 橘子
3 8 苹果
4 9 葡萄

下面我们使用get_dummies来将类型特征转化为只有0和1的二值数值特征,输入代码如下

# 转化数据表中的字符串为数值
fruits_dum=pd.get_dummies(fruits)

# 显示转化后的数据表
display(fruits_dum)
数值特征 类型特征_橘子 类型特征_苹果 类型特征_葡萄 类型特征_西瓜 类型特征_香蕉
0 5 0 0 0 1 0
1 6 0 0 0 0 1
2 7 1 0 0 0 0
3 8 0 1 0 0 0
4 9 0 0 1 0 0

假如我们就是希望把数值特征也进行get_dummies转换怎么办?没问题,我们可以先将数值特征转换为字符串,然后通过get_dummiescolumns参数来转换

# 令程序将数值也看作字符串
fruits['数值特征']=fruits['数值特征'].astype(str)

# 再用get_dummies转化字符串
fruits_dum2=pd.get_dummies(fruits,columns=['数值特征'])

display(fruits_dum2)
类型特征 数值特征_5 数值特征_6 数值特征_7 数值特征_8 数值特征_9
0 西瓜 1 0 0 0 0
1 香蕉 0 1 0 0 0
2 橘子 0 0 1 0 0
3 苹果 0 0 0 1 0
4 葡萄 0 0 0 0 1

注意 实际上,如果我们不用fruits[‘数值特征’]=fruits[‘数值特征’].astype(str)这行代码把数值转换为字符串类型,依然会得到同样的结果。但是在大规模数据集中,还是建议大家进行转换字符串的操作,避免产生不可预料的错误

2.对数据进行装箱处理

首先我们生成许多随机数点在图像中

# 导入numpy
import numpy as np
# 导入画图工具
import matplotlib.pyplot as plt
# 生成随机数列
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

plt.plot(X,y,'o',c='r')

plt.show()

output_13_0.png

下面我们分别用MLPKNN算法对这个数据集进行回归分析

# 导入神经网络
from sklearn.neural_network import MLPRegressor
# 导入KNN
from sklearn.neighbors import KNeighborsRegressor

# 生成一个等差数列
line=np.linspace(-5,5,1000,endpoint=False).reshape(-1,1)
# 分别用两种算法拟合数据
mlpr=MLPRegressor().fit(X,y)
knr=KNeighborsRegressor().fit(X,y)

# 绘制图形
plt.plot(line,mlpr.predict(line),label='MLP')
plt.plot(line,knr.predict(line),label='KNN')
plt.plot(X,y,'o',c='r')
plt.legend(loc='best')

plt.show()

output_15_0.png

[结果分析] MLP产生的回归线非常接近线性模型的结果,而KNN则相对更复杂一些,它视图覆盖更多的数据点

接下来我们对数据进行一下"装箱处理(binning)",这种处理方法也称为"离散化处理(discretization)"

# 设置箱体数为11
bins=np.linspace(-5,5,11)

# 将数据进行装箱操作
target_bin=np.digitize(X,bins=bins)

# 打印装箱数据范围
print('装箱数据范围:
{}'.format(bins))

# 打印前十个数据的特征值
print('
前十个数据点的特征值:
{}'.format(X[:10]))

# 找到它们所在的箱子
print('
前十个数据点所在的箱子:
{}'.format(target_bin[:10]))
装箱数据范围:
[-5. -4. -3. -2. -1.  0.  1.  2.  3.  4.  5.]

前十个数据点的特征值:
[[-1.1522688 ]
 [ 3.59707847]
 [ 4.44199636]
 [ 2.02824894]
 [ 1.33634097]
 [ 1.05961282]
 [-2.99873157]
 [-1.12612112]
 [-2.41016836]
 [-4.25392719]]

前十个数据点所在的箱子:
[[ 4]
 [ 9]
 [10]
 [ 8]
 [ 7]
 [ 7]
 [ 3]
 [ 4]
 [ 3]
 [ 1]]

由于我们在生成这个实验数据集的时候,是在-5到5之间随机生成了50个数据点,因此我们在生成"箱子"(如果觉得这么叫有点土的话,也可以叫它"容器")的时候,也指定范围是从-5到5之间,生成11个元素的等差数列,这样每两个数值之间就形成一个箱子,一共10个

[结果分析] 从结果中可以看到,第一个箱子是-5到-4之间,第二个箱子是-4到-3之间,以此类推。第1个数据点-1.1522688所在的箱子是第4个,第2个数据点3.59707847所在的箱子是第9个,以此类推

接下来我们要做的事情,就是用新的方法来表达已经装箱的数据,所要用到的方法就是scikit-learn的独热编码OneHotEncoderOneHotEncoderpandasget_dummies功能基本上是一样的,但是OneHotEncoder目前只能用于整型数值的类型变量

# 导入独热编码
from sklearn.preprocessing import OneHotEncoder

onehot=OneHotEncoder(sparse=False)
onehot.fit(target_bin)

# 使用独热编码转化数据
X_in_bin=onehot.transform(target_bin)

print('装箱后的数据形态:{}'.format(X_in_bin.shape))
print('
装箱后的前十个数据点:{}'.format(X_in_bin[:10]))
装箱后的数据形态:(50, 10)

装箱后的前十个数据点:[[ 0.  0.  0.  1.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  1.]
 [ 0.  0.  0.  0.  0.  0.  0.  1.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  1.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  1.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  1.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]


E:Anacondaenvsmytensorflowlibsite-packagessklearnpreprocessing\_encoders.py:368: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values.
If you want the future behaviour and silence this warning, you can specify "categories='auto'".
In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly.
  warnings.warn(msg, FutureWarning)

[结果分析] 虽然数据集中样本的数量仍然是50个,但特征数变成了10个。这是因为我们生成的箱子是10个,而新的数据点的特征是用其所在的箱子号码来表示的

我们用MLPKNN算法重新进行回归分析

# 使用独热编码进行数据表达
new_line=onehot.transform(np.digitize(line,bins=bins))

# 使用新的数据来训练模型
new_mlpr=MLPRegressor().fit(X_in_bin,y)
new_knr=KNeighborsRegressor().fit(X_in_bin,y)

# 绘制图形
plt.plot(line,new_mlpr.predict(new_line),label='New MLP')
plt.plot(line,new_knr.predict(new_line),label='New KNN')

plt.plot(X,y,'o',c='r')

plt.legend(loc='best')

plt.show()

output_25_0.png

注意 这种对于样本数据进行装箱的操作对于基于决策树的算法(如随机森林,梯度上升决策树,当然也包括决策树本身)没有太多的作用,因为这算法本身就是不停在拆分样本的特征数据,所以不需要再使用装箱操作

二.数据"升维"

1.向数据集添加交互式特征

介绍两种在统计建模中常用的方法–交互式特征(Interaction Features)多项式特征(Polynomial Features)

# 手工生成两个数组
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))
将数组2添加到数据1中后得到:[1 2 3 4 5 6 7 8 9 0]

接下来我们继续用之前的数据集来进行实验,看对特征进行交互式操作会对模型产生什么样的影响

# 将原始数据和装箱后的数据进行堆叠
X_stack=np.hstack([X,X_in_bin])
print(X_stack.shape)
(50, 11)
# 将数据进行堆叠
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()

output_33_0.png

# 使用新的堆叠方式处理数据
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.       ]
# 重新训练模型
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')
plt.ylim(-4,4)

for vline in bins:
    plt.plot([vline,vline],[-5,5],':',c='gray')
plt.legend(loc='lower right')
plt.plot(X,y,'o',c='r')

plt.show()

output_35_0.png

2.向数据集添加多项式特征

# 导入多项式特征工具
from sklearn.preprocessing import PolynomialFeatures

# 向数据添加多项式特征
poly=PolynomialFeatures(degree=20,include_bias=False)
X_poly=poly.fit_transform(X)

print(X_poly.shape)
(50, 20)

在这段代码中,首先我们指定了PolynomialFeaturesdegree参数为20,这样可以生成20个特征。include_bias设定为False,如果设定为True的话,PolynomialFeatures只会为数据集添加数值为1的特征

print('原始数据集中的第一个样本特征:
{}'.format(X[0]))
print('
处理后的数据集中的第一个样本特征:
{}'.format(X_poly[0]))
原始数据集中的第一个样本特征:
[-1.1522688]

处理后的数据集中的第一个样本特征:
[ -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]
# 打印多项式特征处理的方式
print('PolynomialFeatures对原始数据的处理:
{}'.format(poly.get_feature_names()))
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']
# 导入线性回归
from sklearn.linear_model import LinearRegression

# 使用处理后的数据训练线性回归模型
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.xlim(np.min(y)-0.5,np.max(y)+0.5)

plt.plot(X,y,'o',c='r')
plt.legend(loc='lower right')

plt.show()

output_41_0.png

原文地址:https://www.cnblogs.com/LQ6H/p/10425433.html