3. 数据科学的功能#

数据科学因其从大量数据中提取有价值见解并做出明智决策的巨大潜力而成为一个备受追捧的领域。它结合了统计学、数学、计算机科学和领域知识等多种学科,以分析复杂的数据集并揭示模式、趋势和相关性。

目前,skscope开发了两个对数据科学社区用户有帮助的功能。

  • 第一个功能方便人们使用基于skscope开发的机器/统计学习方法。

  • 第二个特性提供了根据收集的数据选择最佳支持大小\(s\)的基准方法。

3.1. 数据依赖目标函数#

想象一下,你开发了一种基于skscope的新颖统计/机器学习方法,并且你希望数据科学家能够使用这种方法。如果目标函数是以参数为输入进行编程的,并且需要在其定义中提供数据,那么这种编程风格会引发两个主要问题。首先,用户需要理解你的特定编程实现,如果目标函数复杂,这可能会很耗时。其次,用户必须根据自己的数据修改你的目标函数,这可能会更加繁琐且容易出错,因为小的错误可能导致编程失败。这两个问题都会浪费用户的时间,并带来额外的不便。

为了使基于skscope的机器学习方法对数据科学社区更加易于使用,skscope被设计为允许使用不同数据集与相同的目标函数。以下是一个示例,其中目标函数同时接受参数和数据作为输入:

import jax.numpy as jnp
from sklearn.datasets import make_regression
from skscope import ScopeSolver

p, k = 100, 10
X, y = make_regression(n_features=p, n_informative=k)
your_data = (X, y)
## define objective function
def custom_objective(params, data):
    return jnp.sum(
        jnp.square(data[1] - data[0] @ params)
    )
solver = ScopeSolver(p, k)
your_params = solver.solve(custom_objective, your_data)

对于其他用户,即使他们的数据集大小不同(例如,新数据集包含200个预测变量),他们也可以直接使用您的实现:

from sklearn.datasets import make_regression
from skscope import ScopeSolver

p, k = 200, 5
X, y = make_regression(n_features=p, n_informative=k)
new_data = (X, y)
solver = ScopeSolver(p, k)
new_params = solver.solve(custom_objective, new_data)

你可以进一步封装你的实现,使其更易于使用:

## define a wrapped machine learning method:
def SparseRegressor(data, sparsity):
    p = data[0].shape[1]
    solver = ScopeSolver(p, sparsity)
    est_params = solver.solve(custom_objective, data)
    return est_params

通过这种封装的机器学习方法,用户可以使用一行Python命令将其应用于他们的数据集:

SparseRegressor(new_data, sparsity=5)

3.2. 最优支持大小搜索#

在其他地方,我们假设稀疏级别会被适当地设置。然而,有些情况下我们不知道最佳的稀疏级别,需要对其进行搜索。在这种情况下,我们可以将sparsity参数设置为一个整数列表,求解器将从给定的列表中搜索最佳的稀疏级别。

请注意,当使用列表进行sparsity时,还必须向skscope中的求解器提供sample_size参数。

有两种方法可以评估稀疏度水平:信息准则交叉验证

3.2.1. 信息准则#

信息准则是一种统计度量,用于评估模型的拟合优度,同时惩罚模型的复杂性。它有助于从一组竞争模型中选择最佳模型。在稀疏约束优化(特别是数据科学中的优化问题)的背景下,信息准则可用于评估不同的稀疏水平并确定最合适的支持大小。信息准则越小,模型越好。

Some information criterions implemented in the module skscope.utilities.#

``skscope.utilities``

描述

文献

AIC

赤池信息准则

[1]

BIC

贝叶斯信息准则

[2]

EBIC

扩展贝叶斯信息准则

[3]

GIC

广义信息准则

[4]

LinearSIC

特殊信息准则

[5]

3.2.1.1. 为什么LinearSIC是必要的#

在讨论信息准则时,我们经常会涉及到模型的似然函数。例如,经典的AIC公式是\(AIC = -2\log(L) + 2k\),其中\(k`\)是有效参数的数量,\(L\)是似然函数的值。在最大似然估计的背景下,通常将目标函数设置为负对数似然,即\(loss = -\log(L)\)。这是我们鼓励的建模方法,skscope中实现的信息准则,包括AICBICGICEBIC,都是基于这一假设的。

然而,机器学习中最常用的线性模型并不遵循这种方法;它们通常使用均方误差(MSE)作为损失函数。这种设置上的差异使得skscope中许多上述信息准则可能不适用。为了便于使用线性模型的用户进行稀疏性选择,我们提供了一个专门用于线性模型的GIC版本,名为LinearSIC。前缀“Linear”表示该信息准则用于线性模型,而“SIC”源自文献[4]

总之,为了达到与在abess中使用ic_type='gic'相同的效果https://abess.readthedocs.io/en/latest/Python-package/linear/Linear.html#abess.linear.LinearRegression:

  • 对于使用MSE作为损失函数的线性模型,使用LinearSIC

  • 对于使用负对数似然作为损失函数的其他模型,使用 GIC

3.2.1.2. 用法#

如果稀疏性是列表且cv=None,求解器将使用信息准则来评估稀疏性水平。 skscope求解器中的输入参数ic_method可用于选择信息准则。它应该是一个计算信息准则的方法,其参数与此示例相同:

def GIC(
    objective_value: float,
    dimensionality: int,
    effective_params_num: int,
    train_size: int,
):
    return 2 * objective_value + effective_params_num * np.log(np.log(train_size)) * np.log(dimensionality)

这是一个使用SIC找到最佳支持大小的示例。

import jax.numpy as jnp
import numpy as np
from sklearn.datasets import make_regression
from skscope.utilities import LinearSIC

n, p, k = 100, 10, 3
X, y = make_regression(n_samples=n, n_features=p, n_informative=k)
solver = ScopeSolver(
    dimensionality=p,
    sparsity=[1, 2, 3, 4, 5] ## we want to select 1-5 variables
    sample_size=n,           ## the number of samples
    ic_method=LinearSIC,     ## use SIC to evaluate sparsity levels
)
solver.solve(
    lambda params: jnp.sum((X @ params - y)**2),
    jit = True,
)
print(solver.get_result())

请注意,信息准则的有效性在很大程度上取决于目标函数的实现。即使对于相同的模型,不同的目标函数实现通常对应于不同的信息准则实现。在使用前,请仔细检查目标函数和信息准则实现是否匹配。

3.2.2. 交叉验证#

交叉验证是一种用于评估机器学习模型性能和泛化能力的技术。它涉及将可用数据划分为多个子集或折叠,以迭代地训练和测试模型。

为了利用交叉验证 [6],有一些要求:

  1. 目标函数必须将数据作为输入。

import jax.numpy as jnp
from sklearn.datasets import make_regression

## generate data
n, p, k= 10, 5, 3
X, y, true_params = make_regression(n_samples=n, n_features=p, n_informative=k, coef=True)
## define objective function
def custom_objective(params, data):
    return jnp.sum(
        jnp.square(data[1] - data[0] @ params)
    )
  1. 数据需要被分割成训练集和验证集。split_method 参数用于定义分割方法。分割方法必须是一个接受两个参数的函数:dataindex,并返回一个新的数据对象。index 参数代表训练集的索引。

def split_method(data, index):
    return (data[0][index, :], data[1][index])
  1. 初始化求解器时,必须提供sample_sizecv。请注意,cv代表交叉验证中的折数。

solver = ScopeSolver(
    dimensionality=p,          ## there are p parameters
    sparsity=[1, 2, 3, 4, 5],  ## we want to select 1-5 variables
    sample_size=n,             ## the number of samples
    split_method=split_method, ## use split_method to split data
    cv=10,                     ## use 10-fold cross validation
)

params = solver.solve(custom_objective, data = (X, y))

3.3. 参考#

  • [1] Akaike, H. (1998). 信息理论与最大似然原理的扩展。在《Hirotugu Akaike 的精选论文》(第 199-213 页)中。纽约,纽约:Springer New York。

  • [2] Schwarz, G. (1978). 估计模型的维度。统计学年鉴, 461-464.

  • [3] 陈, J., & 陈, Z. (2008). 大模型空间中选择模型的扩展贝叶斯信息准则. Biometrika, 95(3), 759-771.

  • [4] 朱, J., 温, C., 朱, J., 张, H., & 王, X. (2020). 一种用于最佳子集选择问题的多项式算法。美国国家科学院院刊, 117(52), 33117-33123.

  • [5] 朱俊贤, 朱进, 唐博瑞, 陈轩宇, 林红梅, 王雪琴 (2023). 广义线性模型中的最佳子集选择:通过拼接技术实现的快速且一致的算法. https://arxiv.org/abs/2308.00251.

  • [6] Hastie, T., Tibshirani, R., Friedman, J. H., & Friedman, J. H. (2009). 统计学习的要素:数据挖掘、推理和预测(第2卷,第1-758页)。纽约:施普林格。