Pandas-特征工程详解
Pandas-特征工程详解
- 一、特征工程的核心目标
- 二、数据类型与基础转换
- 1. 数值型特征:类型优化与异常处理
- 2. 分类型特征:编码与规范化
- (1)标签编码(Label Encoding)
- (2)独热编码(One-Hot Encoding)
- 3. 时间型特征:提取时间信息
- 三、特征创建:从原始数据中挖掘新特征
- 1. 数值型特征组合
- 2. 分组统计特征
- 3. 文本特征提取
- 四、特征转换:优化特征分布
- 1. 标准化与归一化
- 2. 对数与幂转换
- 3. 交互特征
- 五、特征选择:保留关键信息
- 1. 相关性分析
- 2. 方差过滤
- 3. 基于树模型的特征重要性
- 六、实战案例:完整特征工程流程
特征工程其质量直接决定模型性能,优质的特征能让简单模型达到复杂模型的效果,而劣质特征则可能导致模型失效,Pandas提供了丰富的函数用于特征提取、转换和选择。本文我将系统讲解如何利用Pandas进行特征工程,从数据类型转换到高级特征创建,覆盖特征工程的全流程关键技术。
一、特征工程的核心目标
特征工程的本质是将原始数据转化为模型可理解的特征,核心目标包括:
- 信息保留:最大限度保留原始数据中的有用信息
- 噪声去除:减少冗余和干扰信息
- 分布优化:调整特征分布以适应模型假设(如线性模型偏好正态分布)
- 维度控制:在信息损失最小化的前提下降低特征维度
Pandas在特征工程中的核心作用是高效处理结构化数据,支持数值型、分类型、时间型等多种数据的特征转化。
二、数据类型与基础转换
原始数据的类型往往不符合建模要求,需先进行基础转换,为后续特征工程铺路。
1. 数值型特征:类型优化与异常处理
数值型特征(int/float)是模型最易处理的类型,但需确保数据范围合理:
import pandas as pd
import numpy as np# 示例数据
data = pd.DataFrame({'age': [25, 30, 35, 150, -5], # 包含异常值'income': ['5000', '8000', '12000', '7500', 'NaN'], # 字符串型数值'score': [85.5, 92.0, 78.3, 90.1, 88.7]
})# 1. 将字符串型数值转换为float
data['income'] = pd.to_numeric(data['income'], errors='coerce') # 'NaN'转为NaN# 2. 处理异常值(年龄不可能超过120或为负)
data['age'] = data['age'].clip(lower=0, upper=120) # 截断异常值# 3. 类型优化(减少内存占用)
data['age'] = data['age'].astype('int8') # 年龄范围小,用int8足够
2. 分类型特征:编码与规范化
分类型特征(object/category)需转换为数值形式才能输入模型,常见方法包括:
(1)标签编码(Label Encoding)
适用于有序分类特征(如学历:小学<初中<高中):
# 定义有序类别
education_order = ['小学', '初中', '高中', '本科', '硕士', '博士']
data['education'] = pd.Categorical(data['education'], categories=education_order, ordered=True
)
# 转换为数值(0到n-1)
data['education_code'] = data['education'].cat.codes
(2)独热编码(One-Hot Encoding)
适用于无序分类特征(如颜色、城市):
# 对城市进行独热编码
city_dummies = pd.get_dummies(data['city'], prefix='city', drop_first=True)
# 合并到原数据
data = pd.concat([data, city_dummies], axis=1)
prefix
:为新列名添加前缀(如city_北京
)drop_first=True
:删除第一列以避免多重共线性
3. 时间型特征:提取时间信息
时间特征(datetime)蕴含丰富的模式(如季节性、周期性),需提取关键信息:
# 转换为datetime类型
data['order_time'] = pd.to_datetime(data['order_time'])# 提取时间组件
data['hour'] = data['order_time'].dt.hour # 小时(0-23)
data['dayofweek'] = data['order_time'].dt.dayofweek # 星期几(0=周一)
data['is_weekend'] = data['dayofweek'].isin([5, 6]).astype(int) # 是否周末
data['month'] = data['order_time'].dt.month # 月份(1-12)
data['is_holiday'] = data['order_time'].dt.date.isin(holiday_list).astype(int) # 是否节假日
三、特征创建:从原始数据中挖掘新特征
基于业务逻辑创建新特征,是提升模型性能的关键。Pandas的apply()
和transform()
函数是特征创建的利器。
1. 数值型特征组合
通过算术运算生成新特征(如比率、总和):
# 示例:电商数据
data['total_price'] = data['quantity'] * data['unit_price'] # 总价=数量×单价
data['price_per_weight'] = data['total_price'] / data['weight'] # 单位重量价格
data['discount_rate'] = data['actual_price'] / data['original_price'] # 折扣率
2. 分组统计特征
通过分组聚合创建统计特征(如用户平均消费):
# 按用户ID分组,计算每个用户的消费统计量
user_stats = data.groupby('user_id')['total_price'].agg(['mean', 'sum', 'max', 'count']
).rename(columns={'mean': 'user_avg_spend','sum': 'user_total_spend','max': 'user_max_spend','count': 'user_purchase_count'
})
# 合并回原数据(每个用户的统计量广播到其所有订单)
data = data.merge(user_stats, on='user_id', how='left')
3. 文本特征提取
对文本字段(如商品描述)提取关键词或长度特征:
# 商品标题长度
data['title_length'] = data['product_title'].str.len()# 标题是否包含特定关键词(如"促销")
data['has_promotion'] = data['product_title'].str.contains('促销', na=False).astype(int)# 分割并提取类别(如"男装-T恤"→提取"T恤")
data['sub_category'] = data['category'].str.split('-', expand=True)[1]
四、特征转换:优化特征分布
原始特征的分布可能不符合模型要求(如偏态分布),需通过转换使其更接近理想分布。
1. 标准化与归一化
-
标准化(Standardization):将特征转换为均值0、标准差1,适用于正态分布特征:
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() data['amount_standardized'] = scaler.fit_transform(data[['amount']])
-
归一化(Normalization):将特征缩放到[0,1]区间,适用于均匀分布特征:
data['amount_normalized'] = (data['amount'] - data['amount'].min()) / (data['amount'].max() - data['amount'].min() )
2. 对数与幂转换
适用于右偏分布特征(如收入、消费金额):
# 对数转换(处理右偏分布)
data['income_log'] = np.log1p(data['income']) # log1p = log(1+x),避免x=0时出错# 平方根转换(轻度偏态)
data['price_sqrt'] = np.sqrt(data['price'])
3. 交互特征
通过特征间的乘法/加法创建交互项,捕捉变量间的协同效应:
# 价格×数量=总价(已在特征创建中体现)
# 年龄×消费金额:捕捉不同年龄的消费能力差异
data['age_spend_interaction'] = data['age'] * data['total_price']
五、特征选择:保留关键信息
过多的特征会导致维度灾难,需筛选出与目标变量相关性高的特征。
1. 相关性分析
通过皮尔逊相关系数筛选数值特征:
# 计算特征与目标变量的相关性
corr = data.corr()['target'].abs().sort_values(ascending=False)
# 选择相关性Top20的特征
top_features = corr[1:21].index # 排除目标变量自身
data_selected = data[top_features]
2. 方差过滤
删除方差接近0的特征(几乎无变化,无预测价值):
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.01) # 方差低于0.01的特征将被删除
data_high_variance = selector.fit_transform(data)
3. 基于树模型的特征重要性
利用随机森林等模型评估特征重要性:
from sklearn.ensemble import RandomForestClassifier
# 假设X是特征,y是目标变量
rf = RandomForestClassifier()
rf.fit(X, y)
# 提取特征重要性
importance = pd.Series(rf.feature_importances_, index=X.columns)
# 选择重要性Top10的特征
top10_features = importance.sort_values(ascending=False).head(10).index
X_selected = X[top10_features]
六、实战案例:完整特征工程流程
def build_features(raw_data):"""特征工程流水线函数"""data = raw_data.copy()# 1. 数据类型转换data['order_date'] = pd.to_datetime(data['order_date'])data['price'] = pd.to_numeric(data['price'], errors='coerce')# 2. 异常值处理data['price'] = data['price'].clip(lower=0)# 3. 时间特征data['order_hour'] = data['order_date'].dt.hourdata['is_weekend'] = data['order_date'].dt.dayofweek.isin([5,6]).astype(int)# 4. 分类型特征编码data = pd.get_dummies(data, columns=['category'], drop_first=True)# 5. 分组统计特征user_stats = data.groupby('user_id')['price'].agg(['mean', 'sum']).rename(columns={'mean': 'user_avg_price', 'sum': 'user_total_spend'})data = data.merge(user_stats, on='user_id', how='left')# 6. 特征转换data['price_log'] = np.log1p(data['price'])# 7. 特征选择(删除低方差和冗余特征)data = data.drop(columns=['order_id', 'user_id', 'order_date']) # 非特征列return data# 加载原始数据并执行特征工程
raw_data = pd.read_csv('raw_orders.csv')
features = build_features(raw_data)
总结:特征工程的核心原则
好的特征往往比复杂模型更重要
- 业务驱动:特征创建需基于对业务的理解(如电商的复购率、金融的还款能力)。
- 迭代优化:先构建基础特征,结合模型反馈逐步添加复杂特征。
- 避免信息泄露:特征工程需在训练集上拟合,再应用到验证集/测试集(如分组统计不能用测试集数据)。
- 平衡复杂度:并非特征越多越好,过多特征会导致过拟合和计算成本上升。
That’s all, thanks for reading~~
觉得有用就点个赞
、收进收藏
夹吧!关注
我,获取更多干货~