第203集:特征工程
1. 特征工程概述
1.1 什么是特征工程
特征工程(Feature Engineering)是指从原始数据中提取、转换、选择和创建有用特征的过程,以提高机器学习模型的性能。它是将原始数据转换为适合模型训练的特征表示的艺术和科学。
1.2 特征工程的重要性
- 提高模型性能:好的特征可以显著提升模型的准确性和泛化能力
- 降低计算复杂度:通过选择和提取特征减少数据维度
- 增强模型可解释性:高质量的特征使模型结果更容易理解
- 解决数据质量问题:处理数据中的噪声、异常值和缺失值
- 适应模型要求:将原始数据转换为模型可接受的格式
1.3 特征工程的主要步骤
- 特征理解:分析原始数据的含义和特点
- 特征提取:从原始数据中提取有用信息
- 特征转换:将特征转换为适合模型的形式
- 特征选择:选择最相关的特征子集
- 特征创建:创建新的组合特征
- 特征评估:评估特征对模型性能的贡献
2. 特征选择
2.1 特征选择的目的
- 减少特征数量,降低模型复杂度
- 提高模型训练效率
- 减少过拟合风险
- 增强模型可解释性
2.2 特征选择方法分类
2.2.1 过滤法(Filter Methods)
基于特征的统计特性进行选择,不依赖具体模型:
# 皮尔逊相关系数
from sklearn.feature_selection import SelectKBest, f_regression, chi2
# 回归问题
selector = SelectKBest(f_regression, k=10)
X_new = selector.fit_transform(X, y)
# 分类问题
selector = SelectKBest(chi2, k=10)
X_new = selector.fit_transform(X, y)
# 互信息
from sklearn.feature_selection import mutual_info_regression, mutual_info_classif
# 回归问题的互信息
mutual_info = mutual_info_regression(X, y)
selected_features = X.columns[np.argsort(mutual_info)[-10:]]
# 分类问题的互信息
mutual_info = mutual_info_classif(X, y)
selected_features = X.columns[np.argsort(mutual_info)[-10:]]2.2.2 包裹法(Wrapper Methods)
基于模型性能进行特征选择,考虑特征间的交互关系:
# 递归特征消除
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
rfe = RFE(estimator=model, n_features_to_select=10, step=1)
X_rfe = rfe.fit_transform(X, y)
# 显示选择的特征
selected_features = X.columns[rfe.support_]
# 使用交叉验证的递归特征消除
from sklearn.feature_selection import RFECV
rfecv = RFECV(estimator=model, step=1, cv=5, scoring='accuracy')
X_rfecv = rfecv.fit_transform(X, y)
# 最优特征数量
print(f"最优特征数量: {rfecv.n_features_}")2.2.3 嵌入法(Embedded Methods)
结合了过滤法和包裹法的优点,在模型训练过程中进行特征选择:
# L1正则化(Lasso)
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1)
lasso.fit(X, y)
# 非零系数对应的特征
selected_features = X.columns[lasso.coef_ != 0]
# 决策树特征重要性
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier()
model.fit(X, y)
# 特征重要性
feature_importances = model.feature_importances_
selected_features = X.columns[np.argsort(feature_importances)[-10:]]
# 随机森林特征重要性
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor()
model.fit(X, y)
feature_importances = model.feature_importances_2.2.4 基于模型的特征选择
# 基于梯度提升的特征重要性
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier()
model.fit(X, y)
feature_importances = model.feature_importances_
# 显示特征重要性
for feature, importance in zip(X.columns, feature_importances):
print(f"{feature}: {importance:.4f}")3. 特征提取
3.1 特征提取的定义
从原始数据中提取新的特征,通常用于降维和提取关键信息。
3.2 常见的特征提取方法
3.2.1 主成分分析(PCA)
from sklearn.decomposition import PCA
# 创建PCA模型
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
# 查看解释方差比
print(f"解释方差比: {pca.explained_variance_ratio_}")
print(f"累计解释方差: {sum(pca.explained_variance_ratio_):.2f}")
# 选择能够解释95%方差的主成分数量
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X)
print(f"选择的主成分数量: {pca.n_components_}")3.2.2 线性判别分析(LDA)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y) # LDA需要目标变量
# 查看解释方差比
print(f"解释方差比: {lda.explained_variance_ratio_}")3.2.3 独立成分分析(ICA)
from sklearn.decomposition import FastICA
ica = FastICA(n_components=2, random_state=42)
X_ica = ica.fit_transform(X)3.2.4 特征提取与降维比较
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| PCA | 数据降维,去除相关性 | 计算高效,可解释性强 | 假设数据正态分布 |
| LDA | 分类问题的降维 | 考虑类别信息,适合分类 | 只适用于分类问题 |
| ICA | 信号分离,独立成分提取 | 不假设高斯分布 | 结果解释性差 |
4. 特征转换
4.1 特征转换的目的
将特征转换为适合模型的形式,包括:
- 非线性关系线性化
- 处理异方差性
- 稳定方差
- 提高模型收敛速度
4.2 常见的特征转换方法
4.2.1 数学转换
# 对数转换
import numpy as np
df['log_feature'] = np.log(df['feature'] + 1) # +1避免0值
# 平方根转换
df['sqrt_feature'] = np.sqrt(df['feature'])
# 幂转换
df['power_feature'] = df['feature'] ** 2
# 指数转换
df['exp_feature'] = np.exp(df['feature'])4.2.2 Box-Cox转换
from scipy.stats import boxcox
# Box-Cox转换
df['boxcox_feature'], lambda_value = boxcox(df['positive_feature']) # 要求特征值为正
print(f"Box-Cox转换的lambda值: {lambda_value}")4.2.3 Yeo-Johnson转换
from sklearn.preprocessing import PowerTransformer
# Yeo-Johnson转换(支持负值)
transformer = PowerTransformer(method='yeo-johnson')
df['yeojohnson_feature'] = transformer.fit_transform(df[['feature']])4.2.4 离散化(分箱)
# 等宽分箱
df['equal_width'] = pd.cut(df['feature'], bins=5, labels=False)
# 等频分箱
df['equal_freq'] = pd.qcut(df['feature'], q=5, labels=False)
# 自定义分箱
bins = [0, 20, 40, 60, 80, 100]
labels = ['低', '中低', '中', '中高', '高']
df['custom_bins'] = pd.cut(df['feature'], bins=bins, labels=labels)4.2.5 文本特征转换
# 词袋模型
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(max_features=1000)
X_bow = vectorizer.fit_transform(texts)
# TF-IDF
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features=1000)
X_tfidf = vectorizer.fit_transform(texts)5. 特征创建
5.1 特征创建的定义
通过组合或转换现有特征创建新的有意义的特征。
5.2 常见的特征创建方法
5.2.1 统计特征
# 移动平均线
df['moving_average'] = df['value'].rolling(window=7).mean()
# 累计和
df['cumulative_sum'] = df['value'].cumsum()
# 波动率
df['volatility'] = df['value'].rolling(window=7).std()
# 最值
df['max_7d'] = df['value'].rolling(window=7).max()
df['min_7d'] = df['value'].rolling(window=7).min()5.2.2 交互特征
# 特征相乘
df['feature1_x_feature2'] = df['feature1'] * df['feature2']
# 特征相加
df['feature1_plus_feature2'] = df['feature1'] + df['feature2']
# 特征相除
df['feature1_div_feature2'] = df['feature1'] / (df['feature2'] + 1e-5) # 避免除以0
# 多项式特征
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=False)
X_poly = poly.fit_transform(X)
X_poly_df = pd.DataFrame(X_poly, columns=poly.get_feature_names_out(X.columns))5.2.3 时间特征
# 日期时间特征提取
from datetime import datetime
df['date'] = pd.to_datetime(df['timestamp'])
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['hour'] = df['date'].dt.hour
df['minute'] = df['date'].dt.minute
df['second'] = df['date'].dt.second
df['weekday'] = df['date'].dt.weekday
df['is_weekend'] = df['weekday'].isin([5, 6]).astype(int)
df['is_holiday'] = df['date'].dt.strftime('%Y-%m-%d').isin(holidays).astype(int)5.2.4 地理空间特征
# 经纬度距离计算
from geopy.distance import geodesic
def calculate_distance(row):
point1 = (row['lat1'], row['lon1'])
point2 = (row['lat2'], row['lon2'])
return geodesic(point1, point2).kilometers
df['distance_km'] = df.apply(calculate_distance, axis=1)
# 方位角计算
import numpy as np
def calculate_bearing(lat1, lon1, lat2, lon2):
dlon = np.radians(lon2 - lon1)
lat1 = np.radians(lat1)
lat2 = np.radians(lat2)
y = np.sin(dlon) * np.cos(lat2)
x = np.cos(lat1) * np.sin(lat2) - np.sin(lat1) * np.cos(lat2) * np.cos(dlon)
bearing = np.arctan2(y, x)
bearing = np.degrees(bearing)
bearing = (bearing + 360) % 360
return bearing
df['bearing'] = df.apply(lambda row: calculate_bearing(row['lat1'], row['lon1'], row['lat2'], row['lon2']), axis=1)6. 特征工程的最佳实践
6.1 数据理解
- 深入了解数据的业务背景和含义
- 分析数据的分布、相关性和异常值
- 与领域专家合作获取专业知识
6.2 特征设计原则
- 简单性:优先选择简单直观的特征
- 相关性:选择与目标变量相关的特征
- 独立性:避免高度相关的特征
- 稳定性:特征在不同数据集上应保持稳定
- 可解释性:特征应易于理解和解释
6.3 避免过拟合
- 不要创建过多的特征
- 使用交叉验证评估特征
- 考虑特征的泛化能力
- 对特征数量进行控制
6.4 特征评估
- 使用多种指标评估特征的重要性
- 可视化特征与目标变量的关系
- 通过模型性能验证特征的有效性
- 定期重新评估和更新特征
6.5 自动化特征工程
# 使用Feature-engine库
from feature_engine import feature_creation
from feature_engine import feature_selection
from feature_engine import transformation
# 特征创建
transformer = feature_creation.MathFeatures(
variables=['feature1', 'feature2'],
func=['sum', 'product', 'ratio']
)
df = transformer.fit_transform(df)
# 使用TPOT自动化机器学习
from tpot import TPOTRegressor
from tpot import TPOTClassifier
# 回归问题
tpot = TPOTRegressor(verbosity=2, max_time_mins=60, n_jobs=-1)
tpot.fit(X_train, y_train)
tpot.export('tpot_pipeline.py')7. 特征工程案例分析
7.1 电商用户行为分析
# 加载数据
import pandas as pd
# 假设我们有用户购买记录数据
user_data = pd.read_csv('user_purchase_data.csv')
# 1. 创建时间特征
user_data['purchase_date'] = pd.to_datetime(user_data['purchase_timestamp'])
user_data['purchase_month'] = user_data['purchase_date'].dt.month
user_data['purchase_weekday'] = user_data['purchase_date'].dt.weekday
user_data['purchase_hour'] = user_data['purchase_date'].dt.hour
# 2. 创建用户行为特征
# 计算每个用户的总购买次数
user_purchase_count = user_data.groupby('user_id')['purchase_id'].count().reset_index()
user_purchase_count.columns = ['user_id', 'total_purchases']
# 计算每个用户的总消费金额
user_total_spent = user_data.groupby('user_id')['amount'].sum().reset_index()
user_total_spent.columns = ['user_id', 'total_spent']
# 计算每个用户的平均购买金额
user_avg_spent = user_data.groupby('user_id')['amount'].mean().reset_index()
user_avg_spent.columns = ['user_id', 'avg_spent_per_purchase']
# 计算最近一次购买到当前的天数
current_date = user_data['purchase_date'].max()
user_last_purchase = user_data.groupby('user_id')['purchase_date'].max().reset_index()
user_last_purchase['days_since_last_purchase'] = (current_date - user_last_purchase['purchase_date']).dt.days
# 3. 合并特征
user_features = user_purchase_count.merge(user_total_spent, on='user_id')
user_features = user_features.merge(user_avg_spent, on='user_id')
user_features = user_features.merge(user_last_purchase[['user_id', 'days_since_last_purchase']], on='user_id')
# 4. 特征选择
from sklearn.feature_selection import mutual_info_regression
# 假设我们的目标是预测用户未来消费金额
target = user_features['total_spent']
features = user_features.drop(['user_id', 'total_spent'], axis=1)
# 计算互信息
mutual_info = mutual_info_regression(features, target)
feature_importance = pd.DataFrame({'feature': features.columns, 'importance': mutual_info})
feature_importance = feature_importance.sort_values('importance', ascending=False)
print("特征重要性排序:")
print(feature_importance)
# 5. 特征转换
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_features = scaler.fit_transform(features)
scaled_features_df = pd.DataFrame(scaled_features, columns=features.columns)
# 6. 保存特征
user_features_final = pd.concat([user_features['user_id'], scaled_features_df, user_features['total_spent']], axis=1)
user_features_final.to_csv('user_features.csv', index=False)8. 总结
特征工程是机器学习流程中最具创造力和影响力的环节之一,它需要深入理解数据、领域知识和模型特性。通过合理的特征选择、提取、转换和创建,可以显著提升模型的性能和可解释性。
在实际应用中,特征工程是一个迭代的过程,需要不断尝试、评估和优化。随着自动化特征工程工具的发展,我们可以更高效地进行特征工程工作,但仍然需要人类的智慧和领域知识来指导这个过程。
下一集我们将学习监督学习基础,探讨如何使用这些精心设计的特征来构建和训练监督学习模型。