1. 数据清洗与数据预处理
数据清洗的关键步骤
在Python特征工程中,数据清洗是奠定后续建模质量的第一步。保持数据的一致性、完整性与可追踪性是核心目标,通过识别重复、缺失与异常来提升数据质量。
通过系统化流程实现数据清洗,能够让特征工程的效果更稳定,并降低后续建模的噪声。
import pandas as pd
df = pd.read_csv('data.csv')
# 去重
df = df.drop_duplicates()
# 处理缺失值示例:用中位数填充数值列
num_cols = df.select_dtypes(include=['float64', 'int64']).columns
df[num_cols] = df[num_cols].fillna(df[num_cols].median())
# 处理日期字段
df['date'] = pd.to_datetime(df['date'])
数据类型识别与数据规范化是第一步,确保后续的编码与归一化等步骤可以无缝对接。
缺失值处理策略
缺失值是实际数据中的常态,选择合适的填充策略直接影响模型性能。在数值列上,常用中位数或均值填充;在分类列上,常用众数或新类别“未知”填充。
实现一个可配置的缺失值策略,可以让特征工程在不同数据集上保持一致性。
from sklearn.impute import SimpleImputer
import numpy as np
import pandas as pdX = df.drop('target', axis=1)
# 数值列 imputer
num_imputer = SimpleImputer(strategy='median')
# 分类列 imputer
cat_imputer = SimpleImputer(strategy='most_frequent')
X_num = X.select_dtypes(include=['int64','float64'])
X_cat = X.select_dtypes(include=['object','category'])
X_num = num_imputer.fit_transform(X_num)
X_cat = cat_imputer.fit_transform(X_cat)
通过将缺失值处理与编码、缩放等步骤分离,我们可以在管道化流程中统一管理,提升可维护性。
异常值检测与处理
异常值会扭曲分布和模型估计,采用稳健统计或z-score等方法进行检测,并根据业务场景决定截断还是替换。
import numpy as np
from scipy import stats# 简单的z-score方法
z_scores = np.abs(stats.zscore(df[num_cols]))
threshold = 3
df_clean = df[(z_scores < threshold).all(axis=1)]
对异常值的处理要与特征工程的目标一致,避免在模型训练阶段引入不合理的离群点。
2. 特征工程的核心方法
特征缩放与归一化
特征缩放是许多模型的前置要求,StandardScaler和MinMaxScaler等方法能够将特征映射到相近的区间,帮助梯度下降更稳定地收敛。
通过规范化,我们可以消除量纲差异,使得不同特征在相同尺度下参与模型训练,提升模型收敛速度和性能。

from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegressionpipe = Pipeline([('scaler', StandardScaler()),('model', LogisticRegression(max_iter=1000))
])# 假设X_train, y_train已准备好
pipe.fit(X_train, y_train)
在实现时,对数值型特征单独缩放,避免对类别特征进行不恰当的缩放,通常与其他转换组合使用。
编码类别特征:独热编码、目标编码
类别特征的编码是特征工程的核心之一,One-Hot编码可以消除类别之间的顺序信息,但会带来维度膨胀。
对高基数类别,目标编码或嵌入式编码可以在保留信息的同时降低维度,在树模型和线性模型中都常见应用。
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputercategorical_cols = X.select_dtypes(include=['object','category']).columnspreprocessor = ColumnTransformer(transformers=[('cat', OneHotEncoder(handle_unknown='ignore'), categorical_cols)],remainder='passthrough'
)# 将预处理与模型放在管道中
pipe = Pipeline(steps=[('preprocessor', preprocessor),('model', LogisticRegression(max_iter=1000))])
对于高基数类别,可以尝试目标编码方案或利用类别嵌入,配合交叉验证后效果更稳定。
多项式特征与交互特征
多项式特征通过引入交互项来增强线性模型的非线性表达能力,PolynomialFeatures可以自动生成二阶及高阶特征。
在特征工程中,需要结合正则化以避免维度爆炸导致过拟合,常用Lasso或ElasticNet来控制复杂度。
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipelinepoly = PolynomialFeatures(degree=2, include_bias=False)
X_train_poly = poly.fit_transform(X_train[numeric_cols])model = LogisticRegression(max_iter=1000)
# 或将其放入Pipeline
pipe = Pipeline([('poly', PolynomialFeatures(degree=2, include_bias=False)),('model', model)
])
pipe.fit(X_train, y_train)
对非线性关系的捕捉需要谨慎,与交叉验证结合以评估增益,避免在小样本上产生过拟合。
3. 数据编码与特征编码的高级技巧
特征选择与降维
特征选择通过筛选出对目标变量最有信息量的特征,可以提高模型的泛化能力并降低计算成本。
降维技术如PCA、t-SNE等,可以在保留信息的同时减少冗余特征,但需结合业务解释性来评估。
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression# 选择前K个特征
selector = SelectKBest(score_func=f_classif, k=20)
pca = PCA(n_components=0.95)pipeline = Pipeline([('selector', selector),('model', LogisticRegression(max_iter=1000))
])pipeline.fit(X_train, y_train)
# 或集成降维
pipe_pca = Pipeline([('scaler', StandardScaler()),('pca', PCA(n_components=0.95)),('model', LogisticRegression(max_iter=1000))
])
pipe_pca.fit(X_train, y_train)
选择合适的降维与特征选择组合,需要以交叉验证为准绳,避免因降维带来信息损失。
特征工程在模型中的实际效果评估
要评估特征工程的效果,使用交叉验证、学习曲线和基线模型对照,以量化增益。
通过对比Baseline与含有工程化特征的模型,能够清晰看到性能提升与稳定性改进。
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
import numpy as npclf = RandomForestClassifier(n_estimators=200, random_state=42)
base_score = cross_val_score(clf, X_train, y_train, cv=5).mean()# 使用含特征工程的管道
from sklearn.linear_model import LogisticRegression
logreg = Pipeline([('scaler', StandardScaler()),('model', LogisticRegression(max_iter=1000))
])
feat_score = cross_val_score(logreg, X_train, y_train, cv=5).mean()
print(base_score, feat_score)
通过系统化评估,可以量化特征工程对模型的实际贡献,确保改动带来可重复的改进。
4. sklearn预处理与管道化实战
使用Pipeline管理特征工程
Pipeline将<(数据预处理与模型训练)>整合在一个对象中,提供清晰的训练与预测流程。
通过管道化,训练阶段与预测阶段的行为保持一致,减少数据泄漏与错误。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegressionpipeline = Pipeline([('scaler', StandardScaler()),('model', LogisticRegression(max_iter=1000))
])pipeline.fit(X_train, y_train)
preds = pipeline.predict(X_test)
在实际工程中,将数据读取、清洗、编码、缩放和建模组合到一个可重复执行的Pipeline中,实现端到端自动化。
列转换器的使用
ColumnTransformer允许对不同列应用不同的转换,在同一个数据集上并行执行多种预处理,提高效率与可控性。
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegressionpreprocessor = ColumnTransformer(transformers=[('num', StandardScaler(), ['a','b','c']),('cat', OneHotEncoder(handle_unknown='ignore'), ['kind','type'])])model = Pipeline(steps=[('preprocessor', preprocessor),('model', LogisticRegression(max_iter=1000))])
model.fit(X_train, y_train)
通过ColumnTransformer,可以在同一个数据框中对数值和类别特征应用不同的转换策略,极大提升灵活性。
自定义转换器与特征工程的扩展
有时需要实现自定义转换器来完成特定的特征工程任务,继承sklearn.base.BaseEstimator和TransformerMixin实现,以确保兼容Pipeline。
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as npclass CustomRatioTransformer(BaseEstimator, TransformerMixin):def __init__(self, numerator, denominator, new_col):self.numerator = numeratorself.denominator = denominatorself.new_col = new_coldef fit(self, X, y=None):return selfdef transform(self, X):X = X.copy()X[self.new_col] = X[self.numerator] / (X[self.denominator] + 1e-6)return X
自定义转换器可以实现复杂的业务逻辑,并无缝融入Pipeline,与其他预处理步骤协同工作。
5. 实战技巧:从数据科学家到工程化部署
特征工程的可重复性与版本控制
在团队协作与生产环境中,可重复性是特征工程的核心价值,通过代码化、数据版本控制和参数记录实现可追溯。
使用如DVC、MLflow等工具,可以把特征工程流程和数据版本绑定,便于回滚与实验追踪。
# 简单示例:记录处理步骤
import joblib
# 保存预处理对象
joblib.dump(preprocessor, 'preprocessor.joblib')
# 保存训练后的模型
joblib.dump(model, 'model.joblib')
通过版本化特征与模型,可以在生产环境中实现稳定的特征服务。
在生产环境中的特征服务与缓存
生产环境通常需要将特征工程与特征服务对接,实现低延迟的特征查询与缓存策略,以支撑在线推断。
# 简化示例:使用特征服务缓存
from cachetools import LRUCachefeature_cache = LRUCache(maxsize=1024)def get_features(row):key = tuple(row.items())if key in feature_cache:return feature_cache[key]feats = compute_features(row) # 自定义特征计算feature_cache[key] = featsreturn feats
设计一个稳定的特征缓存机制,减少重复计算、降低延迟,提升在线服务吞吐。
常见坑与调优案例
常见坑包括数据泄漏、特征的未来信息、以及不一致的训练和推断数据分布,提前在开发阶段识别并避免。
调优案例往往围绕正则化、特征选择和管道并行化展开,在性能瓶颈点进行针对性优化,如减少数据传输、缓存重复计算。
# 数据泄漏示例:确保训练数据与推断数据分离
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 避免在特征工程阶段使用未来信息
df['target_next'] = df['target'].shift(-1)


