一、概述特征工程是机器学习工作流程中不可或缺的一环,它将原始数据转化为模型可理解的形式。数据和特征的质量决定了机器学习的上限,而模型和算法则是逼近这个上限的手段。因此,特征工程的重要性不言而喻。其主要工作涉及特征的采集、预处理、选择以及降维等处理。特征工程是数据分析中最耗费时间和精力的阶段。1. 特征(Feature)特征是指从原始数据中提取出的有用信息,用于描述样本的属性。特征可以是数值型的,如身高、体重等,也可以是分类型的,如性别、颜色等。特征通常是用向量或矩阵的形式表示,作为机器学习模型的输入。在特征工程中,我们会对原始数据进行预处理、特征选择、特征提取等操作,以获得更加有用的特征,提高模型的精度和泛化能力。2. 特征工程(Feature Engineering)特征工程是指在机器学习中,对原始数据进行预处理、特征选择、特征提取等操作,以获得更加有用的特征,提高模型的精度和泛化能力的过程。特征工程旨在将原始数据转换为机器学习算法能够理解和处理的形式,为模型提供更加有用的信息。在特征工程中,我们可以对原始数据进行清洗、处理、归一化、缩放等操作,以去除噪声和异常值,提高数据的质量;同时,我们也可以通过特征选择、特征提取等技术,从原始数据中提取出更加有用的特征,以提高模型的精度和泛化能力。3. 特征工程的意义提高数据质量:特征工程可以对原始数据进行清洗、处理、归一化、缩放等操作,去除噪声和异常值,提高数据的质量。提高模型性能:特征工程可以通过特征选择、特征提取等技术,从原始数据中提取出更加有用的特征,提高模型的精度和泛化能力。减少过拟合:特征工程可以通过降维等技术,减少特征的数量,避免模型出现过拟合的问题。降低计算成本:特征工程可以通过降维等技术,减少模型的复杂度,降低计算成本。总之,特征工程是机器学习过程中非常重要的一环,其意义在于提高数据质量、提高模型性能、减少过拟合、降低计算成本等方面。特征工程的好坏直接影响着机器学习算法的性能和表现。二、特征工程数据预处理1. 缩放(静态连续变量)2.1. 标准化(Standardization)标准化:x为变量,mean(x)为均值,δ为x的标准差。将特征缩放到均值为0,方差为1的标准正态分布中,使得特征具有相似的尺度,从而避免特征值的尺度差异对模型的影响from sklearn.preprocessing import StandardScalerimport numpy as npfrom sklearn.datasets import load_iris# 加载iris数据集iris = load_iris()# 获取特征矩阵X = iris.data# 创建标准化器对象scaler = StandardScaler()# 对特征矩阵进行标准化X_std = scaler.fit_transform(X)# 绘制标准化前后的数据箱线图fig, ax = plt.subplots(1, 2, figsize=(10, 5))ax[0].boxplot(X)ax[0].set_xticklabels(iris.feature_names, rotation=45)ax[0].set_title('Before Standardization')ax[1].boxplot(X_std)ax[1].set_xticklabels(iris.feature_names, rotation=45)ax[1].set_title('After Standardization')plt.show()2.2. 最大最小值缩放(MinMax Scaling)最大最小值缩放是一种常用的数据标准化方法,它将数据缩放到一个指定的范围之内,通常是[0, 1]或[-1, 1]。该方法可以使得不同特征之间的数据具有可比性,避免了某些特征因为数据范围不同而对模型产生影响。归一化(Normalization) 将特征缩放到0和1之间,适用于特征值范围较小的情况,是最大最小值缩放的一个特例,对应b=1和a=0的情况,这里另外介绍。from sklearn.datasets import load_irisfrom sklearn.preprocessing import MinMaxScalerimport matplotlib.pyplot as plt# 加载数据集iris = load_iris()X = iris.datay = iris.target# 最大最小值缩放scaler = MinMaxScaler(feature_range=(0, 5))X_scaled = scaler.fit_transform(X)# 绘制图形plt.figure(figsize=(10, 6))plt.scatter(X[:, 0], X[:, 1], c=y)plt.title("Original Data", fontsize=16)plt.xlabel("Sepal Length", fontsize=14)plt.ylabel("Sepal Width", fontsize=14)plt.show()plt.figure(figsize=(10, 6))plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y)plt.title("Scaled Data", fontsize=16)plt.xlabel("Sepal Length (scaled)", fontsize=14)plt.ylabel("Sepal Width (scaled)", fontsize=14)plt.show()结果展示:[[1.11111111 3.125 0.33898305 0.20833333] [0.83333333 2.08333333 0.33898305 0.20833333] [0.55555556 2.5 0.25423729 0.20833333] [0.41666667 2.29166667 0.42372881 0.20833333] [0.97222222 3.33333333 0.33898305 0.20833333] [1.52777778 3.95833333 0.59322034 0.625 ] ...]从图中可以看出,经过最大最小值缩放后,数据被缩放到了 0 到 5 的范围内,并且不同特征之间的数据具有可比性2.3 幂次变换1.对数转换(Log Transformation)将特征进行对数转换,适用于特征值范围较大,但分布不均匀的情况.对数转换可以将数据的范围缩小,使得数据更加平滑,更容易处理。对数转换可以减小离群值的影响,使得数据更加符合正态分布,便于进行统计分析和建模。import numpy as npimport matplotlib.pyplot as pltfrom sklearn.datasets import load_boston# 加载波士顿房价数据集boston = load_boston()# 取出数据集中的房价数据y = boston.target# 对房价数据进行对数转换y_log = np.log(y)print(y_log)# 绘制对数转换前后的房价数据分布图fig, ax = plt.subplots(1, 2, figsize=(10, 5))ax[0].hist(y, bins=50)ax[0].set_title('Original Data')ax[1].hist(y_log, bins=50)ax[1].set_title('Log Transformed Data')plt.show()4. 缺失值的估算(静态连续变量)在实际操作中,数据集中可能缺少值。然而,这种稀疏的数据集与大多数 scikit 学习模型不兼容,这些模型假设所有特征都是数值的,而没有丢失值。所以在应用 scikit 学习模型之前,我们需要估算缺失的值。4.1. 删除法(Deletion)删除法是最简单的缺失值估算方法,直接将带有缺失值的样本或特征删除。但是,如果缺失值的比例较高,删除法会导致样本量过少或特征过少,从而影响模型的准确性。4.2. 插值法(Imputation)插值法是通过已有的数据来估算缺失值。插值法包括以下几种常用方法:单变量特征插补假设第x列中有缺失值,那么我们将用常数或第x 列的统计数据(平均值、中值或模式)对其进行估算。from sklearn.impute import SimpleImputerimport numpy as np# 构造一个有缺失值的二维数组X = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan], [10, 11, 12]])# 创建一个SimpleImputer对象,使用均值插值imputer = SimpleImputer(strategy='mean')# 对X进行插值处理X_imputed = imputer.fit_transform(X)# 输出插值后的结果print(X_imputed)结果展示:[[ 1. 2. 3. ] [ 4. 7. 6. ] [ 7. 8. 7. ] [10. 11. 12. ]]可以看到,原来X数组中的缺失值被均值插值处理后,得到了一个完整的二维数组.2. 多元特征插补多元特征插补利用整个数据集的信息来估计和插补缺失值。在 scikit-learn 中,它以循环迭代的方式实现。现在我们将使用sklearn库中的IterativeImputer类来插补缺失值。这个类使用回归模型来预测缺失值。from sklearn.datasets import load_irisimport pandas as pdimport numpy as npfrom sklearn.experimental import enable_iterative_imputerfrom sklearn.impute import IterativeImputeriris = load_iris()df = pd.DataFrame(data= np.c_[iris['data'], iris['target']], columns= iris['feature_names'] + ['target'])# 创建缺失项df_missing = df.copy()df_missing.iloc[2:4, 1] = np.nandf_missing.iloc[3:6, 2] = np.nandf_missing.iloc[5:7, 3] = np.nandf_missing.iloc[7:9, 0] = np.nandf_missing.iloc[8:10, 1] = np.nandf_missing.iloc[10:13, 2] = np.nandf_missing.iloc[11:14, 3] = np.nanprint(df_missing)# 创建实例imputer = IterativeImputer()imputer.fit(df_missing)df_imputed = pd.DataFrame(data=imputer.transform(df_missing), columns=df_missing.columns)print(df_imputed)缺失值结果展示: sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target0 5.1 3.5 1.4 0.2 0.01 4.9 3.0 1.4 0.2 0.02 4.7 NaN 1.3 0.2 0.03 4.6 NaN NaN 0.2 0.04 5.0 3.6 NaN 0.2 0.05 5.4 3.9 1.7 NaN 0.06 4.6 3.4 1.4 0.3 0.07 NaN 3.4 1.5 0.2 0.08 NaN NaN 1.4 0.2 0.09 4.9 3.1 NaN 0.1 0.010 5.4 3.7 NaN NaN 0.011 4.8 3.4 1.6 NaN 0.012 4.8 3.0 NaN NaN 0.013 4.3 3.0 NaN NaN 0.014 5.8 4.0 1.2 0.2 0.0...补全结果展示:sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target0 5.100000 3.500000 1.400000 0.200000 0.01 4.900000 3.000000 1.400000 0.200000 0.02 4.700000 3.283147 1.300000 0.200000 0.03 4.600000 3.238815 1.213727 0.200000 0.04 5.000000 3.600000 1.222952 0.200000 0.05 5.400000 3.900000 1.700000 0.353042 0.06 4.600000 3.400000 1.400000 0.300000 0.07 5.007057 3.400000 1.500000 0.200000 0.08 4.982975 3.307063 1.400000 0.200000 0.09 4.900000 3.100000 1.213727 0.100000 0.010 5.400000 3.700000 1.223548 0.240023 0.011 4.800000 3.400000 1.600000 0.341056 0.012 4.800000 3.000000 1.215897 0.227493 0.013 4.300000 3.000000 1.207741 0.198455 0.014 5.800000 4.000000 1.200000 0.200000 0.05. 特征变换(静态连续变量)多项式变换(Polynomial Transformation)多项式变换是机器学习中的一种特征工程方法,可以将原始特征进行组合,生成新的特征,从而提高模型的表现。在sklearn中,可以使用PolynomialFeatures类来进行多项式变换。from sklearn.datasets import load_bostonfrom sklearn.linear_model import LinearRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import PolynomialFeatures# 加载数据集boston = load_boston()X = boston.datay = boston.target# 将数据集分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 进行多项式变换poly = PolynomialFeatures(degree=2)X_train_poly = poly.fit_transform(X_train)X_test_poly = poly.transform(X_test)# 使用线性回归模型进行训练lr = LinearRegression()lr.fit(X_train_poly, y_train)# 在测试集上进行预测并评估模型性能score = lr.score(X_test_poly, y_test)print('R^2 score:', score)结果展示:R^2 score: 0.7258515818230033可以看出,使用多项式变换后,线性回归模型在测试集上的表现得到了明显提升,R^2分数达到了0.72左右。2.自定义变换(Custom Transformer)自定义变换是一种常见的特征工程方法,可以根据数据的特点,自定义一些变换操作,从而提高模型的表现。在sklearn中,可以通过自定义Transformer类来实现自定义变换。from sklearn.datasets import load_bostonfrom sklearn.linear_model import LinearRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.base import BaseEstimator, TransformerMixin# 定义自定义Transformer类class CustomTransformer(BaseEstimator, TransformerMixin): def __init__(self): pass def fit(self, X, y=None): return self def transform(self, X): # 对数据进行自定义变换 X_new = X[:, [0, 5, 6, 7]] X_new[:, 0] = X_new[:, 0] ** 2 X_new[:, 1] = X_new[:, 1] / X_new[:, 2] return X_new# 加载数据集boston = load_boston()X = boston.datay = boston.target# 将数据集分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 进行自定义变换ct = CustomTransformer()X_train_new = ct.fit_transform(X_train)X_test_new = ct.transform(X_test)# 使用线性回归模型进行训练lr = LinearRegression()lr.fit(X_train_new, y_train)# 在测试集上进行预测并评估模型性能score = lr.score(X_test_new, y_test)print('R^2 score:', score)结果展示:R^2 score: 0.6027146214638019可以看出,使用自定义变换后,线性回归模型在测试集上的表现得到了一定提升,R^2分数达到了0.60左右。6、特征编码(离散类别型特征)6.1 onehot编码from sklearn import preprocessing enc = preprocessing.OneHotEncoder() enc.fit([[0,0,3],[1,1,0],[0,2,1],[1,0,2]]) #这里一共有4个数据,3种特征 array = enc.transform([[0,1,3]]).toarray() #这里使用一个新的数据来测试 print(array) # [[ 1 0 0 1 0 0 0 0 1]]我们竖着看,可以看出第一种特征中只有0、1两类,第二组有0,、1、2三类,第三种有0、1、2、3四类,因此分别可以用2、3、4个状态类来表示。enc.transform就是将[0,1,3]这组特征转换成one hot编码,toarray()则是转成数组形式。第一个数为0,对应第一种特征则为 1 0;第二个数为1,对应第二种特征则为 0 1 0;第三个数为3,对应第三种特征则为 0 0 0 1。所以最后的输出为:[[ 1 0 0 1 0 0 0 0 1]]6.2 labelEncoding标签映射(Label Encoding)是一种常见的标签编码方法,将每个标签都映射为一个整数,常用于分类问题。在标签数量较少的情况下,标签映射可以简单有效地将标签转换为数字表示。from sklearn.preprocessing import LabelEncoder # 创建标签编码器 label_encoder = LabelEncoder() # 假设有一个包含标签的列表 labels = ['red', 'green', 'blue', 'green', 'red', 'blue', 'blue'] # 对标签进行编码 encoded_labels = label_encoder.fit_transform(labels) # 输出编码后的标签 print(encoded_labels)总结:数据预处理的方法有很多,此处只列其中的一些。以上方法的代码实现,均可在python的pandas和sklearn中完成。大家可根据需要去查阅学习。部分引用自https://mp.weixin.qq.com/s/Q17SHVpQoMDILXvR5gftAA、https://juejin.cn/post/7242202040427642941
yd_299475830
发表于2024-03-11 17:03:26
2024-03-11 17:03:26
最后回复
107