去噪的黎明:用于表格数据填充的多输出机器学习模型

Jon Tyson 在 Unsplash 上的照片

处理表格数据中的缺失值是数据科学中的一个基本问题。如果由于某种原因不能忽略或省略缺失值,那么我们可以尝试填充它们,即用其他值替换缺失值。有一些简单(但简化)的填充方法和一些高级方法(更准确但复杂且可能消耗资源)。本文介绍了一种新颖的表格数据填充方法,旨在在简单性和实用性之间取得平衡。

具体而言,我们将看到如何将去噪的概念(通常与非结构化数据相关联)用于快速将几乎任何多输出机器学习算法转化为适用于实践的表格数据填充器。首先,我们将介绍一些有关去噪、填充和多输出算法的基本概念,然后深入探讨如何使用去噪将多输出算法转化为填充器。然后,我们将简要介绍如何在行业实践中应用这种新方法的示例。最后,我们将讨论在生成式人工智能和基础模型时代,基于去噪的表格数据填充的未来相关性。为了便于解释,代码示例只会以Python语言显示,尽管概念方法本身不依赖于特定语言。

从去噪到填充

去噪是指从数据中去除噪声的过程。去噪算法将带有噪声的数据作为输入,经过一些巧妙的处理尽可能减少噪声,并返回去噪后的数据。去噪的典型用途包括从音频数据中去除噪声和锐化模糊图像。去噪算法可以使用多种方法构建,从高斯和中值滤波器到自编码器。

虽然去噪的概念主要与涉及非结构化数据(如音频、图像)的用例相关联,但结构化表格数据的填充是一个紧密相关的概念。有许多方法可以替换(或填充)表格数据中的缺失值。例如,可以简单地将数据替换为零(或在给定上下文中的等效值),或者对于数值数据,可以用相应行或列的某个统计量(如均值、中位数、众数、最小值、最大值)来替换数据 — 但这样做可能会扭曲数据,并且如果将其用作ML训练工作流程的预处理步骤,这种简单填充可能会对预测性能产生不利影响。其他方法如K最近邻(KNN)或关联规则挖掘可能表现更好,但由于它们没有训练的概念,直接在测试数据上工作,所以当测试数据的大小变大时,它们在速度上可能会遇到困难;这对于需要快速在线推断的用例尤其成问题。

现在,我们可以简单地训练一个ML模型,将具有缺失值的特征设置为输出,将其余特征作为预测器(或输入)。如果我们有几个具有缺失值的特征,为每个特征构建单输出模型可能会很麻烦,更不用说昂贵了,因此我们可以尝试构建一个多输出模型,一次预测所有受影响特征的缺失值。关键是,如果缺失值可以被视为噪声,那么我们可能能够应用去噪的概念来填充表格数据 — 这是我们接下来将建立的关键见解。

多输出机器学习算法

顾名思义,多输出(或多目标)算法可以用于同时训练模型以预测多个输出/目标特征。Scikit-learn网站提供了一个关于多输出分类和回归的很好的概述(请参阅此处)。

虽然一些机器学习算法可以直接进行多输出建模,但其他算法可能仅支持单输出建模。诸如Scikit-learn等库提供了使用包装器的方式,通过提供实现了常用函数(如fit和predict)的包装器,在底层独立地应用这些函数到单输出模型上。以下示例代码显示了如何使用Scikit-learn中的MultiOutputRegressor包装器将本身仅支持单输出建模的线性支持向量回归(Linear SVR)的实现进行包装,以实现多输出回归。

from sklearn.datasets import make_regressionfrom sklearn.svm import LinearSVRfrom sklearn.multioutput import MultiOutputRegressor# 构造一个玩具数据集RANDOM_STATE = 100xs, ys = make_regression(    n_samples=2000, n_features=7, n_informative=5,     n_targets=3, random_state=RANDOM_STATE, noise=0.2)# 使用MultiOutputRegressor包装线性SVR以实现多输出建模wrapped_model = MultiOutputRegressor(    LinearSVR(random_state=RANDOM_STATE)).fit(xs, ys)

虽然这种包装策略至少让我们能够在多输出场景中使用单输出算法,但它可能没有考虑输出特征之间的相关性或依赖关系(即,预测的输出特征集是否作为一个整体是有意义的)。相比之下,一些本身支持多输出建模的机器学习算法似乎考虑了输出之间的相互关系。例如,当使用Scikit-learn中的决策树来基于某些输入数据对n个输出进行建模时,所有n个输出值都存储在叶节点中,并使用考虑所有n个输出值作为一个集合的分割标准,例如通过对它们进行平均值计算(请参见此处)。下面的示例代码展示了如何构建一个多输出决策树回归器 – 你会注意到,表面上,这些步骤与之前用于训练线性SVR的包装器非常相似。

from sklearn.datasets import make_regression
from sklearn.tree import DecisionTreeRegressor
# 构造一个玩具数据集
RANDOM_STATE = 100
xs, ys = make_regression(
    n_samples=2000, n_features=7, n_informative=5,
    n_targets=3, random_state=RANDOM_STATE, noise=0.2)
# 直接使用决策树训练一个多输出模型
model = DecisionTreeRegressor(random_state=RANDOM_STATE).fit(xs, ys)

训练多输出机器学习模型作为表格数据修复器

现在我们已经介绍了去噪、填充和多输出机器学习算法的基础知识,我们可以将所有这些构建块结合起来。一般来说,使用去噪来训练多输出机器学习模型来填充表格数据的步骤如下所述。注意,与上一节中的代码示例不同,我们在接下来的内容中不会明确区分预测变量和目标变量 – 这是因为在表格数据填充的情况下,如果特征在数据中存在,则可以将其作为预测变量,如果特征缺失,则可以将其作为目标变量。

步骤1:创建训练集和验证集

将数据分割为训练集和验证集,例如使用80:20的比例划分。我们将分别称这些集合为df_training和df_validation。

步骤2:创建训练集和验证集的噪声/掩码副本

复制df_training和df_validation,并给这些副本的数据添加噪声,例如通过随机掩码值。我们将分别称这些掩码副本为df_training_masked和df_validation_masked。掩码函数的选择可能会对最终训练的填充模型的预测准确性产生影响,因此我们将在下一节中介绍一些掩码策略。另外,如果df_training的大小很小,那么增加一些倍数k的行数可能是有意义的,这样如果df_training有n行和m列,那么增加后的df_training_masked数据集将有n*k行(和之前的m列)。

步骤3:训练一个多输出模型作为基于去噪的填充器

选择一个您喜欢的多输出算法,并训练一个模型,使用带有噪声/掩码的副本预测原始训练数据。从概念上讲,您可以执行类似于model.fit(predictors = df_training_masked, targets = df_training)的操作。

步骤4:将填充器应用于掩码验证数据集

将df_validation_masked传递给训练好的模型以预测df_validation。从概念上讲,这将类似于df_validation_imputed = model.predict(df_validation_masked)。请注意,一些拟合函数可能直接接受验证数据集作为参数,在拟合过程中计算验证误差(例如,对于TensorFlow中的神经网络) – 如果是这样的话,请记住在计算验证误差时,使用带有噪声/掩码的验证集(df_validation_masked)作为预测变量,使用原始验证集(df_validation)作为目标变量。

步骤5:评估验证数据集的填充准确性

通过将df_validation_imputed(模型预测的结果)与df_validation(实际值)进行比较,评估填充准确性。可以按列进行评估(以确定特征的填充准确性)或按行进行评估(以检查预测实例的准确性)。为了避免每列获得过高的准确性结果,可以在计算准确性之前过滤掉在df_validation_masked中未掩码的待预测列的行。

最后,尝试上述步骤来优化模型(例如,使用另一种掩码策略或选择不同的多输出机器学习算法)。

下面的代码展示了一个玩具示例,演示了如何实现步骤1-5。

import pandas as pd
import numpy as np
from sklearn.datasets import make_classification
from sklearn.tree import DecisionTreeClassifier

# 构造玩具数据集
RANDOM_STATE = 100
data = make_classification(n_samples=2000, n_features=7, n_classes=1, random_state=RANDOM_STATE, class_sep=2, n_informative=3)
df = pd.DataFrame(data[0]).applymap(lambda x: int(abs(x)))

###### 第1步:创建训练集和验证集#####
TRAIN_TEST_SPLIT_FRAC = 0.8
n = int(df.shape[0]*TRAIN_TEST_SPLIT_FRAC)
df_training, df_validation = df.iloc[:n, :], df.iloc[n:, :].reset_index(drop=True)

###### 第2步:创建训练集和验证集的带噪声/掩码副本#####
# 随机掩码的示例,其中掩码值的决策被视为硬币抛掷(伯努利事件)
def random_masking(value): 
    return -1 if np.random.binomial(n=1, p=0.5) else value

df_training_masked = df_training.applymap(random_masking)
df_validation_masked = df_validation.applymap(random_masking)

###### 第3步:训练一个多输出模型,用作去噪补全的方法######
# 注意,使用掩码数据来建模原始数据
model = DecisionTreeClassifier(random_state=RANDOM_STATE).fit(X=df_training_masked, y=df_training)

###### 第4步:将补全器应用于掩码验证数据集#####
df_validation_imputed = pd.DataFrame(model.predict(df_validation_masked))

###### 第5步:在验证数据集上评估补全准确性######
# 检查基本的top-1准确度指标,考虑到结果膨胀
feature_accuracy_dict = {}
for i in range(df_validation_masked.shape[1]):
    # 获取特征i被掩码(需要补全)的行索引列表
    masked_indexes = df_validation_masked.index[df_validation_masked[i] == -1]
    # 仅针对特征i的这些行计算补全准确度
    feature_accuracy_dict[i] = (df_validation_imputed.iloc[masked_indexes, i] == df_validation.iloc[masked_indexes, i]).mean()

print(feature_accuracy_dict)

数据掩码策略

一般来说,可以采用几种策略来对训练和验证数据进行掩码。在高层次上,我们可以区分三种掩码策略:穷举、随机和基于领域的。

穷举掩码

这种策略涉及为数据集中的每一行生成所有可能的掩码组合。假设我们有一个包含n行和m列的数据集。那么穷举掩码将会将每一行扩展为最多2^m行,每一行的m个值的掩码组合;对于该行的掩码组合的最大总数等于Pascal三角形中第m行的和,尽管我们可以选择省略一些在给定用例下无用的组合(例如,所有值都被掩码的组合)。因此,最终的掩码数据集最多会有n*(2^m)行和m列。虽然穷举策略的好处是非常全面,但在m很大的情况下可能不太实用,因为所得到的掩码数据集对于大多数计算机来说可能太大难以处理。例如,如果原始数据集只有1000行和50列,穷举掩码数据集将会有大约10¹⁸行(也就是一万亿亿行)。

随机掩码

顾名思义,这种策略是通过使用某个随机函数来掩码值。在简单的实现中,例如,对于数据集中的每个值,决定是否对其进行掩码可以被看作是独立的伯努利事件,掩码的概率为p。随机掩码策略的明显好处是,与穷举掩码不同,掩码数据的大小是可管理的。然而,特别是对于小数据集,为了实现足够高的补全准确度,可能需要在应用随机掩码之前对训练数据集的行进行上采样,以便反映在得到的掩码数据集中的更多掩码组合。

基于领域的掩码

这种策略旨在以逼近现实生活中缺失值的模式的方式应用掩码,即在补全器将被应用的领域或用例内。为了发现这些模式,分析定量的观察数据以及结合领域专家的见解可能是有用的。

实际应用

本文讨论的基于去噪的填充器在实践中可以提供一种实用的“中间途径”,在其他方法可能过于简单或过于复杂和资源密集的情况下。除了作为较大机器学习工作流程中的数据清理的预处理步骤之外,基于去噪的表格数据填充还可以在某些实际用例中用于驱动核心产品功能。

行业中的在线表单辅助填写就是一个例子。随着各种业务流程的数字化增加,纸质表格正在被数字化的在线版本所取代。提交工作申请、创建采购申请、企业差旅预订和注册活动通常涉及填写某种在线表单。手动完成这样的表单可能是乏味、耗时且潜在易错的,特别是如果表单有多个需要填写的字段。然而,通过AI助手的帮助,完成这样一个在线表单的任务可以变得更加容易、快速和准确,通过根据可用的上下文信息为用户提供输入建议。例如,当用户开始填写表单上的某些字段时,AI助手可以推断出剩余字段的最可能值,并实时向用户提供这些建议。这样的用例可以很容易地看作是一个基于去噪的多输出填充问题,其中噪声/掩码数据由表单的当前状态给出(其中一些字段已填写,其他字段为空/缺失),目标是预测缺失的字段。可以根据需要调整模型以满足各种用例要求,包括预测准确性和端到端响应时间(用户感知)。

在生成AI和基础模型时的相关性

随着生成AI和基础模型的最新进展以及自2022年ChatGPT的出现后,即使在非技术人员中也越来越意识到它们的潜力,可以合理地问去噪式填充器在未来将会有什么相关性。例如,大型语言模型(LLM)可以处理表格数据的填充任务。毕竟,在训练BERT等LLM时,预测句子中缺失的令牌是一个典型的学习目标。

然而,在生成AI和基础模型时,去噪式填充器或其他现今存在的更简单的表格数据填充方法不太可能很快过时。这一点可以从2010年代后期的情况中得到体会,到那时,神经网络已经成为技术上更可行和经济上更可行的选项,适用于之前依赖更简单算法如逻辑回归、决策树和随机森林的几个用例。虽然神经网络确实取代了这些其他算法用于一些高端用例,其中有足够大的训练数据可用并且训练和维护神经网络的成本被视为合理,但许多其他用例保持不变。事实上,促使神经网络采用的存储和计算资源变得更加便宜和易得,也使得其他更简单的算法受益。从这个角度来看,成本、复杂性、可解释性的需求、实时用例的快速响应时间以及对于预训练模型的潜在寡头供应商锁定的威胁等考虑因素,似乎都指向了这样一个未来:在生成AI和基础模型中,去噪式表格数据填充等务实的创新将与它们有意义地共存,而不是被它们所取代。