背景
最近接到一个项目,使用遗传算法对决策树进行调参;以前都是使用网格搜索来调参,没想到也可以用ga来做这件事情,再加上以前也写过比较多的ga算法,也就接了下来,本来以为要花一点时间来搞,实际上熟悉的话2-3个小时就能搞定。
算法
做项目肯定是要用库的啦(不可能自己写的),选择使用sklearn的决策树,ga算法流程比较清晰,就自己手写了,下面关键介绍ga算法的几个步骤是如何做的。
初始化
选择决策树比较重要的三个参数"max_depth", "min_samples_split", "max_leaf_nodes",穷举这三个参数可能的值进行初始化
1 def init(): 2 forest = [] 3 for max_depth in range(5, 31, 3): 4 for min_samples_split in range(5, 25, 5): 5 for max_leaf_nodes in range(5, 25, 5): 6 forest.append(make_tree([max_depth, min_samples_split, max_leaf_nodes])) 7 return forest
选择
使用准确率作为评分依据得到累计概率
1 def tree_score(X, Y, clf): 2 kf = KFold(n_splits=5) 3 score = [] 4 for train_index, valid_index in kf.split(X): 5 clf.fit(X[train_index], Y[train_index]) 6 pred = clf.predict(X[valid_index]) 7 score.append(accuracy_score(y_true=Y[valid_index], y_pred=pred)) 8 return np.mean(score)
1 def adaption(X, Y, forest): 2 score = [] 3 for t in forest: 4 score.append(tree_score(X, Y, t)) 5 best_pos = np.argmax(score) 6 global BEST_TREE 7 BEST_TREE = copy.deepcopy(forest[best_pos]) 8 sm = np.sum(score) 9 ada = score / sm 10 for i in range(1, len(ada)): 11 ada[i] = ada[i] + ada[i - 1] 12 return ada
选择这里可以注意一下,可以使用精英策略,即:把当前这一轮最好的个体,直接送入下一代中。这个策略在提升算法的稳定性上又很大用处
交叉
交叉使用的是参数的交叉,比如clf1,和clf2 然后随机得到一个找到一个交换参数的位置p,进行交叉
1 def _cross_2_tree(t1, t2): 2 sz = len(param) 3 4 t1_param_value = _dict_get_value_list(t1.__dict__, param) 5 t2_param_value = _dict_get_value_list(t2.__dict__, param) 6 pos = random.randint(0, sz - 1) 7 t1_left = t1_param_value[0:pos + 1] 8 t1_right = t1_param_value[pos + 1:] 9 10 t2_left =