catboost xgboost lightgbm
引入相关模型 相关小工具 从sklearn工具库中获得K折交叉验证的工具与损失函数,评估相关函数
import os
import shutil
import numpy as np
import pandas as pd
from catboost import CatBoostClassifier
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss, mean_squared_log_error
import xgboost as xgb
import lightgbm as lgb
import tqdm, sys, os, gc, argparse, warnings
warnings.filterwarnings('ignore')
获取数据 建立容器 加入进度条功能 进行读取 将训练集测试集分到 train_df跟test_df里
# 读取数据
path = 'AI量化模型预测挑战赛公开数据/'
train_files = os.listdir(path+'train')
train_df = pd.DataFrame()
for filename in tqdm.tqdm(train_files):
tmp = pd.read_csv(path+'train/'+filename)
tmp['file'] = filename
train_df = pd.concat([train_df, tmp], axis=0, ignore_index=True)
test_files = os.listdir(path+'test')
test_df = pd.DataFrame()
for filename in tqdm.tqdm(test_files):
tmp = pd.read_csv(path+'test/'+filename)
tmp['file'] = filename
test_df = pd.concat([test_df, tmp], axis=0, ignore_index=True)
对时间信息进行了处理 将时间中的 时 跟 分 提取出来
# 时间相关特征
train_df['hour'] = train_df['time'].apply(lambda x:int(x.split(':')[0]))
test_df['hour'] = test_df['time'].apply(lambda x:int(x.split(':')[0]))
train_df['minute'] = train_df['time'].apply(lambda x:int(x.split(':')[1]))
test_df['minute'] = test_df['time'].apply(lambda x:int(x.split(':')[1]))
对时间进行排列
# 为了保证时间顺序的一致性,故进行排序
train_df = train_df.sort_values(['file','time'])
test_df = test_df.sort_values(['file','time'])
进行特征构造
# 当前时间特征
# 围绕买卖价格和买卖量进行构建
# 暂时只构建买一卖一和买二卖二相关特征,进行优化时可以加上其余买卖信息
train_df['wap1'] = (train_df['n_bid1'] * train_df['n_bsize1'] + train_df['n_ask1'] * train_df['n_asize1']) / (
train_df['n_bsize1'] + train_df['n_asize1'])
test_df['wap1'] = (test_df['n_bid1'] * test_df['n_bsize1'] + test_df['n_ask1'] * test_df['n_asize1']) / (
test_df['n_bsize1'] + test_df['n_asize1'])
train_df['wap2'] = (train_df['n_bid2'] * train_df['n_bsize2'] + train_df['n_ask2'] * train_df['n_asize2']) / (
train_df['n_bsize2'] + train_df['n_asize2'])
test_df['wap2'] = (test_df['n_bid2'] * test_df['n_bsize2'] + test_df['n_ask2'] * test_df['n_asize2']) / (
test_df['n_bsize2'] + test_df['n_asize2'])
train_df['wap_balance'] = abs(train_df['wap1'] - train_df['wap2'])
train_df['price_spread'] = (train_df['n_ask1'] - train_df['n_bid1']) / ((train_df['n_ask1'] + train_df['n_bid1']) / 2)
train_df['bid_spread'] = train_df['n_bid1'] - train_df['n_bid2']
train_df['ask_spread'] = train_df['n_ask1'] - train_df['n_ask2']
train_df['total_volume'] = (train_df['n_asize1'] + train_df['n_asize2']) + (train_df['n_bsize1'] + train_df['n_bsize2'])
train_df['volume_imbalance'] = abs(
(train_df['n_asize1'] + train_df['n_asize2']) - (train_df['n_bsize1'] + train_df['n_bsize2']))
test_df['wap_balance'] = abs(test_df['wap1'] - test_df['wap2'])
test_df['price_spread'] = (test_df['n_ask1'] - test_df['n_bid1']) / ((test_df['n_ask1'] + test_df['n_bid1']) / 2)
test_df['bid_spread'] = test_df['n_bid1'] - test_df['n_bid2']
test_df['ask_spread'] = test_df['n_ask1'] - test_df['n_ask2']
test_df['total_volume'] = (test_df['n_asize1'] + test_df['n_asize2']) + (test_df['n_bsize1'] + test_df['n_bsize2'])
test_df['volume_imbalance'] = abs(
(test_df['n_asize1'] + test_df['n_asize2']) - (test_df['n_bsize1'] + test_df['n_bsize2']))
# 历史平移
# 获取历史信息
for val in ['wap1', 'wap2', 'wap_balance', 'price_spread', 'bid_spread', 'ask_spread', 'total_volume',
'volume_imbalance']:
for loc in [1, 5, 10, 20, 40, 60]:
train_df[f'file_{val}_shift{loc}'] = train_df.groupby(['file'])[val].shift(loc)
test_df[f'file_{val}_shift{loc}'] = test_df.groupby(['file'])[val].shift(loc)
# 差分特征
# 获取与历史数据的增长关系
for val in ['wap1', 'wap2', 'wap_balance', 'price_spread', 'bid_spread', 'ask_spread', 'total_volume',
'volume_imbalance']:
for loc in [1, 5, 10, 20, 40, 60]:
train_df[f'file_{val}_diff{loc}'] = train_df.groupby(['file'])[val].diff(loc)
test_df[f'file_{val}_diff{loc}'] = test_df.groupby(['file'])[val].diff(loc)
# 窗口统计
# 获取历史信息分布变化信息
# 可以尝试更多窗口大小已经统计方式,如min、max、median等
for val in ['wap1', 'wap2', 'wap_balance', 'price_spread', 'bid_spread', 'ask_spread', 'total_volume',
'volume_imbalance']:
train_df[f'file_{val}_win7_mean'] = train_df.groupby(['file'])[val].transform(
lambda x: x.rolling(window=7, min_periods=3).mean())
train_df[f'file_{val}_win7_std'] = train_df.groupby(['file'])[val].transform(
lambda x: x.rolling(window=7, min_periods=3).std())
test_df[f'file_{val}_win7_mean'] = test_df.groupby(['file'])[val].transform(
lambda x: x.rolling(window=7, min_periods=3).mean())
test_df[f'file_{val}_win7_std'] = test_df.groupby(['file'])[val].transform(
lambda x: x.rolling(window=7, min_periods=3).std())
模型
def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2023):
folds = 5
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
oof = np.zeros([train_x.shape[0], 3])
test_predict = np.zeros([test_x.shape[0], 3])
cv_scores = []
for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
print('************************************ {} ************************************'.format(str(i + 1)))
trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], \
train_y[valid_index]
if clf_name == "xgb":
xgb_params = {
'booster': 'gbtree',
'objective': 'multi:softprob',
'num_class': 3,
'max_depth': 9,
'lambda': 10,
'subsample': 0.78,
'colsample_bytree': 0.78,
'colsample_bylevel': 0.78,
'eta': 0.05,
'tree_method': 'hist',
'seed': 42,
'nthread': 16,
'tree_method': 'gpu_hist',
}
train_matrix = clf.DMatrix(trn_x, label=trn_y)
valid_matrix = clf.DMatrix(val_x, label=val_y)
test_matrix = clf.DMatrix(test_x)
watchlist = [(train_matrix, 'train'), (valid_matrix, 'eval')]
model = clf.train(xgb_params, train_matrix, num_boost_round=203, evals=watchlist)
val_pred = model.predict(valid_matrix)
test_pred = model.predict(test_matrix)
oof[valid_index] = val_pred
test_predict += test_pred / kf.n_splits
F1_score = f1_score(val_y, np.argmax(val_pred, axis=1), average='macro')
cv_scores.append(F1_score)
print(cv_scores)
return oof, test_predict
进行数据清洗
# 处理train_x和test_x中的NaN值
train_df = train_df.fillna(0)
test_df = test_df.fillna(0)
# 处理train_x和test_x中的Inf值
train_df = train_df.replace([np.inf, -np.inf], 0)
test_df = test_df.replace([np.inf, -np.inf], 0)
进行训练
# 入模特征
cols = [f for f in test_df.columns if f not in ['uuid', 'time', 'file']]
for label in ['label_5', 'label_10', 'label_20', 'label_40', 'label_60']:
print(f'=================== {label} ===================')
# 选择xgboost模型
xgb_oof, xgb_test = cv_model(xgb, train_df[cols], train_df[label], test_df[cols], 'xgb')
final_test = xgb_test
test_df[label] = np.argmax(final_test, axis=1)
在这里将xgboost的参数进行解释
booster ——》指定弱学习器的类型 booster 默认值为gbtree 基于树模型计算
eta/lr——》对应学习率
gamma——》指定叶节点进行分支所需的损失减少的最小值,默认值为0。设置的值越大,模型就越保守
alpha / reg_alpha——》L1正则化权重项,增加此值将使模型更加保守
lambda / reg_lambda——》L2正则化权重项,增加此值将使模型更加保守
max_depth——》指定树的最大深度,默认值为6,合理的设置可以防止过拟合
min_child_weight——》指定孩子节点中最小的样本权重和
subsample——》指定采样出 subsample * n_samples 个样本用于训练弱学习器。
colsample_bytree——》构建弱学习器时,对特征随机采样的比例
objective——》用于指定学习任务及相应的学习目标
num_class——》用于设置多分类问题的类别个数
eval_metric——》用于指定评估指标,可以传递各种评估方法组成的list
silent——》数值型,表示是否输出运行过程的信息
seed / random_state——》指定随机数种子