所有文章 > AI驱动 > 特征工程进阶:暴力特征字典的构建与应用 实现模型精度质的飞跃

特征工程进阶:暴力特征字典的构建与应用 实现模型精度质的飞跃

传统的特征工程方法如缺失值填充、归一化、类别特征one-hot编码、降维等,对于提升模型性能尤其是像XGBoost和LightGBM这样强大的树模型,效果可能并不显著,这些模型在处理这些基本特征工程任务时已经非常高效,因此,需要更高级和创新的特征工程方法来显著提升性能

什么是暴力特征字典

暴力特征字典是指在机器学习过程中,为了提升模型性能而构建的一个庞大的特征集合,这个特征集合通常包含了各种可能的特征,包括基础特征和经过各种转换、组合、衍生的复杂特征,通过这种方式,利用各种手段来选择和评估哪些特征对模型性能最有帮助

以下是暴力特征字典的几个关键要素:

特征生成:

  • 基础特征:直接从原始数据中提取的特征
  • 衍生特征:通过对基础特征进行变换、组合等操作生成的新特征,例如,对数变换、平方、交叉特征等

特征选择:

  • 筛选:从生成的庞大特征集中挑选出对模型有用的特征,可以通过构建模型并利用模型输出的特征重要性排名来实现
  • 降维:使用特征降维(PCA、t-sne等)来减少特征数量,同时保留大部分信息

特征工程方法:

  • 统计特征:均值、中位数、标准差等
  • 时间序列特征:滞后、滚动统计等
  • 文本特征:TF-IDF、词嵌入等
  • 交叉特征:两个或多个特征组合形成的新特征

为什么叫“暴力特征字典”?

“暴力”一词形象地描述了这种方法的广度和深度:通过生成和评估大量特征,甚至包括一些看似无意义的特征,力图找到最优的特征组合,但是暴力特征字典需要大量的计算资源和时间来生成和评估特征,生成过多特征可能导致模型复杂化,从而增加过拟合的风险

代码案例

数据读取

import pandas as pd 
df = pd.read_excel('数据.xlsx')
print("原始数据特征:",df.drop(['price'], axis=1).columns)
print("原始数据特征数:",len(df.drop(['price'], axis=1).columns))
df

这里原始数据刨除因变量price只存在7个特征,将在这个基础上在想象力范围能组合出尽可能多的特征

等频分箱

# 提取自变量特征
X = df.drop(['price'], axis=1)
# 获取所有列名并转换为列表以适合特定输入格式
variables = X.columns.tolist()

from feature_engine.discretisation import EqualFrequencyDiscretiser
from feature_engine.transformation import LogTransformer, PowerTransformer
# 创建等频分箱器
discretizer = EqualFrequencyDiscretiser(q=4, variables=variables)
X_1 = discretizer.fit_transform(X)
# 重命名分箱后的列名
new_column_names = {col: f"{col}_分箱" for col in X_1.columns}
X_1.rename(columns=new_column_names, inplace=True)
X_1

等频分箱是一种将连续变量转化为离散变量的技术,其原理是将数据排序后,将排序后的数据等频率地划分为指定数量的区间(分箱),每个分箱内包含的数据点数量大致相同

对数变换

# 对数变换前 确保没有零或负值
# 对数变换
log_transformer = LogTransformer(variables=variables)
X_2 = log_transformer.fit_transform(X)
# 重命名对数变换后的列名
new_column_names = {col: f"{col}_对数" for col in X_2.columns}
X_2.rename(columns=new_column_names, inplace=True)
X_2

对数变换将特征值拉伸或压缩,从而减少数据的偏度,平滑数据分布,适合于具有正偏态或长尾分布的数据

幂变换

# 幂变换
power_transformer = PowerTransformer(variables=variables, exp=0.5)
X_3 = power_transformer.fit_transform(X)
# 重命名对数变换后的列名
new_column_names = {col: f"{col}_幂变换" for col in X_3.columns}
X_3.rename(columns=new_column_names, inplace=True)
X_3

幂变换用于通过对数据进行幂函数变换来减小偏度和改善数据的正态性

一些数学特征变化

# 创建一个字典来存储新特征
new_features = {}

# 添加数学特征到字典中
for feature in variables:
for other_feature in variables:
if feature != other_feature:
# 创建新的特征,表示两个特征的加和
new_features[f'{feature}_plus_{other_feature}'] = df[feature] + df[other_feature]
# 创建新的特征,表示两个特征的差
new_features[f'{feature}_minus_{other_feature}'] = df[feature] - df[other_feature]
# 创建新的特征,表示两个特征的乘积
new_features[f'{feature}_times_{other_feature}'] = df[feature] * df[other_feature]
# 创建新的特征,表示两个特征的商
new_features[f'{feature}_div_by_{other_feature}'] = df[feature] / df[other_feature]

# 将新特征转为数据框
X_4 = pd.DataFrame(new_features)
X_4

合并特征字典

data = pd.concat([X, X_1, X_2, X_3, X_4], axis=1)
print("暴力数据特征:",data.columns)
print("暴力数据特征数:",len(data.columns))

通过上述特征工程步骤,从最初的7个特征扩展到196个特征,这种暴力特征工程方法有助于提供更多的信息和特征组合,从而提高模型的预测精度,当然这里是作者的暴力特征工程,读者可拓宽自己对特征工程的想象力,以此来得到更多的特征

筛选特征贡献度前20名

from sklearn.model_selection import train_test_split
X_temp, X_test, y_temp, y_test = train_test_split(data, df['price'], test_size=0.2, random_state=42)

# 然后将训练集进一步划分为训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42) # 0.125 x 0.8 = 0.1

import xgboost as xgb

# XGBoost参数
params_xgb = {
'learning_rate': 0.02,
'booster': 'gbtree',
'objective': 'reg:squarederror',
'max_leaves': 127,
'verbosity': 1,
'seed': 42,
'nthread': -1,
'colsample_bytree': 0.6,
'subsample': 0.7,
'early_stopping_rounds': 100,
'eval_metric': 'rmse'
}

# 初始化模型
model_xgb = xgb.XGBRegressor(**params_xgb)

# 训练模型
model_xgb.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=False)

# 提取特征重要性
feature_importances = model_xgb.feature_importances_

# 创建一个DataFrame,包含特征名称和对应的重要性
importance_df = pd.DataFrame({
'Feature': X_train.columns,
'Importance': feature_importances
})

# 按重要性排序
importance_df = importance_df.sort_values(by='Importance', ascending=False)

# 选择排名前20的特征
top_20_features = importance_df.head(20)
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 可视化
plt.figure(figsize=(15, 5), dpi=600)
plt.barh(top_20_features['Feature'], top_20_features['Importance'], color='skyblue')
plt.xlabel('Feature Importance')
plt.ylabel('Feature Name')
plt.title('Top 20 Feature Importances')
plt.gca().invert_yaxis()
plt.show()

通过特征工程生成新特征,使用XGBoost模型训练和评估数据,筛选出最重要的20个特征,以指导进一步的特征选择和工程,反复迭代和优化,从而提高模型的精确度

本文章转载微信公众号@Python机器学习AI