特征工程实战:数据预处理与特征选择完全指南
1. 特征工程的重要性
"数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限" 特征工程流程: ├── 数据清洗:缺失值、异常值、重复值 ├── 特征变换:标准化、归一化、编码 ├── 特征构造:组合特征、交叉特征 ├── 特征选择:过滤法、包裹法、嵌入法 └── 特征降维:PCA、LDA
2. 缺失值处理
importpandasaspdimportnumpyasnpfromsklearn.imputeimportSimpleImputer,KNNImputer# 方法 1:删除缺失值data.dropna(inplace=True)# 方法 2:均值/中位数/众数填充imputer=SimpleImputer(strategy='mean')# mean/median/most_frequentX_filled=imputer.fit_transform(X)# 方法 3:KNN 填充knn_imputer=KNNImputer(n_neighbors=5)X_filled=knn_imputer.fit_transform(X)# 方法 4:前向填充(时间序列)data.fillna(method='ffill',inplace=True)# 方法 5:插值填充data.interpolate(method='linear',inplace=True)
3. 异常值检测
importnumpyasnp# 方法 1:Z-Scoredefdetect_outliers_zscore(data,threshold=3):z_scores=np.abs((data-data.mean())/data.std())returnz_scores>threshold# 方法 2:IQR(四分位距)defdetect_outliers_iqr(data,factor=1.5):Q1=data.quantile(0.25)Q3=data.quantile(0.75)IQR=Q3-Q1 lower=Q1-factor*IQR upper=Q3+factor*IQRreturn(data<lower)|(data>upper)# 方法 3:孤立森林fromsklearn.ensembleimportIsolationForest iso=IsolationForest(contamination=0.1)outliers=iso.fit_predict(X)# -1 为异常
4. 特征编码
importpandasaspdfromsklearn.preprocessingimportLabelEncoder,OneHotEncoder,OrdinalEncoder# 标签编码(有序类别)le=LabelEncoder()data['size_encoded']=le.fit_transform(data['size'])# S=2, M=1, L=0# 独热编码(无序类别)data_encoded=pd.get_dummies(data,columns=['color'],drop_first=True)# 有序编码oe=OrdinalEncoder(categories=[['low','medium','high']])data['level_encoded']=oe.fit_transform(data[['level']])# 目标编码(高基数类别)fromcategory_encodersimportTargetEncoder te=TargetEncoder()data['city_encoded']=te.fit_transform(data['city'],data['target'])
5. 特征缩放
fromsklearn.preprocessingimportStandardScaler,MinMaxScaler,RobustScaler# 标准化(均值 0,标准差 1)scaler=StandardScaler()X_scaled=scaler.fit_transform(X)# 归一化(0-1 范围)scaler=MinMaxScaler()X_scaled=scaler.fit_transform(X)# 鲁棒缩放(对异常值不敏感)scaler=RobustScaler()X_scaled=scaler.fit_transform(X)
6. 特征构造
# 时间特征data['hour']=pd.to_datetime(data['timestamp']).dt.hour data['day_of_week']=pd.to_datetime(data['timestamp']).dt.dayofweek data['month']=pd.to_datetime(data['timestamp']).dt.month data['is_weekend']=data['day_of_week'].isin([5,6]).astype(int)# 组合特征data['price_per_sqft']=data['price']/data['area']data['bath_per_bed']=data['bathrooms']/data['bedrooms']# 交互特征fromsklearn.preprocessingimportPolynomialFeatures poly=PolynomialFeatures(degree=2,interaction_only=True)X_poly=poly.fit_transform(X)# 文本特征fromsklearn.feature_extraction.textimportTfidfVectorizer tfidf=TfidfVectorizer(max_features=1000)X_text=tfidf.fit_transform(data['text'])
7. 特征选择
fromsklearn.feature_selectionimport(SelectKBest,f_classif,mutual_info_classif,RFE,SelectFromModel)# 方法 1:过滤法 - 方差阈值fromsklearn.feature_selectionimportVarianceThreshold selector=VarianceThreshold(threshold=0.01)X_selected=selector.fit_transform(X)# 方法 2:过滤法 - 相关系数correlations=data.corrwith(data['target']).abs()top_features=correlations.nlargest(10).index# 方法 3:过滤法 - 互信息selector=SelectKBest(mutual_info_classif,k=10)X_selected=selector.fit_transform(X,y)# 方法 4:包裹法 - 递归特征消除fromsklearn.ensembleimportRandomForestClassifier rfe=RFE(RandomForestClassifier(),n_features_to_select=10)X_selected=rfe.fit_transform(X,y)# 方法 5:嵌入法 - L1 正则化fromsklearn.linear_modelimportLassoCV lasso=LassoCV()lasso.fit(X,y)important=np.abs(lasso.coef_)>0.01
8. 特征降维
fromsklearn.decompositionimportPCAfromsklearn.discriminant_analysisimportLinearDiscriminantAnalysis# PCA(无监督降维)pca=PCA(n_components=0.95)# 保留 95% 方差X_pca=pca.fit_transform(X)print(f"降维后维度:{X_pca.shape[1]}")# LDA(有监督降维)lda=LinearDiscriminantAnalysis(n_components=2)X_lda=lda.fit_transform(X,y)
总结
| 技术 | 方法 | 适用场景 |
|---|
| 缺失值 | 均值/KNN/插值 | 数据不完整 |
| 编码 | OneHot/Label/Target | 分类特征 |
| 缩放 | Standard/MinMax | 量纲不同 |
| 选择 | 过滤/包裹/嵌入 | 特征过多 |
| 降维 | PCA/LDA | 高维数据 |