好的特征对于模型性能有着至关重要的影响。可以通过合成特征、对特征做简单变换、用决策树创造新特征、特征组合等方法对特征进行优化。
从一个或者多个输入特征衍生来的特征(标准化和缩放法创建的特征不算),主要包含以下几个类型:
(1)将一个特征与其本身或者其他特征相乘(特征组合)
(2)两个特征相除
(3)对连续特征进行分箱,以分为多个区间分箱。
在决策树系列(单棵决策树、GBDT、随机森林)的算法中,由于每一个样本都会被映射到决策树的一片叶子上,因此可以把样本经过每一棵决策树映射后的index(自然数)或one-hot-vector(哑编码得到的稀疏矢量)作为一项新的特征加入模型中。
具体实现采用sklearn和xgboost中的apply()和decision_path()。
特征组合是指将单独的特征进行组合(相乘或求笛卡尔积)而形成的合成特征,有助于表示非线性关系。
对非线性规律进行编码
由于通过采用随机梯度下降法可以有效地训练线性模型,因此在使用扩展的线性模型时,辅以特征组合一直都是训练大规模数据集的有效方法。可以创建很多不同种类的特征组合,例如:
组合独热向量
机器学习模型很少会组合连续特征,但是却经常组合独热特征向量,将独特特征矢量的特征组合视为逻辑连接。例如country:usa AND language:spanish
对大规模数据集使用特征组合时学习高度复杂模型的一种有效策略,而神经网络可提供另一种策略。
如果要为分桶特征定义特征列,可以使用bucketized_column( 而不是numerical_column),该列数字作为输入并使用boundaries参数中指定的分桶边界 将其转化为分桶特征。
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error
import lightgbm as lgb
import numpy as np
train_data_file = "../data/zhengqi_train.txt"
test_data_file = "../data/zhengqi_test.txt"
train_data = pd.read_csv(train_data_file, sep='\t', encoding='utf-8')
test_data = pd.read_csv(test_data_file, sep='\t', encoding='utf-8')
#定义特征构造方法
epsilon = 1e-5
#组交叉特征,可以自己定义,如增加x*x/y,log(x)/y等
func_dict = {
'add': lambda x, y: x + y,
'mins': lambda x, y: x - y,
'div': lambda x, y: x / (y + epsilon),
'multi': lambda x, y: x * y
}
#特征构造函数
def auto_features_make(train_data, test_data, func_dict, col_list):
train_data, test_data = train_data.copy(), test_data.copy()
for col_i in col_list:
for col_j in col_list:
for func_name, func in func_dict.items():
for data in [train_data, test_data]:
func_features = func(data[col_i], data[col_j])
col_func_features = '-'.join([col_i, func_name, col_j])
data[col_func_features] = func_features
return train_data, test_data
#基于PCA进行特征降维
train_data2, test_data2 = auto_features_make(train_data, test_data, func_dict, col_list=test_data.columns)
pca = PCA(n_components=500)
train_data2_pca = pca.fit_transform(train_data2.iloc[:, 0:-1])
test_data2_pca = pca.transform(test_data2)
train_data2_pca = pd.DataFrame(train_data2_pca)
test_data2_pca = pd.DataFrame(test_data2_pca)
train_data2_pca['target'] = train_data2['target']
x_train2 = train_data2[test_data2.columns].values
y_train2 = train_data2['target']
使用LightGBM模型对新构造的特征进行模型训练和评估。
#模型训练与评估
#5折交叉检验
folds = 5
kf = KFold(n_splits=folds, shuffle=True, random_state=2019)
#记录训练和预测MSE
MSE_DICT = {'train_mse': [], "test_mse": []}
#线下训练预测
for i, (train_index, test_index) in enumerate(kf.split(x_train2)):
#LGB模型
lgb_reg = lgb.LGBMRegressor(
learning_rate=0.01,
max_depth=-1,
n_estimators=5000,
boosting_type='gbdt',
random_state=2022,
objective='regression',
)
#切分训练集和预测集
x_train_kfold = x_train2[train_index]
x_test_kfold = x_train2[test_index]
y_train_kfold = y_train2[train_index]
y_test_kfold = y_train2[test_index]
#模型训练
lgb_reg.fit(X=x_train_kfold,
y=y_train_kfold,
eval_set=[(x_train_kfold, y_train_kfold),
(x_test_kfold, y_test_kfold)],
eval_names=['train', 'test'],
early_stopping_rounds=100,
eval_metric='MSE',
verbose=50)
#训练集和预测集预测
y_train_kfold_predict = lgb_reg.predict(x_train_kfold, num_iteration=lgb_reg.best_iteration_)
y_test_kfold_predict = lgb_reg.predict(x_test_kfold, num_iteration=lgb_reg.best_iteration_)
print('第{}折 训练和预测 训练MSE 预测MSE'.format(i))
train_mse = mean_squared_error(y_train_kfold_predict, y_train_kfold)
print('-----\n', '训练MSE\n', train_mse, '\n-----')
test_mse = mean_squared_error(y_test_kfold_predict, y_test_kfold)
print('-----\n', '预测MSE\n', test_mse, '\n-----')
MSE_DICT["train_mse"].append(train_mse)
MSE_DICT['test_mse'].append(test_mse)
print('-----\n', '训练MSE\n', MSE_DICT['train_mse'], '\n', np.mean(MSE_DICT['train_mse']), '\n-----')
print('-----\n', '预测MSE\n', MSE_DICT['test_mse'], '\n', np.mean(MSE_DICT['test_mse']), '\n-----')
运行结果:
...
-----
训练MSE
[0.00017012122282987903, 0.003986113221006774, 0.004653503140174019, 1.6944261550293392e-05, 0.0019608822664788713]
0.002157512822407967
-----
-----
预测MSE
[0.09929753449545065, 0.1250100344303853, 0.09311309275116833, 0.10307589284589647, 0.09883896847504547]
0.10386710459958923
-----
将代码运行得到的5折交叉验证的各折叠训练MSE、预测MSE及平均MSE,与上一节未作特征优化的结果(训练MSE平均值为0.006117279317883938,预测MSE平均值为0.10952066075608168)对比,可以发现MSE得到进一步降低。
[1] 《阿里云天池大赛赛题解析——机器学习篇》