是否可以通过机器学习学习和预测 NaN 值?

Is it possible to learn from and predict NaN-values with machine learning?

我正在尝试解决具有两个输出值的回归问题。输出值充当传入预订值的两个不同阈值,以接受或拒绝预订。

这两个输出值是在业务案例中手动设置的,但这应借助机器学习自动完成。在业务案例中,其中一个输出值可以是 Nan,那么所有预订都将接受此标准。因此,如果一个输出值未填充,则它对业务案例有效。

示例:

X_train = np.array([(1,1),(2,2),(3,3),(4,4)])
Y_train =np.array([(1,1),(2,2),(3,3),(4,np.nan)])
X_test = np.array([(5,5),(6,6),(7,7)])
Y_test = np.array([(5,5),(6,np.nan),(7,7)])

reg  = MLPRegressor()
reg = reg.fit(X_train,Y_train)

我的问题是当我为输出设置 NaN 值时,例如 scikit-learn 会抛出错误 Y_train/Y_test。

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

我不想用均值或 0 来估算这些值,因为如上所述,缺失值是业务案例的有效设置。

是否可以使用 scikit-learn 或一般机器学习来解决此类问题?

编辑:不是由业务设置的输出值不直接存储为 NaN 而是存储为 -9999999999 无穷大。我用 NaN 替换了这些值,因为我认为如此高的值会扭曲结果。所以如果我不替换任何东西,变量实际上会导致以下结果:

X_train = np.array([(1,1),(2,2),(3,3),(4,4)])
Y_train =np.array([(1,1),(2,2),(3,3),(4,-9999999999)])
X_test = np.array([(5,5),(6,6),(7,7)])
Y_test = np.array([(5,5),(6,-9999999999),(7,7)])

是保留这​​些值比保留 NaN 更好,还是它们会扭曲结果而必须被忽略?

训练数据的全部意义在于监督模型,教它预测具有一组特征的输出。因此,将 nan 值作为训练 X, y 的一部分是没有意义的。一个模型不会 'fill in the gaps' 并且仍然在学习。 T

他的标准方法是使用缺失值技术,例如 - 通过 mean/0 估算,使用 KNN 通过检测包含缺失数据的样本的最近邻居来替换值,顺序数据的估算技术(线性,akima , quadratic, spline etc) 或可以处理缺失数据的编码方法。

如果您不想使用缺失值处理策略,则不应将该行保留为训练数据集的一部分。

Is it possible to solve such a problem with scikit-learn or with machine learning in general?

是的,正如我提到的,有一个完整的研究领域可以用来解决这个问题(KNN 是处理这个问题的最流行和最容易获得的机器学习方法)。此 article 可能会帮助您提供更多指导。


编辑(基于 OP 编辑​​)

将 99999999 值替换为 Nan 是正确的方法,因为我们不知道为什么业务将它们设置为该值。很可能是丢失了数据,他们将这些数据归为垃圾值,以便能够将数据存储在数据库中而不会出现太多问题。其次,将它们视为 Nan 值而不是异常值会更明智。因此,出于监督培训的目的,我建议删除具有这些值的行。

另一件事是我注意到这些值是 Y 训练和 Y 测试的一部分。如果 Nans 仅在 Y 数据中,这会使事情变得更容易,因为您可以简单地将这些行保留为数据的一部分以进行预测。在 non-nan 数据上训练模型,并使用该模型预测行的 Y 值以替换 Nan 值。

但是,如果您认为这些是极值并且应该被视为异常值,您仍然必须将它们从模型训练中删除,因为它们会使模型结果产生疯狂的偏差。

最后,如果这是一个 class 化练习(不是回归)那么你实际上可以将 999999 视为一个单独的 class 并像其他任何 classes 一样预测它.这不适用于回归,因为在回归中 999999 是将要进行预测的连续尺度的一部分。

即使您的模型可以在输出时生成 NaN,也无法判断这是错误还是实际估计。我不会在训练集中使用 NaN。

不仅因为 NaN 不能用任何数值数据类型表示,而且因为无法对 NaN 执行算术运算:这意味着您无法计算它的梯度,无法计算直线或与其相交的坡度。简而言之,您的模型无法将其学习为数值,因为它不是数字。

也许将您的问题分成两个任务是一个可以接受的解决方案。一个用于回归和分类,无论是否提供数据。

X_train = np.array([(1,1),(2,2),(3,3),(4,4)])
Y1_train = np.array([(1,1),(2,2),(3,3),(4,4)])
Y2_train = np.array([(1,1),(1,1),(1,1),(1,0)])

X_test = np.array([(5,5),(6,6),(7,7)])
Y1_test = np.array([(5,5),(6,6),(7,7)])
Y2_test = np.array([(1,1),(1,0),(1,1)])

对于回归,做与 X_train 和 Y1_train 对一样的操作。

分类部分的示例代码

from sklearn.neural_network import MLPClassifier
clf = MLPClassifier()
clf.fit(X_train, Y2_train)