公众号:尤而小屋
编辑:Peter
作者:Peter
大家好,我是Peter~
今天给大家分享如何基于机器学习建模全能包scikit-learn进行特征工程feature-engineering。
特征工程
机器学习的特征工程(Feature Engineering)是机器学习项目中一个至关重要的步骤,它涉及从原始数据中提取、选择和转换特征,以便更好地训练机器学习模型。特征工程直接影响到模型的性能,因为机器学习算法的性能很大程度上依赖于输入数据的表示(即特征)。
数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
基于scikit-learn做特征工程
scikit-learn中主要用于特征的工具包:
数据预处理sklearn-Processing-data: https://scikit-learn.org/stable/modules/preprocessing.html#non-linear-transformation 特征选择sklearn-feature-selection:https://scikit-learn.org/stable/modules/feature_selection.html 降维sklearn-Dimensionality-reduction:https://scikit-learn.org/stable/modules/decomposition.html#decompositions
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
导入数据
使用鸢尾花数据集iris
from sklearn.datasets import load_iris
iris = load_iris()
# 特征数据X
X = iris.data
# 目标变量
y = iris.target
X[:5]
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2]])
y[:5]
array([0, 0, 0, 0, 0])
数据预处理processing-data
数据标准化
标准化是将数据缩放到均值为0,标准差为1的过程。使用preproccessing库的StandardScaler类对数据进行标准化的代码如下:
:x的均值 S:x的标准差
from sklearn.preprocessing import StandardScaler
# 标准化后的数据
ss_data = StandardScaler().fit_transform(X)
ss_data[:5]
array([[-0.90068117, 1.01900435, -1.34022653, -1.3154443 ],
[-1.14301691, -0.13197948, -1.34022653, -1.3154443 ],
[-1.38535265, 0.32841405, -1.39706395, -1.3154443 ],
[-1.50652052, 0.09821729, -1.2833891 , -1.3154443 ],
[-1.02184904, 1.24920112, -1.34022653, -1.3154443 ]])
用于稀疏数据(比如文本数据)的标准化MaxAbsScaler(最大值缩放到1):
from sklearn.preprocessing import MaxAbsScaler
scaler = MaxAbsScaler()
X_scaled = scaler.fit_transform(X)
数据归一化
方式1:基于最大值最小值的归一化
from sklearn.preprocessing import MinMaxScaler
mm_data = MinMaxScaler().fit_transform(X)
mm_data[:5]
array([[0.22222222, 0.625 , 0.06779661, 0.04166667],
[0.16666667, 0.41666667, 0.06779661, 0.04166667],
[0.11111111, 0.5 , 0.05084746, 0.04166667],
[0.08333333, 0.45833333, 0.08474576, 0.04166667],
[0.19444444, 0.66666667, 0.06779661, 0.04166667]])
方式2:基于规则l2的归一化处理
from sklearn.preprocessing import Normalizer
#归一化,返回值为归一化后的数据
normal_data = Normalizer().fit_transform(X)
normal_data[:5]
array([[0.80377277, 0.55160877, 0.22064351, 0.0315205 ],
[0.82813287, 0.50702013, 0.23660939, 0.03380134],
[0.80533308, 0.54831188, 0.2227517 , 0.03426949],
[0.80003025, 0.53915082, 0.26087943, 0.03478392],
[0.790965 , 0.5694948 , 0.2214702 , 0.0316386 ]])
数据二值化处理Binarizer
连续型特征的二值化处理方法:大于设置阈值的赋值为1,其他为0:
from sklearn.preprocessing import Binarizer
#二值化处理:阈值设置为3
bin_data = Binarizer(threshold=3).fit_transform(X)
bin_data[:5]
array([[1., 1., 0., 0.],
[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 0., 0.]])
独热码Onehot
from sklearn.preprocessing import OneHotEncoder
# 哑编码:对IRIS数据集的目标值进行独热码
OneHotEncoder().fit_transform(y.reshape((-1,1)))
<150x3 sparse matrix of type '<class 'numpy.float64'>'
with 150 stored elements in Compressed Sparse Row format>
scikit-learn
中的OneHotEncoder
通常与ColumnTransformer
一起使用,特别是在处理混合类型数据时:
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
# 假设 X_categorical 是包含分类变量的DataFrame
categorical_features = ['feature1', 'feature2']
onehot = OneHotEncoder(handle_unknown='ignore')
col_trans = ColumnTransformer([("onehot", onehot, categorical_features)], remainder='passthrough')
X_transformed = col_trans.fit_transform(X_categorical)
# 注意:X_transformed 是一个稀疏矩阵,用toarray() 转换为NumPy数组
X_transformed_array = X_transformed.toarray()
缺失指填充Imputer
模拟存在缺失值的数据
import pandas as pd
import numpy as np
df = pd.DataFrame({
"chinese":[100,np.nan,98,90,np.nan],
"math":[100,np.nan,98,80,94],
})
df
chinese | math | |
---|---|---|
0 | 100.0 | 100.0 |
1 | NaN | NaN |
2 | 98.0 | 98.0 |
3 | 90.0 | 80.0 |
4 | NaN | 94.0 |
from sklearn.impute import SimpleImputer
# 列方向:使用现有值的均值填充
imputer = SimpleImputer(missing_values=np.nan, strategy="mean")
imputer.fit(df)
官网地址:https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html
sklearn.impute.SimpleImputer(
missing_values=nan,
strategy='mean',
fill_value=None,
copy=True,
add_indicator=False,
keep_empty_features=False
)
impute_data = imputer.transform(df)
impute_data
array([[100., 100.],
[ 96., 93.],
[ 98., 98.],
[ 90., 80.],
[ 96., 94.]])
(100+98+90) / 3 # chinese列
96.0
(100+98+80+94) / 4 # math列
93.0
手动计算的结果和自动填充的结果是吻合的。
数据变换
基于多项式、指数、对数、平方根等进行变换;
from sklearn.preprocessing import PolynomialFeatures
# 参数degree为度,默认值为2
poly_data = PolynomialFeatures(degree=2).fit_transform(X) # X = iris.data
可以自定义变换函数:
from sklearn.preprocessing import FunctionTransformer
# 自定义变换函数
def custom_transform(X):
return X * 2
transformer = FunctionTransformer(custom_transform)
X_transformed = transformer.fit_transform(X)
还有其他的变换,比如:Box-Cox变换等
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
from scipy import stats
# 生成一组不符合正态分布的数据(例如,指数分布数据)
data = np.random.exponential(size=100)
# 进行Box-Cox变换
transformed_data, lambda_value = stats.boxcox(data)
# ----------
plt.scatter(x=range(len(data)),y=data)
plt.scatter(x=range(len(data)),y=transformed_data)
plt.show()
特征选择
根据特征选择的形式又可以将特征选择方法分为3种:
Filter:过滤法,不用考虑后续学习器,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。 Wrapper:包装法,需考虑后续学习器,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。 Embedded:嵌入法,是Filter与Wrapper方法的结合。先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。我们使用sklearn中的feature_selection库来进行特征选择。
Filter方法
基于方差
使用方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征
from sklearn.feature_selection import VarianceThreshold
# 方差选择法:threshold为方差的阈值
var_data = VarianceThreshold(threshold=3).fit_transform(X)
var_data[:5]
array([[1.4],
[1.4],
[1.3],
[1.5],
[1.4]])
基于卡方检验
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
chi_data = SelectKBest(chi2,k=3).fit_transform(X,y)
Wrapper方法
递归特征消除(Recursive Feature Elimination,RFE)
递归特征消除(Recursive Feature Elimination,RFE)是一种在机器学习中广泛使用的特征选择方法。它首先使用所有特征训练一个模型,通过迭代地训练模型并剔除不重要的特征,直到达到预设的特征数量或满足其他停止条件为止。
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
# estimator基模型;n_features_to_select 选择的特征数
rfe_data = RFE(estimator=LogisticRegression(), n_features_to_select=3).fit_transform(iris.data, iris.target)
rfe_data[:5]
array([[3.5, 1.4, 0.2],
[3. , 1.4, 0.2],
[3.2, 1.3, 0.2],
[3.1, 1.5, 0.2],
[3.6, 1.4, 0.2]])
Embedded方法
带有惩罚项的特征选择
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
# 基模型:带L2惩罚项的逻辑回归
sfm_data1 = SelectFromModel(LogisticRegression(penalty="l2", C=0.1)).fit_transform(X, y)
sfm_data1[:5]
array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2]])
基于树模型的特征选择
树模型比如GBDT可用来作为基模型进行特征选择
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
# GBDT作为基模型的特征选择
sfm_data2 = SelectFromModel(GradientBoostingClassifier()).fit_transform(X, y)
sfm_data2[:5]
array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2]])
数据降维
机器学习建模过程中,当特征数量非常大时,模型的训练时间、预测时间以及所需的计算资源(如内存和CPU/GPU)都会显著增加。通过降维,可以减少特征的数量,从而降低计算成本,使模型更加高效。
基于主成分分析PCA
PCA算法,全称为主成分分析(Principal Component Analysis),是一种无监督学习算法,主要用于数据降维和特征提取。PCA通过线性变换将原始数据映射到一个新的低维空间,以保留数据中的最大方差,即保留数据的主要信息。
from sklearn.decomposition import PCA
# PCA:n_components为主成分数目
pca_data = PCA(n_components=2).fit_transform(X)
pca_data[:5]
array([[-2.68412563, 0.31939725],
[-2.71414169, -0.17700123],
[-2.88899057, -0.14494943],
[-2.74534286, -0.31829898],
[-2.72871654, 0.32675451]])
基于线性判别分析(LDA)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
#线性判别分析法LDA: n_components为降维后的维数
lda_data = LDA(n_components=2).fit_transform(X, y)
lda_data[:5]
array([[ 8.06179978, -0.30042062],
[ 7.12868772, 0.78666043],
[ 7.48982797, 0.26538449],
[ 6.81320057, 0.67063107],
[ 8.13230933, -0.51446253]])