超参数调优#

skfolio 中进行超参数调优遵循与 scikit-learn 相同的API。

超参数是指在估计器中未直接学习的参数。它们作为参数传递给估计器类的构造函数。

搜索超参数空间以找到最佳交叉验证得分是可能的并且是推荐的。

在构造估算器时提供的任何参数都可以以这种方式进行优化。具体而言,要查找给定估算器的所有参数的名称和当前值,请使用:

estimator.get_params()

搜索由以下内容组成:

  • 一个估计器(如 MeanRisk

  • 一个参数空间

  • 用于搜索或抽样候选者的方法

  • 交叉验证方案

  • a 得分函数

在scikit-learn中提供了两种通用的参数搜索方法:对于给定的值,GridSearchCV 详尽地考虑所有参数组合,而 RandomizedSearchCV 可以从具有指定分布的参数空间中随机抽取一定数量的候选者。

在描述这些工具之后,我们详细介绍了适用于这些方法的 最佳实践

随机参数优化#

虽然使用参数设置的网格方法是目前最广泛使用的参数优化方法,但其他搜索方法具有更有利的特性。RandomizedSearchCV 实现了对参数的随机搜索, 每个设置都是从可能参数值的分布中采样。这比全面搜索有两个主要优点:

  • 预算可以独立于参数的数量和可能的值进行选择。

  • 添加不影响性能的参数不会降低效率。

指定如何对参数进行采样是使用字典完成的,这与为 GridSearchCV 指定参数非常相似。此外,计算预算,即采样候选者的数量或采样迭代次数,是通过 n_iter 参数指定的。对于每个参数,可以指定一个可能值的分布或一组离散选择(将均匀采样)。

原则上,任何提供 rvs(随机变量样本)方法以获取值的函数都可以传递。对 rvs 函数的调用应该在连续调用中提供可能参数值的独立随机样本。

scipy.stats 模块包含许多用于抽样参数的有用分布,例如 expongammauniformloguniformrandint

对于连续参数,例如 l1_coef,指定连续分布以充分利用随机化是很重要的。这样,增加 n_iter 将总是导致更细致的搜索。

连续的对数均匀随机变量是对数间隔参数的连续版本。例如,指定上面的 l2_coef 的等效项时,可以使用 loguniform(0.01,  1) 来代替 [0.01, 0.1, 1]

与上面的网格搜索示例相对应,我们可以指定一个在 0.011 之间对数均匀分布的连续随机变量:

import scipy.stats as stats
{'l1_coef': stats.loguniform(0.01,  1), 'risk_measure': [RiskMeasure.SEMI_VARIANCE]}

示例:

import scipy.stats as stats
from sklearn.model_selection import KFold, RandomizedSearchCV, train_test_split

from skfolio import RiskMeasure
from skfolio.datasets import load_sp500_dataset
from skfolio.optimization import MeanRisk
from skfolio.preprocessing import prices_to_returns

prices = load_sp500_dataset()
X = prices_to_returns(prices)
X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)

param_dist = {'l2_coef': stats.loguniform(0.01,  1), 'risk_measure': [RiskMeasure.CVAR]}

rd_search = RandomizedSearchCV(
    estimator=MeanRisk(min_weights=-1),
    cv=KFold(),
    n_iter=10,
    param_distributions=param_dist,
    n_jobs=-1  # using all cores
)
rd_search.fit(X_train)
print(rd_search.cv_results_)

best_model = rd_search.best_estimator_
print(best_model.weights_)