【机器学习】(二十)数据表示与特征工程:One-Hot编码(adult数据集),特征分箱,多项式回归,自动化特征选择

特征工程:如何找到最佳的数据表示。
连续特征:由一系列浮点数组成的数组描述。
分类特征/离散特征:以不连续的方式变化描述一件产品的属性。

分类变量

分类特征是一系列固定的可能取值(而不是一个范围),表示的是定性属性(而不是数量)。数据的输入特征,当这个特征是数据时,一系列计算公式才有意义。于是需要换一种方式来表示数据。

One-Hot编码/N取一编码/虚拟变量

通常将一个分类特征的k个可能取值编码为k-1个特征,新特征取值为0/1(都为0表示最后一个可能取值)

将数据转换为分类变量的one-hot编码有两种方法:pandas;scikit-learn。

使用pandas从adult数据集(CSV文件)中加载数据

CSV格式存储:逗号分隔的一系列值。
美国收支预测adult数据集下载:http://archive.ics.uci.edu/ml/datasets/Adult

import pandas as pd 
from IPython.display import display 

# 读取数据
# 文件中没有包含列名称的表头(header=None),然后在names显示提供列名称
data = pd.read_csv( "data/adult.data", header=None, index_col=False, 
                  names=['Age','Workclass','fnlgwt','Education','EdNum','MaritalStatus',
                         'Occupation','Relationship','Race','Sex','CapitalGain',
                         'CapitalLoss','HoursPerWeek','Country','Income'])

# 选择数据集中的几列
data = data[['Age','Workclass','Education','Sex','HoursPerWeek','Occupation','Income']]

# 控制输出的格式
display(data.head())

# 检查分类数据是否有意义,比如含义上分类变量man=male
print(data.Workclass.value_counts())

# pandas数据编码
data_dummies = pd.get_dummies(data)
print(list(data_dummies.columns))
data_dummies.head()

pd.read_csv()方法:使用pandas读取csv文件,得到一个合适的DataFrame。header参数值为整数,则默认为0(数据的第一行≠文件的第一行),指定pd.DataFrame的columns(列名称)的名称在哪一行。index_col参数用作行索引的列编号或者列名,如果给定一个序列则有多个行索引。如果文件不规则,行尾有分隔符,则可以设定index_col=False表示不适用第一列作为行索引。
value_counts () 方法:返回一个序列 Series,该序列包含每个值的数量。即返回该列每个项的计数。
pd.get_dummies()方法:利用pandas实现one hot encode的方式。自动变换所有具有对象类型(比如字符串)的列或者所有分类的列。
pandas的DataFrame对象,有三个组成并存储为属性的组件:values属性:对应的二维NumPy值数组。columns属性:列名称。indexs属性:行号或行名。

pd.read_csv参数详解
高效利用value-counts函数的方法
官方文档:pandas.get_dummies

在这里插入图片描述
在这里插入图片描述
将数据框(DataFrame)转换为NumPy数组训练机器学习模型

# 将数据框数据转换为NumPy数组
# 列索引提取包含特征的列(包括范围的结尾)
features = data_dummies.loc[:, 'Age':'Occupation_ Transport-moving']
# 提取Numpy数组
x = features.values
y = data_dummies['Income_ >50K'].values
print(x.shape, y.shape) # (32561, 44) (32561,)

# 训练logsitic回归分类器模型
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0)
logreg = LogisticRegression()
logreg.fit(x_train, y_train)
print(logreg.score(x_test, y_test)) # 0.8067804937968308

pandas中的列索引包括范围的结尾,NumPy数组切片是‘左闭右开’。
需要在同时包含数据训练点和数据测试点的数据框上调用get_dummies函数,确保调用后的训练集和测试集列名称相同(有相同的语义)。

在pandas的1.0.0版本开始,移除了Series.ix and DataFrame.ix 方法,使用DataFrame的loc方法或者iloc方法进行替换。
AttributeError: ‘DataFrame’ object has no attribute 'ix’报错

数字可以编码分类变量

分类变量被编码为字符串。(sex:male,female)
分类变量被编码为整数。(class:0,1,2…)
pd.get_dummies函数将所有数字看成连续的,不为其创建虚拟变量。使用columns参数,可以指定要编码的列。
sklearn的OneHotEncoder函数,可以指定哪些变量是连续的、哪些是离散的。

# 创建一个DataFrame
demo_df = pd.DataFrame({'Integar Feature':[0, 1, 2, 1],  
                        'Catagorical Feature':['socks', 'fox', 'socks', 'box']})
display(demo_df)

# 使用get_dimmies默认编码字符串特征
# 指定需要编码的列
pd.get_dummies(demo_df, columns=['Integar Feature', 'Catagorical Feature'])

当然也可以直接转变数据类型

demo_df['Integar Future'] = demo_df['Integar Feature'].astype(str) 
pd.get_dummies(demo_df)

特征分箱/离散化

数据表示的最佳方法不仅取决于数据的语义,还取决于所使用的模型种类。
线性模型只能对线性关系建模,对于单个特征是一条直线。
特征分箱:这一串连续的直线划分成阶梯。
每两个数据点之间创建一个箱子,包含所有特征取值在这之间的数据点(两个边界之间的空间),数据点就可以用它所以在的箱子来表示。
连续特征->离散特征

将wave数据集中单个连续输入特征变换为一个分类特征

from sklearn.linear_model import LinearRegression
import mglearn
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import OneHotEncoder
x, y = mglearn.datasets.make_wave(n_samples=100)

# 创建元素
line = np.linspace(-3, 3, 100, endpoint=False).reshape(-1, 1)

# 线性模型
reg = LinearRegression().fit(x, y)

# 绘制线性模型
fig, axes = plt.subplots(1, 2, figsize=(7,3), subplot_kw={'xticks':(), 'yticks':()})
axes[0].scatter(x[:,0], y, marker='o', s=20)
axes[0].scatter(line, reg.predict(line), s=5)
axes[0].set_title("Original Linear")

# 创建箱子
bins = np.linspace(-3, 3, 10)
# 计算数据点所属的箱子
which_bin = np.digitize(x, bins=bins)

# 将离散特征变成one-hot编码并创建one-hot编码
x_binned = OneHotEncoder(sparse=False).fit_transform(which_bin)
line_binned = OneHotEncoder(sparse=False).fit_transform(np.digitize(line, bins=bins))

# 构建新的线性模型
reg2 = LinearRegression().fit(x_binned, y)
axes[1].scatter(x[:,0], y, marker='o', s=20)
axes[1].scatter(line, reg2.predict(line_binned), s=5)
axes[1].set_title("Linear Binned")

OneHotEncoder函数:实现将分类特征的每个元素转化为一个可以用来计算的值。sparse参数表示编码的格式,默认为 True,即为稀疏的格式。
numpy.digitize(x, bins, right = False)函数:返回x在bins中的位置。x参数 : numpy数组。bins参数 :一维单调数组,必须是升序或者降序。right参数:间隔是否包含最右。

scikit-learn 中 OneHotEncoder 解析

在这里插入图片描述

交互特征与多项式特征

在核SVM模型中,使用过第二个特征的平方作为扩展特征。
想要丰富特征表示,特别是对于线性模型,可以添加原始数据的交互特征和多项式特征。

使用分箱扩展连续特征

线性模型不仅可以学习偏移,还可以学习斜率。
使用分箱(偏移)扩展连续特征。可以添加交互特征或乘积特征(斜率)。
乘积特征:箱子指示符与原始特征的乘积,用来表示数据点所在的箱子以及数据点在x轴上的位置。可以将乘积特征看作每个箱子x轴特征的单独副本。它在箱子内等于原始特征,在其它位置等于0.

对线性模型在wave数据集中的每个箱子添加斜率参数:

# 添加乘积特征
x_product = np.hstack([x_binned, x*x_binned]) # (100,20)
line_product = np.hstack([line_binned, line*line_binned])

reg = LinearRegression().fit(x_product, y)

plt.plot(line, reg.predict(line_product), label='linear regression product')
# 虚线分箱
for bin in bins:
    plt.plot([bin, bin], [-3, 3], ":", c='k')
plt.plot(x[:, 0], y, 'o', c='k')
plt.legend(loc='best')

在这里插入图片描述

如果向分箱数据上的线性模型添加原始特征(x轴)作为斜率,每个分箱斜率相同,因为只有一个x轴特征,只有一个斜率。

使用原始特征的多项式

多项式回归:多项式特征+线性回归模型

from sklearn.preprocessing import PolynomialFeatures

# 生成多项式特征
poly = PolynomialFeatures(degree=10, include_bias=False).fit(x, y)
x_poly = poly.transform(x) # (100,10)

# 获取每个特征的语义
print(poly.get_feature_names()) # ['x0', 'x0^2', ... 'x0^10']

# 多项式回归
reg = LinearRegression().fit(x_poly, y)
line_poly = poly.transform(line)

plt.plot(line, reg.predict(line_poly))
plt.plot(x[:, 0], y, 'o')

PolynomialFeatures()函数:生成原始特征的多项式。degree参数:度数,决定多项式的次数。include_bias参数: 默认为True, 这个bias指的是多项式会自动包含1,设为False就没这个1了。interaction_only参数: 默认为False,适用于多个原始特征(a,b)只能交叉相乘,不能有a^2这种。
get_feature_names()方法:获取每个特征的语义。

多项式回归, PolynomialFeatures详解

在这里插入图片描述
在使用Ridge岭回归时,交互特征和多项式特征对性能有有很大提升。
更复杂的模型随机森林中,添加特征会略降低其性能。

单变量非线性变换

基于树的模型值关注特征的顺序。线性模型和神经网络一类与每个特征的尺寸和分布。若特征和目标之间存在非线性关系,不好建模。除了添加特征,应用数学函数也对变换某些特征有用,log、exp、sin。特征为整数,响应是连续的。

自动化特征选择

删减掉不重要的特征,加快预测速度,或允许可解释性更强的模型。不太可能大幅度提升性能。

三种基本策略(都是监督方法,需要目标值拟合模型)

单变量统计基于模型的选择迭代选择
使用阈值来舍弃p值(用来度量否定原假设的证据)过大的特征同时考虑所有特征(可以获取交互项),选出重要性程度(由监督模型给出,例如决策树中的feature_importances_属性)两种迭代,1:从没有特征逐个添加特征;2:所有特征开始逐个删减特征,直到满足条件。
SelectPercentile(选择固定百分比的特征)SelectKBest(选择固定数量的k个特征) 测试参数默认f_classif(分类),可选f_regression(回归)SelectFromModel变换器递归特征消除(RFE)

分类的特征选择(按百分比的单变量统计)应用于cancer数据集:

from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectPercentile
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()

# 获取一个确定的随机数,创建并添加噪声
rng = np.random.RandomState(42)
noise = rng.normal(size=(len(cancer.data), 50)) # 五十个噪声特征
x_w_noise = np.hstack([cancer.data, noise]) # 噪声添加到末尾 30+50

x_train, x_test, y_train, y_test = train_test_split(x_w_noise, cancer.target, 
                                                   random_state=0, test_size=.5)

# 特征选择
select = SelectPercentile(percentile=50).fit(x_train, y_train)
x_train_select = select.transform(x_train)

print(x_train.shape) # (284, 80)
print(x_train_select.shape) # (284, 40)

# 可视化
mask = select.get_support()
print(mask)
plt.matshow(mask.reshape(1,-1), cmap='gray_r')

# 删选后的数据测试 Logistic回归
from sklearn.linear_model import LogisticRegression

x_test_select = select.transform(x_test)

lr = LinearRegression().fit(x_train, y_train)
print(lr.score(x_test, y_test))
lr.fit(x_train_select, y_train)
print(lr.score(x_test_select, y_test))

np.random.normal(loc,scale,size)函数用于生成高斯随机分布,是随机数,其中loc表示均值,scale表示方差,size表示输出的大小。
get_support()方法查看哪些特征被选中,返回所选特征的布尔遮罩。
**matplotlib.pyplot.matshow(A, fignum=None, kwargs)显示矩阵。A是绘制的矩阵,一个矩阵元素对应一个图像像素。cmap代表一种颜色映射方式。
在这里插入图片描述
删除的大多是噪声。

# 基于模型的特征选择
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
select = SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42), threshold="median")

# 迭代特征选择
from sklearn.feature_selection import RFE
select = RFE(RandomForestClassifier(n_estimators=100, random_state=42), n_features_to_select=40)

只要选择了正确的特征,线性模型的表现就与随机森林一样好。

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值