一个GPU版本的遗传算法迭代xgboost最优参数的示例,这里用的是自定义损失函数

一个简单的遗传算法迭代xgboost最优参数的示例,这里用的是自定义损失函数

import pandas as pd
import numpy as np
import xgboost as xgb
from sko.GA import GA
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn import metrics
from log_color import log,LogLevel
from tqdm import tqdm
# from matplotlib import pyplot as plt

train_df = pd.read_csv('./train_v2.csv')
test_df =pd.read_csv('./test_v2.csv')

x = train_df.drop(['user_id','merchant_id','label'],axis=1)
y = train_df['label']

# ## 混合打乱数据
# y_to_numpy = y.to_numpy()
# x_to_numpy = x.to_numpy()
# m,n = x_to_numpy.shape
# y_to_numpy = y_to_numpy.reshape((m,1))
# xy = np.c_[x_to_numpy,y_to_numpy]

# for i in tqdm(range(20),desc="随机打乱数据"):
#     np.random.shuffle(xy)

# x,y = xy[:,0:13],xy[:,13:14]

# log(f"x.shape:{x.shape},y.shape:{y.shape}",LogLevel.INFO)

x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.2, random_state = 42)

gamma = 0
### 自动计算alpha值的取值范围 取负例的比例
train_Y = y_train 

alpha = (train_Y==0).sum()/train_Y.size

def logistic_obj(p, dtrain):
   y = dtrain.get_label()
   p = 1.0 / (1.0 + np.exp(-p))
   grad = p * (1 - p) * (alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
               1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(1 - p) / p + p ** gamma * (
                                     1 - alpha) * (1 - y) / (1 - p))
   hess = p * (1 - p) * (p * (1 - p) * (
               -alpha * gamma ** 2 * y * (1 - p) ** gamma * np.log(p) / (1 - p) ** 2 + alpha * gamma * y * (
                   1 - p) ** gamma * np.log(p) / (1 - p) ** 2 + 2 * alpha * gamma * y * (1 - p) ** gamma / (
                           p * (1 - p)) + alpha * y * (1 - p) ** gamma / p ** 2 - gamma ** 2 * p ** gamma * (
                           1 - alpha) * (1 - y) * np.log(1 - p) / p ** 2 + 2 * gamma * p ** gamma * (1 - alpha) * (
                           1 - y) / (p * (1 - p)) + gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
           1 - p) / p ** 2 + p ** gamma * (1 - alpha) * (1 - y) / (1 - p) ** 2) - p * (
                                     alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
                                         1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
                                 1 - p) / p + p ** gamma * (1 - alpha) * (1 - y) / (1 - p)) + (1 - p) * (
                                     alpha * gamma * y * (1 - p) ** gamma * np.log(p) / (1 - p) - alpha * y * (
                                         1 - p) ** gamma / p - gamma * p ** gamma * (1 - alpha) * (1 - y) * np.log(
                                 1 - p) / p + p ** gamma * (1 - alpha) * (1 - y) / (1 - p)))
   return grad, hess

# class Myobj(xgb.core.):
#     def __call__(self,preds,label):
#         grad,hess = logistic_obj(preds,label)
#         return grad,hess
   
#     def create_obj(self):
#         return self

def XGBoostAUC(p):
   etas = [0.0001,0.001,0.01,0.1]
   sampling_methods = ["uniform","gradient_based"]
   # tree_methods = ["auto","exact","approx","hist"]
   w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17 = p
   params = { #"objective":Myobj()
               "learning_rate":w1 #0.1
              , "n_estimators":int(w2)#11 #即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边  n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。
              , "max_depth":int(w3) #构建树的深度,越大越容易过拟合
              , "min_child_weight":w4 #0.8 #越大min_child_weight,算法越保守。范围:[0,无穷大] 孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束
#                , "num_class ":1#类别数,与 multisoftmax 并用
               , "gamma":w5 #损失下降多少才进行分裂, 控制叶子节点的个数
              , "subsample":w6#0.8 #随机采样训练样本
              #, "colsample_bytree":1 #生成树时进行的列采样
#                , "objective":'binary:logistic' # {'binary:logistic'}是二分类的问题,{'multi:softmax',}是多分类的问题 这个是优化目标,必须得有,因为xgboost里面有求一阶导数和二阶导数,其实就是这个。
              , "nthread":5 #cpu 线程数
              , "scale_pos_weight":(train_Y==0).sum()/(train_Y==1).sum() #负样本总数/正样本总数 。若训练负样本总数是500 ,正样本总数100,那么设置 scale_pos_weigh为 5
              , "lambda":w7#2 # 正则化参数
              , "eta":etas[int(w8)] #0.001 # 如同学习率
               , "verbosity":1 # 打印消息的详细程度。有效值为 0(静默)、1(警告)、2(信息)、3(调试)。
#                , metrics='auc'
              , "eval_metric":"auc"
#                , "silent ": 0 # ,设置成1则没有运行信息输出,最好是设置为0.
              , "seed":int(w9)
              , "max_delta_step":w10 #范围:[0,无穷大] ,我们允许每个叶子输出的最大增量步长。如果该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但当类别极度不平衡时,它可能有助于逻辑回归。将其设置为 1-10 的值可能有助于控制更新。
               ,"subsample":w11
               ,"sampling_method":sampling_methods[int(w12)]
               ,'colsample_bytree':w13
               , 'colsample_bylevel':w14
               , 'colsample_bynode':w15
               ,"gpu_id":0 # 使用GPU的参数1
               ,"tree_method":"gpu_hist"#tree_methods[int(w16)]# #使用GPU的参数2
               ,"max_leaves":int(w16) #要添加的最大节点数。不被树方法使用
               ,"num_parallel_tree":int(w17) #每次迭代期间构建的并行树的数量。此选项用于支持增强随机森林
       }
   dtrain = xgb.DMatrix(x_train,label=y_train)
   clf = xgb.train(params=params
                   ,dtrain=dtrain
                   ,num_boost_round=100
                   ,evals=[(dtrain,"train")]
                   ,verbose_eval=False # 不显示训练信息就改False
                   ,obj=logistic_obj
                   )
   dtest = xgb.DMatrix(x_val,label=y_val)
   lr_proba = clf.predict(dtest)
   lr_proba = np.nan_to_num(lr_proba,0)
   fpr,tpr,threshold = metrics.roc_curve(y_val, lr_proba)
   roc_auc = metrics.auc(fpr,tpr)
   dtrain=None
   clf = None
   dtest = None
   lr_proba = None
   fpr,tpr,threshold = None,None,None
   log(f"本次迭代AUC分数为:[{roc_auc}],本次X值为:[{p}]",LogLevel.PASS)

   return -roc_auc


ga = GA(func=XGBoostAUC
       , n_dim=17 #待求解的自变量数量
       , size_pop=10 #种群初始化个体数量 
       , max_iter=5 # 进化迭代次数
       , prob_mut=0.01 #变异概率
       , lb=[0.1,5,1,0,0,0,0,0,10,0,0,0,0,0,0,0,1] # 自变量下限
       ,ub=[1,20,20,100,1,1,100,3,100,10,1,1,1,1,1,10,10] # 自变量上限
       ,precision=[0.1,1,1,0.1,0.1,0.1,0.1,1,1,0.1,0.1,1,0.1,0.1,0.1,1,1] #精度
       #,early_stop = True # 当出现两个相同值时是否早停退出
      )
best_x,best_y = ga.run()
print('best_x:', best_x,'\n','best_y:',best_y)


opt_x_log = pd.DataFrame({
   "best_x":[best_x]
   ,"best_y":[best_y]
})
print(f"优化结果表:{opt_x_log}")
opt_x_log.to_csv("best_x2.csv")


### 保存参数表
w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17 = best_x

etas = [0.0001,0.001,0.01,0.1]
sampling_methods = ["uniform","gradient_based"]
params = { #"objective":Myobj()
               "learning_rate":w1 #0.1
              , "n_estimators":int(w2)#11 #即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边  n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。
              , "max_depth":int(w3) #构建树的深度,越大越容易过拟合
              , "min_child_weight":w4 #0.8 #越大min_child_weight,算法越保守。范围:[0,无穷大] 孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束
               
#               
#                , "num_class ":1#类别数,与 multisoftmax 并用
               , "gamma":w5 #损失下降多少才进行分裂, 控制叶子节点的个数
              , "subsample":w6#0.8 #随机采样训练样本
              #, "colsample_bytree":1 #生成树时进行的列采样
#                , "objective":'binary:logistic' # {'binary:logistic'}是二分类的问题,{'multi:softmax',}是多分类的问题 这个是优化目标,必须得有,因为xgboost里面有求一阶导数和二阶导数,其实就是这个。
              , "nthread":5 #cpu 线程数
              , "scale_pos_weight":(train_Y==0).sum()/(train_Y==1).sum() #负样本总数/正样本总数 。若训练负样本总数是500 ,正样本总数100,那么设置 scale_pos_weigh为 5
              , "lambda":w7#2 # 正则化参数
              , "eta":etas[int(w8)] #0.001 # 如同学习率
               , "verbosity":1 # 打印消息的详细程度。有效值为 0(静默)、1(警告)、2(信息)、3(调试)。
#                , metrics='auc'
              , "eval_metric":"auc"
#                , "silent ": 0 # ,设置成1则没有运行信息输出,最好是设置为0.
              , "seed":int(w9)
              , "max_delta_step":w10 #范围:[0,无穷大] ,我们允许每个叶子输出的最大增量步长。如果该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但当类别极度不平衡时,它可能有助于逻辑回归。将其设置为 1-10 的值可能有助于控制更新。
               ,"subsample":w11
               ,"sampling_method":sampling_methods[int(w12)]
               ,'colsample_bytree':w13
               , 'colsample_bylevel':w14
               , 'colsample_bynode':w15
               ,"gpu_id":0 # 使用GPU的参数1
               ,"tree_method":"gpu_hist"#tree_methods[int(w16)]# #使用GPU的参数2
               ,"max_leaves":int(w16) #要添加的最大节点数。不被树方法使用
               ,"num_parallel_tree":int(w17) #每次迭代期间构建的并行树的数量。此选项用于支持增强随机森林


       }
params.update({"best_auc":best_y})
best_params_table = pd.DataFrame({k:[v] for k,v in params.items()})
best_params_table.to_csv("best_params_table.csv")

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值