引言

在机器学习的树模型(如决策树、随机森林、梯度提升树等)应用中,模型性能很大程度上取决于参数的合理设置。合适的参数能让模型更好拟合数据、提升预测准确性并避免过拟合等问题。

常见参数优化方法及原理

网格搜索(Grid Search)
  • 原理:基于穷举搜索思路。先为给定树模型定义参数网格,涵盖要优化的各参数及其可能取值范围。然后逐一遍历这些参数组合,利用交叉验证在训练集评估模型在各组合下的性能(如准确率、均方误差等),最终选出性能最佳的参数组合作为模型最终参数。
随机搜索(Random Search)
  • 原理:旨在缓解网格搜索的计算复杂度问题。同样需定义参数取值范围,但并非穷举所有组合。而是在指定范围内按随机策略随机选取一定数量的参数组合,通过交叉验证在训练集评估这些随机选取组合对应的模型性能,进而找出表现较好的参数组合。
贝叶斯优化(Bayesian Optimization)
  • 原理:这是一种基于贝叶斯定理的智能参数优化方法。首先构建目标函数(通常为模型性能指标,如验证集上的准确率)的概率模型,常采用高斯过程近似。接着依据已有的参数评估点(已尝试的参数组合及其对应性能),利用贝叶斯定理更新概率模型,以此推断目标函数在整个参数空间的分布情况。基于此推断,选择最有可能提升性能的参数点进行下一次评估,循环直至达到停止条件(如达到最大评估次数或性能提升不再明显等)。
遗传算法(Genetic Algorithm)
  • 原理:模拟自然界生物进化过程。将参数组合视为个体,首先随机生成初始种群(一组参数组合)。然后根据适应度函数(通常基于模型在验证集上的性能)评估每个个体的优劣。通过选择、交叉和变异等遗传操作,产生新的种群,不断迭代这个过程,使种群逐渐向性能更优的方向进化,最终找到较优的参数组合。
粒子群优化(Particle Swarm Optimization)
  • 原理:受鸟群觅食行为启发。将每个参数组合看作一个粒子,所有粒子构成粒子群。每个粒子有自己的位置(代表参数组合)和速度。粒子根据自身历史最优位置和群体历史最优位置来调整自己的速度和位置,不断在参数空间中搜索,通过评估粒子位置对应的模型性能,引导粒子群向性能更优的区域移动,最终找到合适的参数组合。
模拟退火算法(Simulated Annealing)
  • 原理:类比金属退火过程。从一个初始参数组合开始,在每一步迭代中,随机生成一个邻近的参数组合。根据新老参数组合对应的模型性能以及一个基于温度的接受准则(温度随迭代逐渐降低)来决定是否接受新的参数组合。在高温时,更易接受较差的新组合以跳出局部最优;在低温时,接受新组合的条件更严格,逐渐收敛到较优的参数组合。

代码实现示例

网格搜索示例(以决策树为例)
from sklearn.datasets import load_iris
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 定义决策树分类器
dtc = DecisionTreeClassifier()

# 定义要搜索的参数网格
param_grid = {
    'criterion': ['gini', 'entropy'],
    'max_depth': [None, 2, 4, 6, 8],
   'min_samples_split': [2, 5, 10]
}

# 创建网格搜索对象
grid_search = GridSearchCV(dtc, param_grid, cv=5)

# 执行网格搜索
grid_search.fit(X, y)

# 输出最佳参数组合和对应的最佳得分
print("Best parameters:", grid_search.best_params_)
print("Best score:", grid_search.best_score_)
随机搜索示例(以随机森林为例)
from sklearn.datasets import load_iris
from sklearn.model_selection import RandomSearchCV
from sklearn.ensemble import RandomForestClassifier
import numpy as np

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 定义随机森林分类器
rfc = RandomForestClassifier()

# 定义要搜索的参数分布
param_distributions = {
    'n_estimators': np.arange(50, 201, 10),
    'criterion': ['gini', 'entropy'],
    'max_depth': [None, 2, 4, 6, 8],
    'min_samples_split': [2, 5, 10]
}

# 创建随机搜索对象
random_search = RandomSearchCV(rfc, param_distributions, n_iter=10, cv=5)

# 执行随机搜索
random_search.fit(X, y)

# 输出最佳参数组合和对应的最佳得分
print("Best parameters:", random_search.best_params_)
print("Best score:", random_search.best_score_)
贝叶斯优化示例(以梯度提升树为例)
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from bayes_opt import BayesianOptimization

# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 定义要优化的参数范围
pbounds = {
    'learning_rate': (0.01, 0.2),
    'n_estimators': (50, 200),
    'max_depth': (2, 8),
    'min_samples_split': (2, 10)
}

# 定义目标函数,用于评估参数组合的性能
def target_function(learning_rate, n_estimators, max_depth, min_samples_split):
    gbc = GradientBoostingClassifier(
        learning_rate=learning_rate,
        n_estimators=n_estimators,
        max_depth=max_depth,
        min_samples_split=min_samples_split
    )
    gbc.fit(X_train, y_train)
    return gbc.score(X_test, y_test)

# 创建贝叶斯优化对象
optimizer = BayesianOptimization(
    f=target_function,
    pbounds=pbounds
)

# 执行贝叶斯优化
optimizer.maximize(iterations=10)

# 输出最佳参数组合和对应的最佳得分
print("Best parameters:", optimizer.max["params"])
print("Best score:", optimizer.max["target"])
遗传算法示例(以决策树为例)
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 定义决策树分类器
dtc = DecisionTreeClassifier()

# 定义适应度函数
def fitness_function(params):
    dtc.set_params(**params)
    scores = cross_val_score(dtc, X, y, cv=5)
    return np.mean(scores)

# 定义遗传算法参数
population_size = 20
num_generations = 10
mutation_rate = 0.1

# 随机生成初始种群
initial_population = [
    {
        'criterion': np.random.choice(['gini', 'entropy']),
        'max_depth': np.random.choice([None, 2, 4, 6, 8]),
       'min_samples_split': np.random.choice([2, 5, 10])
    } for _ in range(population_size)
]

# 迭代遗传算法过程
for generation in range(num_generations):
    # 计算种群中每个个体的适应度
    fitness_scores = [fitness_function(individual) for individual in initial_population]

    # 选择操作
    selected_indices = np.argsort(fitness_scores)[-population_size // 2:]
    selected_population = [initial_population[i] for i in selected_indices]

    # 交叉操作
    new_population = []
    for i in range(len(selected_population)):
        for j in range(len(selected_population)):
            if i!= j:
                child = {}
                for key in selected_population[i].keys():
                    if np.random.rand() < 0.5:
                        child[key] = selected_population[i][key]
                    else:
                    child[key] = selected_population[j][key]
                new_population.append(child)

    # 变异操作
    for individual in new_population:
        if np.random.rand() < mutation_rate:
            key = np.random.choice(list(individual.keys()))
            if key == 'criterion':
                individual[key] = np.random.choice(['gini', 'entropy'])
            elif key == 'max_depth':
                individual[key] = np.random.choice([None, 2, 4, 6, 8])
            elif key == 'min_samples_split':
                individual[key] = np.random.choice([2, 5, 10])

    initial_population = new_population

# 输出最佳参数组合和对应的最佳得分
best_params = max(initial_population, key=fitness_function)
print("Best parameters:", best_params)
print("Best score:", fitness_function(best_params))
  • 设定遗传算法参数,如种群大小、世代数、变异率等。
  • 随机生成初始种群,每个个体包含决策树的相关参数。
  • 迭代遗传算法过程,包括计算适应度、选择、交叉和变异操作。
  • 最后输出最佳参数组合和对应的最佳得分。
粒子群优化示例(以随机森林为例)
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 定义随机森林分类器
rfc = RandomForestClassifier()

# 定义适应度函数
def fitness_function(params):
    rfc.set_params(**params)
    scores = cross_val_score(rfc, X, y, cv=5)
    return np.mean(scores)

# 定义粒子群优化参数
num_particles = 20
max_iterations = 10
w = 0.5
c1 = 1.5
c2 = 1.5

# 随机生成初始粒子群
initial_particles = [
    {
        'n_estimators': np.random.randint(50, 201),
        'criterion': np.random.choice(['gini', 'entropy']),
        'max_depth': np.random.choice([None, 2, 4, 6, 8]),
        'min_samples_split': np.random.choice([2, 5, 10])
    } for _ in range(num_particles)
]

# 初始化粒子的速度
initial_velocities = [
    {
        'n_estimators': np.random.randn(),
        'criterion': np.random.randn(),
        'max_depth': np.random.randn(),
        'min_samples_split': np.random.randn()
    } for _in range(num_particles)
]

# 迭代粒子群优化过程
for iteration in range(max_iterations):
    # 计算粒子群中每个粒子的适应度
    fitness_scores = [fitness_function(particle) for particle in initial_particles]

    # 找到每个粒子的历史最优位置和群体历史最优位置
    personal_best_positions = []
    global_best_position = max(initial_particles, key=fitness_function)

    for i, particle in enumerate(initial_particles):
        if fitness_function(particle) >= fitness_function(personal_best_positions[i - 1]):
            personal_best_positions[i] = particle
        else:
            personal_best_positions[i] = personal_best_positions[i - 1]

    # 更新粒子的速度和位置
    for i, particle in enumerate(initial_particles):
        for key in particle.keys():
            r1 = np.random.rand()
            r2 = np.random.rand()
            velocity = w * initial_velocities[i][key] + c1 * r1 * (personal_best_positions[i][key] - particle[key]) + c2 * r2 * (global_best_position[key] - particle[key])
            particle[key] = particle[key] + velocity
            initial_velocities[i][key] = velocity

# 输出最佳参数组合和对应的最佳得分
best_params = global_best_position
print("Best parameters:", best_params)
print("Best score:", fitness_function(best_params))
  • 设定粒子群优化参数,如粒子数量、最大迭代次数、惯性权重、认知系数、社会系数等。
  • 随机生成初始粒子群和其初始速度。
  • 迭代粒子群优化过程,包括计算适应度、找到历史最优位置、更新速度和位置等操作。
  • 最后输出最佳参数组合和对应的最佳得分。
模拟退火算法示例(以梯度提升树为例)
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import GradientBoostingClassifier

# 加载鸢尾花数据集
iris = 680 iris.dataset.load_iris()
X = iris.data
y = iris.target

# 定义梯度提升树分类器
gbc = GradientBoostingClassifier()

# 定义适应度函数
def fitness_function(params):
    gbc.set_params(**params)
    scores = cross_val_score(gbc, X, y, cv=5)
    return np.mean(scores)

# 定义模拟退火算法参数
initial_temperature = 100
final_temperature = 1
temperature_decay_rate = 0.9

# 随机生成初始参数组合
initial_params = {
    'learning_rate': np.random.uniform(0.01, 0.2),
    'n_estimators': np.random.uniform(50, 200),
    'max_depth': np.random.uniform(2, 8),
    'min_samples_split': np.random.uniform(2, 10)
}

# 迭代模拟退火算法过程
while initial_temperature > final_temperature:
    # 生成邻近的参数组合
    new_params = {
        'learning_rate': initial_params['learning_rate'] + np.random.uniform(-0.1, 0.1),
        'n_estimators': initial_params['n_estimators'] + np.random.uniform(-0.1, 0.1),
        'max_depth': initial_params['max_depth'] + np.random.uniform(-0.1, 0.1),
        'min_samples_split': initial_params['min_samples_split'] + np.random.uniform(-0.1, 0.1)
    }

    # 计算新旧参数组合的适应度
    old_fitness = fitness_function(initial_params)
    new_fitness = fitness_function(new_params)

    # 根据温度和适应度决定是否接受新参数组合
    if new_fitness > old_fitness or np.random.rand() < np.exp((new_fitness - old_fitness) / initial_temperature):
        initial_params = new_params

    # 降低温度
    initial_temperature *= temperature_decay_rate

# 输出最佳参数组合和对应的最佳得分
print("Best parameters:", initial_params)
print("Best score:", fitness_function(initial_params))
  • 设定模拟退火算法参数,如初始温度、最终温度、温度衰减率等。
  • 随机生成初始参数组合。
  • 迭代模拟退火算法过程,包括生成邻近参数组合、计算适应度、决定是否接受新参数组合以及降低温度等

作者介绍:数分36计OpenDogs

目前正在撰写数分工作4部曲:AB实验、因果模型、归因分析、机器学习等;让同学们在工作、面试中没有短板!

所以你并没有超过95%的人,只是平均水平而已。