Machine-Learning-Mastery-数据准备教程-五-

192 阅读1小时+

Machine Learning Mastery 数据准备教程(五)

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

如何在 Sklearn 中保存和重用数据准备对象

原文:machinelearningmastery.com/how-to-save…

最后更新于 2020 年 6 月 30 日

将来,在训练数据集上执行的任何数据准备都必须在新的数据集上执行,这一点至关重要。

这可能包括评估模型时的测试数据集,或者使用模型进行预测时来自域的新数据。

通常,训练数据集中的模型拟合被保存以备后用。将来为模型准备新数据的正确解决方案是将任何数据准备对象(如数据缩放方法)与模型一起保存到文件中。

在本教程中,您将了解如何将模型和数据准备对象保存到文件中供以后使用。

完成本教程后,您将知道:

  • 为机器学习模型正确准备测试数据和新数据的挑战。
  • 将模型和数据准备对象保存到文件中以备后用的解决方案。
  • 如何在新数据上保存和后期加载并使用机器学习模型和数据准备模型。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

  • 2020 年 1 月更新:针对 Sklearn v0.22 API 的变化进行了更新。
  • 2020 年 5 月更新:改进代码示例,打印输出。

How to Save and Load Models and Data Preparation in Sklearn for Later Use

如何在 Scikit 中保存和加载模型和数据准备-学习以备后用 图片由 Dennis Jarvis 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 为模型准备新数据的挑战
  2. 保存数据准备对象
  3. 如何保存和以后使用数据准备对象

为模型准备新数据的挑战

数据集中的每个输入变量可能有不同的单位。

例如,一个变量可能以英寸为单位,另一个以英里为单位,另一个以天为单位,等等。

因此,在拟合模型之前缩放数据通常很重要。

这对于使用输入或距离度量的加权和的模型尤其重要,如逻辑回归、神经网络和 k 近邻。这是因为具有较大值或范围的变量可能会支配或抵消具有较小值或范围的变量的影响。

缩放技术,如标准化或规范化,具有将每个输入变量的分布转换为相同的效果,如标准化情况下的相同最小值和最大值,或标准化情况下的相同平均值和标准偏差。

缩放技术必须适合,这意味着它只需要从数据中计算系数,例如观察到的最小值和最大值,或者观察到的平均值和标准偏差。这些值也可以由领域专家设置。

在使用缩放技术评估模型时,最佳实践是将模型拟合到训练数据集中,然后将它们应用到训练和测试数据集中。

或者,在使用最终模型时,在训练数据集上调整缩放方法,并将转换应用于训练数据集和将来的任何新数据集。

应用于训练数据集的任何数据准备或转换在将来也应用于测试或其他数据集是至关重要的。

当所有的数据和模型都在内存中时,这很简单。

当模型被保存并在以后使用时,这是一个挑战。

保存拟合模型供以后使用(如最终模型)时,缩放数据的最佳做法是什么?

保存数据准备对象

解决方案是将数据准备对象与模型一起保存到文件中。

例如,通常使用 pickle 框架(内置于 Python 中)来保存机器学习模型供以后使用,例如保存最终模型。

这个相同的框架可以用来保存用于数据准备的对象。

之后,可以加载和使用模型和数据准备对象。

将整个对象保存到文件中很方便,例如模型对象和数据准备对象。然而,专家可能更喜欢只将模型参数保存到文件中,然后稍后加载它们,并将它们设置到新的模型对象中。这种方法也可以用于缩放数据的系数,例如每个变量的最小值和最大值,或者每个变量的平均值和标准偏差。

选择哪种方法适合您的项目由您决定,但我建议将模型和数据准备对象(或多个对象)直接保存到文件中以备后用。

为了使将对象和数据转换对象保存到文件的想法具体化,让我们看一个工作示例。

如何保存和以后使用数据准备对象

在本节中,我们将演示准备数据集、在数据集上拟合模型、将模型和数据转换对象保存到文件中,以及稍后加载模型和转换并在新数据上使用它们。

1.定义数据集

首先,我们需要一个数据集。

我们将使用 Sklearn 数据集的测试数据集,特别是一个二分类问题,通过 make_blobs()函数随机创建两个输入变量。

下面的示例创建了一个包含 100 个示例、两个输入要素和两个类标签(0 和 1)的测试数据集。然后将数据集分成训练集和测试集,并报告每个变量的最小值和最大值。

重要的是, random_state 是在创建数据集和拆分数据时设置的,这样每次运行代码时都会创建相同的数据集并执行相同的数据拆分。

# example of creating a test dataset and splitting it into train and test sets
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
# prepare dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the scale of each input variable
for i in range(X_test.shape[1]):
	print('>%d, train: min=%.3f, max=%.3f, test: min=%.3f, max=%.3f' %
		(i, X_train[:, i].min(), X_train[:, i].max(),
			X_test[:, i].min(), X_test[:, i].max()))

运行该示例会报告训练和测试数据集中每个变量的最小值和最大值。

我们可以看到,每个变量都有不同的尺度,并且训练数据集和测试数据集之间的尺度不同。这是一个现实的场景,我们可能会遇到真实的数据集。

>0, train: min=-11.856, max=0.526, test: min=-11.270, max=0.085
>1, train: min=-6.388, max=6.507, test: min=-5.581, max=5.926

2.缩放数据集

接下来,我们可以缩放数据集。

我们将使用最小最大缩放器将每个输入变量缩放到范围[0,1]。使用此定标器的最佳实践是将其放在训练数据集上,然后将转换应用于训练数据集和其他数据集:在本例中是测试数据集。

下面列出了缩放数据和总结效果的完整示例。

# example of scaling the dataset
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
# prepare dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# define scaler
scaler = MinMaxScaler()
# fit scaler on the training dataset
scaler.fit(X_train)
# transform both datasets
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# summarize the scale of each input variable
for i in range(X_test.shape[1]):
	print('>%d, train: min=%.3f, max=%.3f, test: min=%.3f, max=%.3f' %
		(i, X_train_scaled[:, i].min(), X_train_scaled[:, i].max(),
			X_test_scaled[:, i].min(), X_test_scaled[:, i].max()))

运行该示例将打印缩放数据的效果,显示训练和测试数据集中每个变量的最小值和最大值。

我们可以看到,两个数据集中的所有变量现在的值都在 0 到 1 的期望范围内。

>0, train: min=0.000, max=1.000, test: min=0.047, max=0.964
>1, train: min=0.000, max=1.000, test: min=0.063, max=0.955

3.保存模型和数据缩放器

接下来,我们可以在训练数据集上拟合模型,并将模型和缩放器对象保存到文件中。

我们将使用物流配送模型,因为这个问题是一个简单的二分类任务。

训练数据集像以前一样缩放,在这种情况下,我们将假设测试数据集当前不可用。缩放后,数据集用于拟合逻辑回归模型。

我们将使用 pickle 框架将后勤导出模型保存到一个文件中,并将最小最大缩放器保存到另一个文件中。

下面列出了完整的示例。

# example of fitting a model on the scaled dataset
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression
from pickle import dump
# prepare dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# split data into train and test sets
X_train, _, y_train, _ = train_test_split(X, y, test_size=0.33, random_state=1)
# define scaler
scaler = MinMaxScaler()
# fit scaler on the training dataset
scaler.fit(X_train)
# transform the training dataset
X_train_scaled = scaler.transform(X_train)
# define model
model = LogisticRegression(solver='lbfgs')
model.fit(X_train_scaled, y_train)
# save the model
dump(model, open('model.pkl', 'wb'))
# save the scaler
dump(scaler, open('scaler.pkl', 'wb'))

运行该示例会缩放数据,拟合模型,并使用 pickle 将模型和缩放器保存到文件中。

您当前的工作目录中应该有两个文件:

  • 型号
  • scaler . PK

4.负载模型和数据缩放器

最后,我们可以加载模型和缩放器对象并使用它们。

在这种情况下,我们将假设训练数据集不可用,并且只有新数据或测试数据集可用。

我们将加载模型和定标器,然后使用定标器准备新数据并使用模型进行预测。因为它是一个测试数据集,所以我们有预期的目标值,所以我们将把预测与预期的目标值进行比较,并计算模型的准确性。

下面列出了完整的示例。

# load model and scaler and make predictions on new data
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from pickle import load
# prepare dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# split data into train and test sets
_, X_test, _, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# load the model
model = load(open('model.pkl', 'rb'))
# load the scaler
scaler = load(open('scaler.pkl', 'rb'))
# check scale of the test set before scaling
print('Raw test set range')
for i in range(X_test.shape[1]):
	print('>%d, min=%.3f, max=%.3f' % (i, X_test[:, i].min(), X_test[:, i].max()))
# transform the test dataset
X_test_scaled = scaler.transform(X_test)
print('Scaled test set range')
for i in range(X_test_scaled.shape[1]):
	print('>%d, min=%.3f, max=%.3f' % (i, X_test_scaled[:, i].min(), X_test_scaled[:, i].max()))
# make predictions on the test set
yhat = model.predict(X_test_scaled)
# evaluate accuracy
acc = accuracy_score(y_test, yhat)
print('Test Accuracy:', acc)

运行该示例加载模型和定标器,然后使用定标器为模型正确准备测试数据集,满足模型在训练时的期望。

为了确认缩放器具有所需的效果,我们报告了应用缩放之前和之后每个输入特征的最小值和最大值。然后,该模型对测试集中的示例进行预测,并计算分类准确率。

在这种情况下,正如预期的那样,数据集正确地规范化了模型,在测试集上实现了 100%的准确性,因为测试问题微不足道。

Raw test set range
>0, min=-11.270, max=0.085
>1, min=-5.581, max=5.926

Scaled test set range
>0, min=0.047, max=0.964
>1, min=0.063, max=0.955

Test Accuracy: 1.0

这提供了一个模板,您可以使用它将模型和缩放器对象(或多个对象)保存到自己的项目中。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

邮件

蜜蜂

摘要

在本教程中,您发现了如何将模型和数据准备对象保存到文件中供以后使用。

具体来说,您了解到:

  • 为机器学习模型正确准备测试数据和新数据的挑战。
  • 将模型和数据准备对象保存到文件中以备后用的解决方案。
  • 如何在新数据上保存和后期加载并使用机器学习模型和数据准备模型。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

如何在 Python 中转换回归的目标变量

原文:machinelearningmastery.com/how-to-tran…

最后更新于 2020 年 10 月 1 日

数据准备是应用机器学习的一大部分。

正确准备您的训练数据可能意味着平庸和非凡的结果之间的区别,即使使用非常简单的线性算法。

对于输入变量来说,执行数据准备操作(如缩放)相对简单,并且已经通过 Pipeline Sklearn 类在 Python 中成为常规操作。

在必须预测数值的回归预测建模问题上,对目标变量进行缩放和执行其他数据转换也很关键。这可以在 Python 中使用transformed targetgressor类来实现。

在本教程中,您将发现如何使用 TransformedTargetRegressor 来使用 Sklearn Python 机器学习库缩放和转换回归的目标变量。

完成本教程后,您将知道:

  • 缩放输入和目标数据对机器学习的重要性。
  • 将数据转换应用于目标变量的两种方法。
  • 如何在真实回归数据集上使用 TransformedTargetRegressor。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

How to Transform Target Variables for Regression With Sklearn

如何用 Scikit 转换回归的目标变量-学习 图片由唐·海尼斯提供,版权所有。

教程概述

本教程分为三个部分;它们是:

  1. 数据缩放的重要性
  2. 如何缩放目标变量
  3. 使用 TransformedTargetRegressor 的示例

数据缩放的重要性

在不同变量之间,数值范围不同的数据是很常见的。

例如,一个变量可能以英尺为单位,另一个以米为单位,等等。

如果所有变量都缩放到相同的范围,一些机器学习算法的表现会好得多,例如将所有变量缩放到 0 到 1 之间的值,称为归一化。

这影响了使用输入加权和的算法,如线性模型和神经网络,以及使用距离度量的模型,如支持向量机和 k 近邻。

因此,缩放输入数据是一种很好的做法,甚至可以尝试其他数据变换,例如使用幂变换使数据更正常(更好地符合高斯概率分布)。

这也适用于称为目标变量的输出变量,例如在建模回归预测建模问题时预测的数值。

对于回归问题,通常需要缩放或转换输入和目标变量。

缩放输入变量很简单。在 Sklearn 中,您可以手动使用缩放对象,或者使用更方便的 Pipeline,它允许您在使用模型之前将一系列数据转换对象链接在一起。

管道将为您拟合训练数据上的比例对象,并将变换应用于新数据,例如当使用模型进行预测时。

例如:

...
# prepare the model with input scaling
pipeline = Pipeline(steps=[('normalize', MinMaxScaler()), ('model', LinearRegression())])
# fit pipeline
pipeline.fit(train_x, train_y)
# make predictions
yhat = pipeline.predict(test_x)

挑战在于,Sklearn 中缩放目标变量的等效机制是什么?

如何缩放目标变量

有两种方法可以缩放目标变量。

第一种是手动管理转换,第二种是使用新的自动方式管理转换。

  1. 手动转换目标变量。
  2. 自动转换目标变量。

1.目标变量的手动转换

手动管理目标变量的缩放涉及手动创建缩放对象并将其应用于数据。

它包括以下步骤:

  1. 创建变换对象,例如最小最大缩放器。
  2. 在训练数据集上拟合变换。
  3. 将转换应用于训练和测试数据集。
  4. 反转任何预测的变换。

例如,如果我们想要规范化一个目标变量,我们将首先定义并训练一个最小最大缩放器对象:

...
# create target scaler object
target_scaler = MinMaxScaler()
target_scaler.fit(train_y)

然后,我们将转换列车并测试目标变量数据。

...
# transform target variables
train_y = target_scaler.transform(train_y)
test_y = target_scaler.transform(test_y)

然后我们将拟合我们的模型,并使用该模型进行预测。

在用误差度量来使用或评估预测之前,我们必须反转变换。

...
# invert transform on predictions
yhat = model.predict(test_X)
yhat = target_scaler.inverse_transform(yhat)

这是一个痛点,因为这意味着您不能使用 Sklearn 中的便利功能,如 cross_val_score() 来快速评估模型。

2.目标变量的自动转换

另一种方法是自动管理变换和逆变换。

这可以通过使用包装给定模型和缩放对象的transformed targetgressior对象来实现。

它将使用用于拟合模型的相同训练数据准备目标变量的变换,然后对调用 predict()时提供的任何新数据应用该逆变换,以正确的比例返回预测。

要使用 TransformedTargetRegressor,它是通过指定要在目标上使用的模型和转换对象来定义的;例如:

...
# define the target transform wrapper
wrapped_model = TransformedTargetRegressor(regressor=model, transformer=MinMaxScaler())

稍后,TransformedTargetRegressor 实例可以像任何其他模型一样通过调用 fit()函数进行拟合,并通过调用 predict()函数进行预测。

...
# use the target transform wrapper
wrapped_model.fit(train_X, train_y)
yhat = wrapped_model.predict(test_X)

这要容易得多,并且允许您使用像 cross_val_score() 这样的有用函数来评估模型

现在我们已经熟悉了 TransformedTargetRegressor,让我们看一个在真实数据集上使用它的例子。

使用 TransformedTargetRegressor 的示例

在本节中,我们将演示如何在真实数据集上使用 TransformedTargetRegressor。

我们将使用波士顿住房回归问题,该问题有 13 个输入和一个数字目标,需要学习郊区特征和房价之间的关系。

数据集可以从这里下载:

下载数据集,保存在当前工作目录下,名称为“ housing.csv ”。

在数据集中,您应该看到所有变量都是数字。

0.00632,18.00,2.310,0,0.5380,6.5750,65.20,4.0900,1,296.0,15.30,396.90,4.98,24.00
0.02731,0.00,7.070,0,0.4690,6.4210,78.90,4.9671,2,242.0,17.80,396.90,9.14,21.60
0.02729,0.00,7.070,0,0.4690,7.1850,61.10,4.9671,2,242.0,17.80,392.83,4.03,34.70
0.03237,0.00,2.180,0,0.4580,6.9980,45.80,6.0622,3,222.0,18.70,394.63,2.94,33.40
0.06905,0.00,2.180,0,0.4580,7.1470,54.20,6.0622,3,222.0,18.70,396.90,5.33,36.20
...

您可以在此了解有关此数据集和列含义的更多信息:

我们可以确认数据集可以作为 NumPy 数组正确加载,并将其拆分为输入和输出变量。

下面列出了完整的示例。

# load and summarize the dataset
from numpy import loadtxt
# load data
dataset = loadtxt('housing.csv', delimiter=",")
# split into inputs and outputs
X, y = dataset[:, :-1], dataset[:, -1]
# summarize dataset
print(X.shape, y.shape)

运行该示例会打印数据集输入和输出部分的形状,显示 13 个输入变量、一个输出变量和 506 行数据。

(506, 13) (506,)

我们现在可以准备一个使用 TransformedTargetRegressor 的例子。

预测该问题目标平均值的朴素回归模型可以达到约 6.659 的平均绝对误差 (MAE)。我们将力争做得更好。

在这个例子中,我们将拟合一个huberrelater对象,并使用一个管道来规范化输入变量。

...
# prepare the model with input scaling
pipeline = Pipeline(steps=[('normalize', MinMaxScaler()), ('model', HuberRegressor())])

接下来,我们将定义一个 TransformedTargetRegressor 实例,并将回归器设置为管道,将转换器设置为一个 MinMaxScaler 对象的实例。

...
# prepare the model with target scaling
model = TransformedTargetRegressor(regressor=pipeline, transformer=MinMaxScaler())

然后,我们可以使用 10 倍交叉验证对输入和输出变量进行标准化来评估模型。

...
# evaluate model
cv = KFold(n_splits=10, shuffle=True, random_state=1)
scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)

将这些结合在一起,完整的示例如下所示。

# example of normalizing input and output variables for regression.
from numpy import mean
from numpy import absolute
from numpy import loadtxt
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.pipeline import Pipeline
from sklearn.linear_model import HuberRegressor
from sklearn.preprocessing import MinMaxScaler
from sklearn.compose import TransformedTargetRegressor
# load data
dataset = loadtxt('housing.csv', delimiter=",")
# split into inputs and outputs
X, y = dataset[:, :-1], dataset[:, -1]
# prepare the model with input scaling
pipeline = Pipeline(steps=[('normalize', MinMaxScaler()), ('model', HuberRegressor())])
# prepare the model with target scaling
model = TransformedTargetRegressor(regressor=pipeline, transformer=MinMaxScaler())
# evaluate model
cv = KFold(n_splits=10, shuffle=True, random_state=1)
scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
# convert scores to positive
scores = absolute(scores)
# summarize the result
s_mean = mean(scores)
print('Mean MAE: %.3f' % (s_mean))

运行该示例使用输入和输出变量的规范化来评估模型。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们实现了大约 3.1 的 MAE,比实现了大约 6.6 的天真模型好得多。

Mean MAE: 3.191

我们不限于使用缩放对象;例如,我们还可以探索对目标变量使用其他数据变换,如 PowerTransformer ,可以使每个变量更像高斯(使用 Yeo-Johnson 变换)并提高线性模型的表现。

默认情况下,PowerTransformer 还会在执行转换后对每个变量进行标准化。

下面列出了在房屋数据集的输入和目标变量上使用电力变压器的完整示例。

# example of power transform input and output variables for regression.
from numpy import mean
from numpy import absolute
from numpy import loadtxt
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.pipeline import Pipeline
from sklearn.linear_model import HuberRegressor
from sklearn.preprocessing import PowerTransformer
from sklearn.compose import TransformedTargetRegressor
# load data
dataset = loadtxt('housing.csv', delimiter=",")
# split into inputs and outputs
X, y = dataset[:, :-1], dataset[:, -1]
# prepare the model with input scaling
pipeline = Pipeline(steps=[('power', PowerTransformer()), ('model', HuberRegressor())])
# prepare the model with target scaling
model = TransformedTargetRegressor(regressor=pipeline, transformer=PowerTransformer())
# evaluate model
cv = KFold(n_splits=10, shuffle=True, random_state=1)
scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
# convert scores to positive
scores = absolute(scores)
# summarize the result
s_mean = mean(scores)
print('Mean MAE: %.3f' % (s_mean))

运行该示例使用输入和输出变量的幂变换来评估模型。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们看到 MAE 进一步提高到大约 2.9。

Mean MAE: 2.926

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

应用程序接口

资料组

摘要

在本教程中,您发现了如何在 Sklearn 中使用 TransformedTargetRegressor 来缩放和转换回归的目标变量。

具体来说,您了解到:

  • 缩放输入和目标数据对机器学习的重要性。
  • 将数据转换应用于目标变量的两种方法。
  • 如何在真实回归数据集上使用 TransformedTargetRegressor。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

机器学习中缺失值的迭代插补

原文:machinelearningmastery.com/iterative-i…

最后更新于 2020 年 8 月 18 日

数据集可能会有缺失值,这可能会给许多机器学习算法带来问题。

因此,在对预测任务建模之前,识别并替换输入数据中每一列的缺失值是一种很好的做法。这被称为缺失数据插补,简称为插补。

一种复杂的方法包括定义一个模型来预测每个缺失的特征,作为所有其他特征的函数,并多次重复这个估计特征值的过程。该重复允许在预测缺失值的后续迭代中使用其他特征的精确估计值作为输入。这通常被称为迭代插补。

在本教程中,您将发现如何在机器学习中对缺失数据使用迭代插补策略。

完成本教程后,您将知道:

  • 缺少的值必须用 NaN 值标记,并且可以用迭代估计值替换。
  • 如何加载缺失值的 CSV 值并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
  • 在评估模型和拟合最终模型以对新数据进行预测时,如何使用迭代模型作为数据准备方法来估计缺失值。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

  • 更新 6 月/2020 :更改了示例中用于预测的列。

Iterative Imputation for Missing Values in Machine Learning

机器学习中缺失值的迭代插补 图片由 Gergely Csatari 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 迭代插补
  2. 马结肠数据集
  3. 用迭代插补器进行迭代插补
    1. 迭代输入数据转换
    2. 迭代估计器和模型评估
    3. 迭代插补器和不同的插补顺序
    4. 迭代估计器和不同的迭代次数
    5. 进行预测时的迭代估计变换

迭代插补

数据集可能缺少值。

这些数据行中的一个或多个值或列不存在。这些值可能完全丢失,或者用特殊字符或值标记,如问号“?”。

由于许多原因,这些值可能会丢失,通常是特定于问题域的,并且可能包括损坏的测量或不可用等原因。

大多数机器学习算法需要数字输入值,并且数据集中的每一行和每一列都需要一个值。因此,缺失值会给机器学习算法带来问题。

因此,识别数据集中缺失的值并用数值替换它们是很常见的。这被称为数据插补,或缺失数据插补。

一种估计缺失值的方法是使用迭代估计模型

迭代插补是指将每个特征建模为其他特征的函数的过程,例如预测缺失值的回归问题。每个特征都是按顺序估计的,一个接一个,允许先前的估计值在预测后续特征时用作模型的一部分。

它是迭代的,因为这个过程被重复多次,允许随着所有特征的缺失值被估计,缺失值的改进估计被计算。

这种方法通常被称为完全条件规范(FCS)或链式方程多元插补(MICE)。

如果多元分布是对数据的合理描述,这种方法是有吸引力的。FCS 通过一组条件密度在逐个变量的基础上指定多元插补模型,每个不完全变量一个条件密度。从初始插补开始,FCS 通过迭代条件密度绘制插补。少量的迭代(比如 10-20 次)通常就足够了。

——小鼠:R 中链式方程的多元插补,2009。

可以使用不同的回归算法来估计每个特征的缺失值,尽管为了简单起见,通常使用线性方法。过程的迭代次数通常保持很少,例如 10 次。最后,可以考虑按顺序处理特征的顺序,例如从缺失值最少的特征到缺失值最多的特征。

现在我们已经熟悉了缺失值插补的迭代方法,让我们来看看一个缺失值的数据集。

马结肠数据集

马绞痛数据集描述了患有绞痛的马的医学特征以及它们是活的还是死的。

有 300 行 26 个输入变量和一个输出变量。这是一个二分类预测任务,包括预测 1 如果马活了,2 如果马死了。

在这个数据集中,我们可以选择许多字段进行预测。在这种情况下,我们将预测问题是否是外科手术(列索引 23),使其成为二分类问题。

数据集的许多列都有许多缺失值,其中每个缺失值都用问号字符(“?”).

下面提供了数据集中带有标记缺失值的行的示例。

2,1,530101,38.50,66,28,3,3,?,2,5,4,4,?,?,?,3,5,45.00,8.40,?,?,2,2,11300,00000,00000,2
1,1,534817,39.2,88,20,?,?,4,1,3,4,2,?,?,?,4,2,50,85,2,2,3,2,02208,00000,00000,2
2,1,530334,38.30,40,24,1,1,3,1,3,3,1,?,?,?,1,1,33.00,6.70,?,?,1,2,00000,00000,00000,1
1,9,5290409,39.10,164,84,4,1,6,2,2,4,4,1,2,5.00,3,?,48.00,7.20,3,5.30,2,1,02208,00000,00000,1
...

您可以在此了解有关数据集的更多信息:

不需要下载数据集,因为我们将在工作示例中自动下载它。

使用 Python 在加载的数据集中用 NaN(而不是数字)值标记缺失值是最佳实践。

我们可以使用 read_csv() Pandas 函数加载数据集,并指定“na_values”来加载“?”的值作为缺失,用 NaN 值标记。

...
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')

加载后,我们可以查看加载的数据以确认“?”值被标记为 NaN。

...
# summarize the first few rows
print(dataframe.head())

然后,我们可以枚举每一列,并报告该列缺少值的行数。

...
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
	# count number of rows with missing values
	n_miss = dataframe[[i]].isnull().sum()
	perc = n_miss / dataframe.shape[0] * 100
	print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))

将这些联系在一起,下面列出了加载和汇总数据集的完整示例。

# summarize the horse colic dataset
from pandas import read_csv
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# summarize the first few rows
print(dataframe.head())
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
	# count number of rows with missing values
	n_miss = dataframe[[i]].isnull().sum()
	perc = n_miss / dataframe.shape[0] * 100
	print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))

运行该示例首先加载数据集并汇总前五行。

我们可以看到,被标记为“?”的缺失值字符已被 NaN 值替换。

    0   1        2     3      4     5    6   ...   21   22  23     24  25  26  27
0  2.0   1   530101  38.5   66.0  28.0  3.0  ...  NaN  2.0   2  11300   0   0   2
1  1.0   1   534817  39.2   88.0  20.0  NaN  ...  2.0  3.0   2   2208   0   0   2
2  2.0   1   530334  38.3   40.0  24.0  1.0  ...  NaN  1.0   2      0   0   0   1
3  1.0   9  5290409  39.1  164.0  84.0  4.0  ...  5.3  2.0   1   2208   0   0   1
4  2.0   1   530255  37.3  104.0  35.0  NaN  ...  NaN  2.0   2   4300   0   0   2

[5 rows x 28 columns]

接下来,我们可以看到数据集中所有列的列表以及缺失值的数量和百分比。

我们可以看到,一些列(例如列索引 1 和 2)没有缺失值,而其他列(例如列索引 15 和 21)有许多甚至大部分缺失值。

> 0, Missing: 1 (0.3%)
> 1, Missing: 0 (0.0%)
> 2, Missing: 0 (0.0%)
> 3, Missing: 60 (20.0%)
> 4, Missing: 24 (8.0%)
> 5, Missing: 58 (19.3%)
> 6, Missing: 56 (18.7%)
> 7, Missing: 69 (23.0%)
> 8, Missing: 47 (15.7%)
> 9, Missing: 32 (10.7%)
> 10, Missing: 55 (18.3%)
> 11, Missing: 44 (14.7%)
> 12, Missing: 56 (18.7%)
> 13, Missing: 104 (34.7%)
> 14, Missing: 106 (35.3%)
> 15, Missing: 247 (82.3%)
> 16, Missing: 102 (34.0%)
> 17, Missing: 118 (39.3%)
> 18, Missing: 29 (9.7%)
> 19, Missing: 33 (11.0%)
> 20, Missing: 165 (55.0%)
> 21, Missing: 198 (66.0%)
> 22, Missing: 1 (0.3%)
> 23, Missing: 0 (0.0%)
> 24, Missing: 0 (0.0%)
> 25, Missing: 0 (0.0%)
> 26, Missing: 0 (0.0%)
> 27, Missing: 0 (0.0%)

现在我们已经熟悉了丢失值的马绞痛数据集,让我们看看如何使用迭代插补。

用迭代插补器进行迭代插补

Sklearn 机器学习库提供了支持迭代插补的迭代插补器类

在本节中,我们将探讨如何有效地使用迭代器类。

迭代输入数据转换

这是一种数据转换,首先根据用于估计缺失值的方法进行配置。默认情况下,使用贝叶斯岭模型,该模型使用所有其他输入特征的函数。要素以升序填充,从缺失值最少的要素到缺失值最多的要素。

...
# define imputer
imputer = IterativeImputer(estimator=BayesianRidge(), n_nearest_features=None, imputation_order='ascending')

然后将估计值拟合到数据集上。

...
# fit on the dataset
imputer.fit(X)

然后将拟合估计值应用于数据集,以创建数据集的副本,用估计值替换每列的所有缺失值。

...
# transform the dataset
Xtrans = imputer.transform(X)

迭代器类不能直接使用,因为它是实验性的。

如果您尝试直接使用它,您将获得如下错误:

ImportError: cannot import name 'IterativeImputer'

相反,您必须添加额外的导入语句来添加对迭代器类的支持,如下所示:

...
from sklearn.experimental import enable_iterative_imputer

我们可以在 horse colic 数据集上演示它的用法,并通过总结转换前后数据集中缺失值的总数来确认它的工作。

下面列出了完整的示例。

# iterative imputation transform for the horse colic dataset
from numpy import isnan
from pandas import read_csv
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# print total missing
print('Missing: %d' % sum(isnan(X).flatten()))
# define imputer
imputer = IterativeImputer()
# fit on the dataset
imputer.fit(X)
# transform the dataset
Xtrans = imputer.transform(X)
# print total missing
print('Missing: %d' % sum(isnan(Xtrans).flatten()))

运行该示例首先加载数据集,并报告数据集中缺失值的总数为 1,605。

转换被配置、调整和执行,生成的新数据集没有缺失值,这证实了它是按照我们的预期执行的。

每个缺失的值都被替换为模型估计的值。

Missing: 1605
Missing: 0

迭代估计器和模型评估

使用 k 倍交叉验证在数据集上评估机器学习模型是一个很好的实践。

为了正确应用迭代缺失数据插补并避免数据泄漏,需要仅在训练数据集上计算每一列的模型,然后应用于数据集中每个折叠的训练集和测试集。

这可以通过创建建模管道来实现,其中第一步是迭代插补,然后第二步是模型。这可以使用管道类来实现。

例如,下面的管道使用带有默认策略的迭代估计器,后跟随机森林模型。

...
# define modeling pipeline
model = RandomForestClassifier()
imputer = IterativeImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])

我们可以使用重复的 10 倍交叉验证来评估马结肠数据集的估计数据集和随机森林建模管道。

下面列出了完整的示例。

# evaluate iterative imputation and random forest for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# define modeling pipeline
model = RandomForestClassifier()
imputer = IterativeImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
# define model evaluation
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

正确运行该示例将数据插补应用于交叉验证程序的每个折叠。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

使用三次重复的 10 倍交叉验证对管道进行评估,并报告数据集上的平均分类准确率约为 86.3%,这是一个不错的分数。

Mean Accuracy: 0.863 (0.057)

我们如何知道使用默认的迭代策略对这个数据集是好的还是最好的?

答案是我们没有。

迭代插补器和不同的插补顺序

默认情况下,插补按照从缺失值最少的特征到缺失值最多的特征的升序进行。

这是有意义的,因为我们希望在估计大多数值缺失的列的缺失值时有更完整的数据。

然而,我们可以尝试不同的插补顺序策略,如降序、从右向左(阿拉伯语)、从左向右(罗马语)和随机。

以下示例评估和比较了每个可用的插补顺序配置。

# compare iterative imputation strategies for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# evaluate each strategy on the dataset
results = list()
strategies = ['ascending', 'descending', 'roman', 'arabic', 'random']
for s in strategies:
	# create the modeling pipeline
	pipeline = Pipeline(steps=[('i', IterativeImputer(imputation_order=s)), ('m', RandomForestClassifier())])
	# evaluate the model
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# store results
	results.append(scores)
	print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.xticks(rotation=45)
pyplot.show()

运行该示例使用重复的交叉验证来评估马结肠数据集上的每个插补顺序。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

每种策略的平均精确度都是一路上报告的。结果表明,大多数方法之间差别不大,降序(与默认值相反)表现最好。结果表明,阿拉伯语(从右到左)或罗马顺序可能更适合此数据集,准确率约为 87.2%。

>ascending 0.867 (0.049)
>descending 0.871 (0.052)
>roman 0.872 (0.052)
>arabic 0.872 (0.052)
>random 0.870 (0.060)

在运行结束时,为每组结果创建一个方框图和须图,以便比较结果的分布。

Box and Whisker Plot of Imputation Order Strategies Applied to the Horse Colic Dataset

应用于马结肠数据集的插补顺序策略的盒须图

迭代估计器和不同的迭代次数

默认情况下,迭代估计器将重复迭代 10 次。

大量的迭代可能会开始偏离或偏斜估计值,而较少的迭代可能是优选的。过程的迭代次数可以通过“ max_iter ”参数指定。

评估不同的迭代次数可能会很有趣。以下示例比较了从 1 到 20 的“ max_iter ”的不同值。

# compare iterative imputation number of iterations for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# evaluate each strategy on the dataset
results = list()
strategies = [str(i) for i in range(1, 21)]
for s in strategies:
	# create the modeling pipeline
	pipeline = Pipeline(steps=[('i', IterativeImputer(max_iter=int(s))), ('m', RandomForestClassifier())])
	# evaluate the model
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# store results
	results.append(scores)
	print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.xticks(rotation=45)
pyplot.show()

运行该示例使用重复的交叉验证来评估马结肠数据集上的每次迭代次数。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

结果表明,在这个数据集上,很少的迭代,如 3 次迭代,可能与 9-12 次迭代一样有效或更有效。

>1 0.872 (0.053)
>2 0.872 (0.052)
>3 0.874 (0.051)
>4 0.868 (0.050)
>5 0.870 (0.050)
>6 0.871 (0.051)
>7 0.867 (0.055)
>8 0.869 (0.054)
>9 0.867 (0.054)
>10 0.871 (0.051)
>11 0.876 (0.047)
>12 0.870 (0.053)
>13 0.870 (0.056)
>14 0.871 (0.053)
>15 0.868 (0.057)
>16 0.870 (0.053)
>17 0.874 (0.051)
>18 0.873 (0.054)
>19 0.866 (0.054)
>20 0.866 (0.051)

在运行结束时,为每组结果创建一个方框图和须图,以便比较结果的分布。

Box and Whisker Plot of Number of Imputation Iterations on the Horse Colic Dataset

马结肠数据集上插补迭代次数的方框图和触须图

进行预测时的迭代估计变换

我们可能希望使用迭代插补和随机森林算法创建最终的建模管道,然后对新数据进行预测。

这可以通过定义管道并将其拟合到所有可用数据上来实现,然后调用 predict() 函数,将新数据作为参数传入。

重要的是,新数据行必须使用 NaN 值标记任何缺失的值。

...
# define new data
row = [2, 1, 530101, 38.50, 66, 28, 3, 3, nan, 2, 5, 4, 4, nan, nan, nan, 3, 5, 45.00, 8.40, nan, nan, 2, 11300, 00000, 00000, 2]

下面列出了完整的示例。

# iterative imputation strategy and prediction for the hose colic dataset
from numpy import nan
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# create the modeling pipeline
pipeline = Pipeline(steps=[('i', IterativeImputer()), ('m', RandomForestClassifier())])
# fit the model
pipeline.fit(X, y)
# define new data
row = [2, 1, 530101, 38.50, 66, 28, 3, 3, nan, 2, 5, 4, 4, nan, nan, nan, 3, 5, 45.00, 8.40, nan, nan, 2, 11300, 00000, 00000, 2]
# make a prediction
yhat = pipeline.predict([row])
# summarize prediction
print('Predicted Class: %d' % yhat[0])

运行该示例适合所有可用数据的建模管道。

定义一个新的数据行,其缺失值用 NaNs 标记,并进行分类预测。

Predicted Class: 2

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

相关教程

报纸

蜜蜂

资料组

摘要

在本教程中,您发现了如何在机器学习中对缺失数据使用迭代插补策略。

具体来说,您了解到:

  • 缺少的值必须用 NaN 值标记,并且可以用迭代估计值替换。
  • 如何加载缺失值的 CSV 值并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
  • 在评估模型和拟合最终模型以对新数据进行预测时,如何使用迭代模型作为数据准备方法来估计缺失值。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

机器学习中缺失值的 KNN 插补

原文:machinelearningmastery.com/knn-imputat…

最后更新于 2020 年 8 月 17 日

数据集可能会有缺失值,这可能会给许多机器学习算法带来问题。

因此,在对预测任务建模之前,识别并替换输入数据中每一列的缺失值是一种很好的做法。这被称为缺失数据插补,简称为插补。

缺失数据插补的一种流行方法是使用模型来预测缺失值。这需要为每个缺少值的输入变量创建一个模型。尽管一系列不同模型中的任何一个都可以用来预测缺失值,但 k-最近邻(KNN)算法已被证明通常是有效的,通常被称为“最近邻插补

在本教程中,您将发现如何在机器学习中对缺失数据使用最近邻插补策略。

完成本教程后,您将知道:

  • 缺少的值必须用 NaN 值标记,并且可以用最近邻估计值替换。
  • 如何加载缺失值的 CSV 文件并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
  • 在评估模型和拟合最终模型以对新数据进行预测时,如何使用最近邻模型估计缺失值作为数据准备方法。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

  • 更新 6 月/2020 :更改了示例中用于预测的列。

kNN Imputation for Missing Values in Machine Learning

机器学习中缺失值的 kNN 插补 图片由预告,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. k-最近邻插补
  2. 马结肠数据集
  3. 用 KNNImputer 进行最近邻插补
    1. KNN 计算机数据转换
    2. KNN 计算机和模型评估
    3. KNN 计算机和不同数量的邻居
    4. 进行预测时的计算机变换

k-最近邻插补

数据集可能缺少值。

这些数据行中的一个或多个值或列不存在。这些值可能完全丢失,或者可能用特殊字符或值标记,如问号“”。

由于许多原因,这些值可能会丢失,通常是特定于问题域的,并且可能包括损坏的测量或不可用等原因。

大多数机器学习算法需要数字输入值,并且数据集中的每一行和每一列都需要一个值。因此,缺失值会给机器学习算法带来问题。

识别数据集中缺失的值并用数值替换它们是很常见的。这被称为数据插补,或缺失数据插补。

…缺失的数据是可以估计的。在这种情况下,我们可以使用训练集预测器中的信息来本质上估计其他预测器的值。

—第 42 页,应用预测建模,2013 年。

一种有效的数据输入方法是使用模型来预测缺失值。为每个缺少值的要素创建一个模型,将可能所有其他输入要素的输入值作为输入值。

一种流行的插补技术是 K 近邻模型。通过在训练集中找到“最接近”的样本并对这些附近的点进行平均来填充该值,从而估计出一个新的样本。

—第 42 页,应用预测建模,2013 年。

如果输入变量是数字,那么回归模型可以用于预测,这种情况很常见。可以使用一系列不同的模型,尽管简单的 k 近邻(KNN)模型在实验中被证明是有效的。使用 KNN 模型预测或填充缺失值被称为“最近邻插补”或“T2 KNN 插补”

我们表明 KNNimpute 似乎为缺失值估计提供了一种更稳健和更敏感的方法[…],并且 KNNimpute 超过了常用的行平均方法(以及用零填充缺失值)。

——DNA 微阵列缺失值估计方法,2001。

KNN 插补的配置通常涉及为每个预测选择距离度量(例如欧几里德)和贡献邻居的数量,即 KNN 算法的 k 超参数。

现在我们已经熟悉了缺失值插补的最近邻方法,让我们来看看一个缺失值的数据集。

马结肠数据集

马绞痛数据集描述了患有绞痛的马的医学特征以及它们是活的还是死的。

有 300 行 26 个输入变量和一个输出变量。这是一个二分类预测任务,包括预测 1 如果马活了,2 如果马死了。

在这个数据集中,我们可以选择许多字段进行预测。在这种情况下,我们将预测问题是否是外科手术(列索引 23),使其成为二分类问题。

数据集的许多列都有许多缺失值,其中每个缺失值都用问号字符(“?”).

下面提供了数据集中带有标记缺失值的行的示例。

2,1,530101,38.50,66,28,3,3,?,2,5,4,4,?,?,?,3,5,45.00,8.40,?,?,2,2,11300,00000,00000,2
1,1,534817,39.2,88,20,?,?,4,1,3,4,2,?,?,?,4,2,50,85,2,2,3,2,02208,00000,00000,2
2,1,530334,38.30,40,24,1,1,3,1,3,3,1,?,?,?,1,1,33.00,6.70,?,?,1,2,00000,00000,00000,1
1,9,5290409,39.10,164,84,4,1,6,2,2,4,4,1,2,5.00,3,?,48.00,7.20,3,5.30,2,1,02208,00000,00000,1
...

您可以在此了解有关数据集的更多信息:

不需要下载数据集,因为我们将在工作示例中自动下载它。

使用 Python 在加载的数据集中用 NaN(而不是数字)值标记缺失值是最佳实践。

我们可以使用 read_csv() Pandas 函数加载数据集,并指定“na_values”来加载“?”的值作为缺失,用 NaN 值标记。

...
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')

加载后,我们可以查看加载的数据以确认“?”值被标记为 NaN。

...
# summarize the first few rows
print(dataframe.head())

然后,我们可以枚举每一列,并报告该列缺少值的行数。

...
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
	# count number of rows with missing values
	n_miss = dataframe[[i]].isnull().sum()
	perc = n_miss / dataframe.shape[0] * 100
	print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))

将这些联系在一起,下面列出了加载和汇总数据集的完整示例。

# summarize the horse colic dataset
from pandas import read_csv
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# summarize the first few rows
print(dataframe.head())
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
	# count number of rows with missing values
	n_miss = dataframe[[i]].isnull().sum()
	perc = n_miss / dataframe.shape[0] * 100
	print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))

运行该示例首先加载数据集并汇总前五行。

我们可以看到,被标记为“?”的缺失值字符已被 NaN 值替换。

    0   1        2     3      4     5    6   ...   21   22  23     24  25  26  27
0  2.0   1   530101  38.5   66.0  28.0  3.0  ...  NaN  2.0   2  11300   0   0   2
1  1.0   1   534817  39.2   88.0  20.0  NaN  ...  2.0  3.0   2   2208   0   0   2
2  2.0   1   530334  38.3   40.0  24.0  1.0  ...  NaN  1.0   2      0   0   0   1
3  1.0   9  5290409  39.1  164.0  84.0  4.0  ...  5.3  2.0   1   2208   0   0   1
4  2.0   1   530255  37.3  104.0  35.0  NaN  ...  NaN  2.0   2   4300   0   0   2

[5 rows x 28 columns]

接下来,我们可以看到数据集中所有列的列表以及缺失值的数量和百分比。

我们可以看到,一些列(例如列索引 1 和 2)没有缺失值,而其他列(例如列索引 15 和 21)有许多甚至大部分缺失值。

> 0, Missing: 1 (0.3%)
> 1, Missing: 0 (0.0%)
> 2, Missing: 0 (0.0%)
> 3, Missing: 60 (20.0%)
> 4, Missing: 24 (8.0%)
> 5, Missing: 58 (19.3%)
> 6, Missing: 56 (18.7%)
> 7, Missing: 69 (23.0%)
> 8, Missing: 47 (15.7%)
> 9, Missing: 32 (10.7%)
> 10, Missing: 55 (18.3%)
> 11, Missing: 44 (14.7%)
> 12, Missing: 56 (18.7%)
> 13, Missing: 104 (34.7%)
> 14, Missing: 106 (35.3%)
> 15, Missing: 247 (82.3%)
> 16, Missing: 102 (34.0%)
> 17, Missing: 118 (39.3%)
> 18, Missing: 29 (9.7%)
> 19, Missing: 33 (11.0%)
> 20, Missing: 165 (55.0%)
> 21, Missing: 198 (66.0%)
> 22, Missing: 1 (0.3%)
> 23, Missing: 0 (0.0%)
> 24, Missing: 0 (0.0%)
> 25, Missing: 0 (0.0%)
> 26, Missing: 0 (0.0%)
> 27, Missing: 0 (0.0%)

现在我们已经熟悉了丢失值的马绞痛数据集,让我们看看如何使用最近邻插补。

用 KNNImputer 进行最近邻插补

Sklearn 机器学习库提供了支持最近邻插补的 KNNImputer 类

在本节中,我们将探讨如何有效地使用 KNNImputer 类。

KNN 计算机数据转换

KNNImputer 是一种数据转换,首先根据用于估计缺失值的方法进行配置。

默认距离度量是 NaN 感知的欧几里德距离度量,例如,在计算训练数据集成员之间的距离时不包括 NaN 值。这是通过“度量参数设置的。

邻居数量默认设置为 5,可以通过“ n_neighbors ”参数进行配置。

最后,距离度量可以与实例(行)之间的距离成比例地加权,尽管默认情况下这被设置为统一的加权,通过“权重”参数来控制。

...
# define imputer
imputer = KNNImputer(n_neighbors=5, weights='uniform', metric='nan_euclidean')

然后,在数据集上拟合估计值。

...
# fit on the dataset
imputer.fit(X)

然后,将拟合估计器应用于数据集,以创建数据集的副本,用估计值替换每列的所有缺失值。

...
# transform the dataset
Xtrans = imputer.transform(X)

我们可以在 horse colic 数据集上演示它的用法,并通过总结转换前后数据集中缺失值的总数来确认它的工作。

下面列出了完整的示例。

# knn imputation transform for the horse colic dataset
from numpy import isnan
from pandas import read_csv
from sklearn.impute import KNNImputer
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# print total missing
print('Missing: %d' % sum(isnan(X).flatten()))
# define imputer
imputer = KNNImputer()
# fit on the dataset
imputer.fit(X)
# transform the dataset
Xtrans = imputer.transform(X)
# print total missing
print('Missing: %d' % sum(isnan(Xtrans).flatten()))

运行该示例首先加载数据集,并报告数据集中缺失值的总数为 1,605。

转换被配置、调整和执行,生成的新数据集没有缺失值,这证实了它是按照我们的预期执行的。

每个缺失的值都被替换为模型估计的值。

Missing: 1605
Missing: 0

KNN 计算机和模型评估

使用 k 倍交叉验证在数据集上评估机器学习模型是一个很好的实践。

为了正确应用最近邻缺失数据插补并避免数据泄漏,要求为每一列计算的模型仅在训练数据集上计算,然后应用于数据集中每个折叠的训练集和测试集。

这可以通过创建建模管道来实现,其中第一步是最近邻插补,然后第二步是模型。这可以使用管道类来实现。

例如,下面的管道使用带有默认策略的 KNNImputer ,后跟随机森林模型。

...
# define modeling pipeline
model = RandomForestClassifier()
imputer = KNNImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])

我们可以使用重复的 10 倍交叉验证来评估马结肠数据集的估计数据集和随机森林建模管道。

下面列出了完整的示例。

# evaluate knn imputation and random forest for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import KNNImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# define modeling pipeline
model = RandomForestClassifier()
imputer = KNNImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
# define model evaluation
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

正确运行该示例将数据插补应用于交叉验证程序的每个折叠。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

使用 10 倍交叉验证的三次重复对管道进行评估,并报告数据集上的平均分类准确率约为 86.2%,这是一个合理的分数。

Mean Accuracy: 0.862 (0.059)

我们如何知道使用默认的 5 个邻居对这个数据集是好的还是最好的?

答案是我们没有。

KNN 计算机和不同数量的邻居

KNN 算法的关键超参数是k;它控制用于预测的最近邻居的数量。

k 测试一组不同的值是一个很好的做法。

下面的示例评估模型管道,并比较从 1 到 21 的 k 的奇数。

# compare knn imputation strategies for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import KNNImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# evaluate each strategy on the dataset
results = list()
strategies = [str(i) for i in [1,3,5,7,9,15,18,21]]
for s in strategies:
	# create the modeling pipeline
	pipeline = Pipeline(steps=[('i', KNNImputer(n_neighbors=int(s))), ('m', RandomForestClassifier())])
	# evaluate the model
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# store results
	results.append(scores)
	print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.show()

运行该示例使用重复的交叉验证来评估马绞痛数据集中的每个 k 值。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

报告管道的平均分类准确率,每个 k 值用于插补。

在这种情况下,我们可以看到,较大的 k 值会产生表现更好的模型,其中 k=1 会产生约 86.7%准确率的最佳表现。

>1 0.867 (0.049)
>3 0.859 (0.056)
>5 0.864 (0.054)
>7 0.863 (0.053)
>9 0.860 (0.062)
>15 0.866 (0.054)
>18 0.858 (0.052)
>21 0.862 (0.056)

在运行结束时,为每组结果创建一个方框图和须图,以便比较结果的分布。

该图表明,当输入缺失值时,k 值没有太大差异,在平均表现(绿色三角形)附近略有波动。

Box and Whisker Plot of Imputation Number of Neighbors for the Horse Colic Dataset

马绞痛数据集近邻插补数的方框图和须图

进行预测时的计算机变换

我们可能希望使用最近邻插补和随机森林算法创建最终的建模管道,然后对新数据进行预测。

这可以通过定义管道并将其拟合到所有可用数据上来实现,然后调用 predict() 函数,将新数据作为参数传入。

重要的是,新数据行必须使用 NaN 值标记任何缺失的值。

...
# define new data
row = [2, 1, 530101, 38.50, 66, 28, 3, 3, nan, 2, 5, 4, 4, nan, nan, nan, 3, 5, 45.00, 8.40, nan, nan, 2, 11300, 00000, 00000, 2]

下面列出了完整的示例。

# knn imputation strategy and prediction for the hose colic dataset
from numpy import nan
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import KNNImputer
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# create the modeling pipeline
pipeline = Pipeline(steps=[('i', KNNImputer(n_neighbors=21)), ('m', RandomForestClassifier())])
# fit the model
pipeline.fit(X, y)
# define new data
row = [2, 1, 530101, 38.50, 66, 28, 3, 3, nan, 2, 5, 4, 4, nan, nan, nan, 3, 5, 45.00, 8.40, nan, nan, 2, 11300, 00000, 00000, 2]
# make a prediction
yhat = pipeline.predict([row])
# summarize prediction
print('Predicted Class: %d' % yhat[0])

运行该示例适合所有可用数据的建模管道。

定义一个新的数据行,其缺失值用 NaNs 标记,并进行分类预测。

Predicted Class: 2

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

相关教程

报纸

蜜蜂

资料组

摘要

在本教程中,您发现了如何在机器学习中对缺失数据使用最近邻插补策略。

具体来说,您了解到:

  • 缺少的值必须用 NaN 值标记,并且可以用最近邻估计值替换。
  • 如何加载缺失值的 CSV 文件并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
  • 在评估模型和拟合最终模型以对新数据进行预测时,如何使用最近邻模型估计缺失值作为数据准备方法。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

Python 中用于降维的线性判别分析

原文:machinelearningmastery.com/linear-disc…

最后更新于 2020 年 8 月 18 日

减少预测模型的输入变量的数量被称为降维。

较少的输入变量可以导致更简单的预测模型,该模型在对新数据进行预测时可能具有更好的表现。

线性判别分析,简称 LDA,是一种多类分类的预测建模算法。它还可以用作降维技术,提供一个训练数据集的投影,通过给定的类最好地分离示例。

使用线性判别分析进行降维的能力经常让大多数从业者感到惊讶。

在本教程中,您将发现在开发预测模型时如何使用 LDA 进行降维。

完成本教程后,您将知道:

  • 降维包括减少建模数据中输入变量或列的数量。
  • LDA 是一种多类分类技术,可用于自动执行降维。
  • 如何评估使用线性判别分析投影作为输入的预测模型,并使用新的原始数据进行预测。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

  • 2020 年 5 月更新:改进代码注释

Linear Discriminant Analysis for Dimensionality Reduction in Python

Python 中降维的线性判别分析 图片由金伯利·瓦德曼提供,保留部分权利。

教程概述

本教程分为四个部分;它们是:

  1. 降维
  2. 线性判别分析
  3. LDA Sklearn API
  4. 维度的线性判别分析工作示例

降维

降维是指减少数据集的输入变量数量。

如果您的数据是用行和列来表示的,例如在电子表格中,那么输入变量就是作为输入提供给模型以预测目标变量的列。输入变量也称为特征。

我们可以将 n 维特征空间上表示维度的数据列和数据行视为该空间中的点。这是数据集的一种有用的几何解释。

在具有 k 个数字属性的数据集中,您可以将数据可视化为 k 维空间中的点云…

—第 305 页,数据挖掘:实用机器学习工具与技术,2016 年第 4 版。

特征空间中有大量的维度可能意味着该空间的体积非常大,反过来,我们在该空间中的点(数据行)通常代表一个小的且不具有代表性的样本。

这可能会极大地影响机器学习算法在具有许多输入特征的数据上的表现,通常被称为“维度诅咒””

因此,通常希望减少输入特征的数量。这减少了特征空间的维数,因此得名“降维

降维的一种流行方法是使用线性代数领域的技术。这通常被称为“T0”特征投影,所使用的算法被称为“T2”投影方法

投影方法寻求减少特征空间中的维数,同时保留数据中观察到的变量之间最重要的结构或关系。

当处理高维数据时,通过将数据投影到捕捉数据“本质”的低维子空间来降低维数通常是有用的。这叫做降维。

—第 11 页,机器学习:概率视角,2012。

得到的数据集,即投影,可以用作训练机器学习模型的输入。

本质上,原始特征不再存在,而新特征是从与原始数据不直接可比的可用数据构建的,例如没有列名。

未来在进行预测时,任何新数据(如测试数据集和新数据集)都必须使用相同的技术进行投影。

线性判别分析

线性判别分析,简称 LDA,是一种用于多类分类的线性机器学习算法。

不应与“潜在狄利克雷分配”(LDA)混淆,后者也是一种针对文本文档的降维技术。

线性判别分析试图通过类别值来最好地分离(或区分)训练数据集中的样本。具体而言,该模型寻求找到输入变量的线性组合,实现类间样本的最大分离(类质心或平均值)和每个类内样本的最小分离。

…找出预测因子的线性组合,使组间方差相对于组内方差最大化。[……]找到预测因子的组合,使数据中心之间的间隔最大化,同时使每组数据中的变化最小化。

—第 289 页,应用预测建模,2013 年。

LDA 的框架和求解方法有很多;例如,通常用贝叶斯定理和条件概率来描述 LDA 算法。

在实践中,用于多类分类的 LDA 通常使用来自线性代数的工具来实现,并且像 PCA 一样,使用作为技术核心的矩阵分解。因此,在拟合线性判别分析模型之前,最好先对数据进行标准化。

有关如何详细计算 LDA 的更多信息,请参见教程:

现在我们已经熟悉了降维和 LDA,让我们看看如何将这种方法用于 Sklearn 库。

LDA Sklearn API

我们可以使用线性判别分析来计算数据集的投影,并选择投影的多个维度或分量作为模型的输入。

Sklearn 库提供了linear discriminator analysis 类,该类可适用于数据集,并用于转换训练数据集和未来的任何附加数据集。

例如:

...
# prepare dataset
data = ...
# define transform
lda = LinearDiscriminantAnalysis()
# prepare transform on dataset
lda.fit(data)
# apply transform to dataset
transformed = lda.transform(data)

线性判别分析的输出可以用作训练模型的输入。

也许最好的方法是使用管道,其中第一步是 LDA 变换,下一步是将变换后的数据作为输入的学习算法。

...
# define the pipeline
steps = [('lda', LinearDiscriminantAnalysis()), ('m', GaussianNB())]
model = Pipeline(steps=steps)

如果输入变量具有不同的单位或比例,在执行线性判别分析变换之前标准化数据也是一个好主意;例如:

...
# define the pipeline
steps = [('s', StandardScaler()), ('lda', LinearDiscriminantAnalysis()), ('m', GaussianNB())]
model = Pipeline(steps=steps)

现在我们已经熟悉了 LDA 应用编程接口,让我们来看看一个成功的例子。

维度的线性判别分析工作示例

首先,我们可以使用 make_classification()函数创建一个包含 1000 个示例和 20 个输入特征的合成 10 类分类问题,其中 15 个输入是有意义的。

下面列出了完整的示例。

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集并总结输入和输出组件的形状。

(1000, 20) (1000,)

接下来,我们可以在拟合朴素贝叶斯模型的同时对该数据集进行降维。

我们将使用管道,其中第一步执行线性判别分析变换并选择五个最重要的维度或组件,然后在这些特征上拟合朴素贝叶斯模型。我们不需要标准化这个数据集中的变量,因为所有的变量都有相同的设计比例。

管道将使用重复分层交叉验证进行评估,重复三次,每次重复 10 次。表现表示为平均分类准确率。

下面列出了完整的示例。

# evaluate lda with naive bayes algorithm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10)
# define the pipeline
steps = [('lda', LinearDiscriminantAnalysis(n_components=5)), ('m', GaussianNB())]
model = Pipeline(steps=steps)
# evaluate model
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行示例评估模型并报告分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到带有朴素贝叶斯的 LDA 变换获得了大约 31.4%的表现。

Accuracy: 0.314 (0.049)

我们如何知道把 20 个维度的投入减少到 5 个是好的还是我们能做的最好的?

我们没有;五是一个任意的选择。

更好的方法是用不同数量的输入特征评估相同的变换和模型,并选择导致最佳平均表现的特征数量(降维量)。

LDA 在降维中使用的组件数量被限制在类的数量减一之间,在这种情况下是(10–1)或 9

下面的示例执行了该实验,并总结了每种配置的平均分类准确率。

# compare lda number of components with naive bayes algorithm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	for i in range(1,10):
		steps = [('lda', LinearDiscriminantAnalysis(n_components=i)), ('m', GaussianNB())]
		models[str(i)] = Pipeline(steps=steps)
	return models

# evaluate a give model using cross-validation
def evaluate_model(model, X, y):
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	scores = evaluate_model(model, X, y)
	results.append(scores)
	names.append(name)
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行该示例首先报告所选组件或特征的每个数量的分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

随着维度数量的增加,我们可以看到表现提高的总体趋势。在这个数据集上,结果显示了维度数量和模型分类准确率之间的权衡。

结果表明,使用默认的九个组件可以在这个数据集上获得最佳表现,尽管会有一个温和的折衷,因为使用的维度更少。

>1 0.182 (0.032)
>2 0.235 (0.036)
>3 0.267 (0.038)
>4 0.303 (0.037)
>5 0.314 (0.049)
>6 0.314 (0.040)
>7 0.329 (0.042)
>8 0.343 (0.045)
>9 0.358 (0.056)

为每个配置的尺寸数量的准确率分数的分布创建一个方框和触须图。

我们可以看到分类准确率随着组件数量的增加而增加的趋势,限制在 9 个。

Box Plot of LDA Number of Components vs. Classification Accuracy

线性判别分析组件数与分类准确率的箱线图

我们可以选择使用线性判别分析变换和朴素贝叶斯模型组合作为最终模型。

这包括在所有可用数据上拟合管道,并使用管道对新数据进行预测。重要的是,必须对这个新数据执行相同的转换,这是通过管道自动处理的。

下面的代码提供了一个在新数据上使用线性判别分析变换拟合和使用最终模型的例子。

# make predictions using lda with naive bayes
from sklearn.datasets import make_classification
from sklearn.pipeline import Pipeline
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7, n_classes=10)
# define the model
steps = [('lda', LinearDiscriminantAnalysis(n_components=9)), ('m', GaussianNB())]
model = Pipeline(steps=steps)
# fit the model on the whole dataset
model.fit(X, y)
# make a single prediction
row = [[2.3548775,-1.69674567,1.6193882,-1.19668862,-2.85422348,-2.00998376,16.56128782,2.57257575,9.93779782,0.43415008,6.08274911,2.12689336,1.70100279,3.32160983,13.02048541,-3.05034488,2.06346747,-3.33390362,2.45147541,-1.23455205]]
yhat = model.predict(row)
print('Predicted Class: %d' % yhat[0])

运行该示例使管道适用于所有可用数据,并对新数据进行预测。

这里,变换使用了我们在上面的测试中发现的 LDA 变换的九个最重要的组成部分。

提供了一个包含 20 列的新数据行,它被自动转换为 15 个分量,并被馈送到朴素贝叶斯模型,以便预测类标签。

Predicted Class: 6

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

蜜蜂

文章

摘要

在本教程中,您发现了在开发预测模型时如何使用 LDA 进行降维。

具体来说,您了解到:

  • 降维包括减少建模数据中输入变量或列的数量。
  • LDA 是一种多类分类技术,可用于自动执行降维。
  • 如何评估使用线性判别分析投影作为输入的预测模型,并使用新的原始数据进行预测。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

Python 中的 4 种自动异常值检测算法

原文:machinelearningmastery.com/model-based…

最后更新于 2020 年 8 月 17 日

分类或回归数据集中异常值的存在会导致拟合不佳和预测建模表现降低。

在给定大量输入变量的情况下,对于大多数机器学习数据集来说,用简单的统计方法识别和去除异常值是具有挑战性的。相反,可以在建模管道中使用自动异常值检测方法并进行比较,就像可以应用于数据集的其他数据准备转换一样。

在本教程中,您将发现如何使用自动异常值检测和移除来提高机器学习预测建模表现。

完成本教程后,您将知道:

  • 自动异常值检测模型提供了一种替代统计技术的方法,该技术具有大量输入变量,这些变量具有复杂且未知的相互关系。
  • 如何正确地对训练数据集应用自动异常值检测和去除,避免数据泄露?
  • 如何评估和比较预测建模管道和从训练数据集中移除的异常值。

用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

Model-Based Outlier Detection and Removal in Python

Python 中基于模型的异常值检测和移除 图片由佐尔坦·沃尔斯提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 异常值的检测和去除
  2. 数据集和表现基线
    1. 房价回归数据集
    2. 基线模型表现
  3. 自动异常值检测
    1. 隔离林
    2. 最小协方差行列式
    3. 局部异常因子
    4. 一等 SVM

异常值的检测和去除

异常值是数据集中不符合某种方式的观测值。

也许最常见或最熟悉的异常值类型是远离其余观测值或观测值重心的观测值。

当我们有一个或两个变量时,这很容易理解,我们可以将数据可视化为直方图或散点图,尽管当我们有许多定义高维输入特征空间的输入变量时,这变得非常具有挑战性。

在这种情况下,用于识别异常值的简单统计方法可能会失效,例如使用标准差或四分位数范围的方法。

在训练机器学习算法进行预测建模时,从数据中识别和移除异常值可能很重要。

异常值会偏斜统计度量和数据分布,对底层数据和关系提供误导性的表示。在建模之前从训练数据中去除异常值可以使数据更好地匹配,进而产生更巧妙的预测。

谢天谢地,有各种基于模型的自动方法来识别输入数据中的异常值。重要的是,每种方法对异常值的定义略有不同,提供了准备可评估和比较的训练数据集的替代方法,就像建模管道中的任何其他数据准备步骤一样。

在我们深入研究自动异常值检测方法之前,让我们首先选择一个标准的机器学习数据集,作为我们研究的基础。

数据集和表现基线

在本节中,我们将首先选择一个标准的机器学习数据集,并在该数据集上建立表现基线。

这将为下一节探索数据准备的异常值识别和移除方法提供背景。

房价回归数据集

我们将使用房价回归数据集。

这个数据集有 13 个输入变量,描述了房子和郊区的属性,并要求以千美元为单位预测郊区房子的中值。

您可以在此了解有关数据集的更多信息:

不需要下载数据集,因为我们将自动下载它作为我们工作示例的一部分。

打开数据集并查看原始数据。下面列出了前几行数据。

我们可以看到,这是一个带有数值输入变量的回归预测建模问题,每个变量都有不同的尺度。

0.00632,18.00,2.310,0,0.5380,6.5750,65.20,4.0900,1,296.0,15.30,396.90,4.98,24.00
0.02731,0.00,7.070,0,0.4690,6.4210,78.90,4.9671,2,242.0,17.80,396.90,9.14,21.60
0.02729,0.00,7.070,0,0.4690,7.1850,61.10,4.9671,2,242.0,17.80,392.83,4.03,34.70
0.03237,0.00,2.180,0,0.4580,6.9980,45.80,6.0622,3,222.0,18.70,394.63,2.94,33.40
0.06905,0.00,2.180,0,0.4580,7.1470,54.20,6.0622,3,222.0,18.70,396.90,5.33,36.20
...

数据集有许多数值输入变量,这些变量具有未知且复杂的关系。我们不知道这个数据集中是否存在异常值,尽管我们可能猜测可能存在一些异常值。

下面的示例加载数据集并将其拆分为输入和输出列,将其拆分为训练和测试数据集,然后总结数据数组的形状。

# load and summarize the dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# summarize the shape of the dataset
print(X.shape, y.shape)
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the shape of the train and test sets
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

运行该示例,我们可以看到数据集被正确加载,并且有 506 行数据,包含 13 个输入变量和一个目标变量。

数据集被分成训练集和测试集,其中 339 行用于模型训练,167 行用于模型评估。

(506, 13) (506,)
(339, 13) (167, 13) (339,) (167,)

接下来,让我们在这个数据集上评估一个模型,并建立一个表现基线。

基线模型表现

这是一个回归预测建模问题,意味着我们将预测一个数值。所有输入变量也是数字。

在这种情况下,我们将拟合线性回归算法,并通过在测试数据集上训练模型并对测试数据进行预测来评估模型表现,并使用平均绝对误差(MAE)来评估预测。

下面列出了在数据集上评估线性回归模型的完整示例。

# evaluate model on the raw dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)

运行该示例适合并评估模型,然后报告 MAE。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到模型实现了大约 3.417 的 MAE。这提供了一个表现基线,我们可以据此比较不同的异常值识别和去除程序。

MAE: 3.417

接下来,我们可以尝试从训练数据集中移除异常值。

自动异常值检测

Sklearn 库提供了许多内置的自动方法来识别数据中的异常值。

在本节中,我们将回顾四种方法,并比较它们在房价数据集上的表现。

每个方法都将被定义,然后适合训练数据集。然后,拟合模型将预测训练数据集中哪些示例是异常值,哪些不是(所谓的内联值)。然后将从训练数据集中移除异常值,然后将模型拟合到剩余的示例中,并在整个测试数据集中进行评估。

在整个训练数据集上拟合异常值检测方法是无效的,因为这会导致数据泄露。也就是说,模型可以访问测试集中未用于训练模型的数据(或关于数据的信息)。这可能导致对模型表现的乐观估计。

在进行预测之前,我们可以尝试检测“新数据”上的异常值,例如测试集,但是如果检测到异常值,我们该怎么办?

一种方法可能是返回“ None ”,表示模型无法对这些异常情况做出预测。这可能是一个有趣的扩展,适合您的项目。

隔离林

隔离森林,简称 iForest,是一种基于树的异常检测算法。

它基于对正常数据进行建模,从而隔离特征空间中数量少且不同的异常。

……我们提出的方法利用了两个异常的数量属性:I)它们是由较少实例组成的少数,以及 ii)它们具有与正常实例非常不同的属性值。

——隔离森林,2008 年。

Sklearn 库在 IsolationForest 类中提供了隔离林的实现。

也许模型中最重要的超参数是“污染”参数,该参数用于帮助估计数据集中异常值的数量。这是一个介于 0.0 和 0.5 之间的值,默认设置为 0.1。

...
# identify outliers in the training dataset
iso = IsolationForest(contamination=0.1)
yhat = iso.fit_predict(X_train)

一旦识别出来,我们就可以从训练数据集中移除异常值。

...
# select all rows that are not outliers
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]

将这些联系在一起,下面列出了在房屋数据集上评估线性模型的完整示例,使用隔离林识别并移除异常值。

# evaluate model performance with outliers removed using isolation forest
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import IsolationForest
from sklearn.metrics import mean_absolute_error
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the shape of the training dataset
print(X_train.shape, y_train.shape)
# identify outliers in the training dataset
iso = IsolationForest(contamination=0.1)
yhat = iso.fit_predict(X_train)
# select all rows that are not outliers
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]
# summarize the shape of the updated training dataset
print(X_train.shape, y_train.shape)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)

运行该示例适合并评估模型,然后报告 MAE。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到,该模型识别并移除了 34 个异常值,并获得了约 3.189 的 MAE,这比得分约为 3.417 的基线有所改善。

(339, 13) (339,)
(305, 13) (305,)
MAE: 3.189

最小协方差行列式

如果输入变量具有高斯分布,则可以使用简单的统计方法来检测异常值。

例如,如果数据集有两个输入变量,并且都是高斯的,那么特征空间形成多维高斯,并且可以使用这种分布的知识来识别远离该分布的值。

这种方法可以通过定义一个覆盖正常数据的超球(椭球)来推广,超出这个形状的数据被认为是异常值。对于多变量数据,这种技术的有效实现被称为最小协方差行列式,简称 MCD。

最小协方差行列式(MCD)方法是一种高度稳健的多元定位和散射估计方法,其快速算法是可用的。[……]它也是一个方便有效的异常值检测工具。

——最小协方差行列式与延拓,2017。

Sklearn 库通过椭圆包络类提供对该方法的访问。

它提供了“污染”参数,该参数定义了在实践中观察到的异常值的预期比率。在这种情况下,我们将它设置为 0.01 的值,通过一点点反复试验发现。

...
# identify outliers in the training dataset
ee = EllipticEnvelope(contamination=0.01)
yhat = ee.fit_predict(X_train)

一旦识别出异常值,就可以像我们在前面的示例中所做的那样,从训练数据集中移除异常值。

将这些联系在一起,下面列出了使用椭圆包络(最小协变行列式)方法从房屋数据集中识别和移除异常值的完整示例。

# evaluate model performance with outliers removed using elliptical envelope
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.covariance import EllipticEnvelope
from sklearn.metrics import mean_absolute_error
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the shape of the training dataset
print(X_train.shape, y_train.shape)
# identify outliers in the training dataset
ee = EllipticEnvelope(contamination=0.01)
yhat = ee.fit_predict(X_train)
# select all rows that are not outliers
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]
# summarize the shape of the updated training dataset
print(X_train.shape, y_train.shape)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)

运行该示例适合并评估模型,然后报告 MAE。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到椭圆包络方法仅识别并移除了 4 个异常值,导致 MAE 从基线的 3.417 下降到 3.388。

(339, 13) (339,)
(335, 13) (335,)
MAE: 3.388

局部异常因子

识别异常值的一个简单方法是定位那些在特征空间中远离其他示例的示例。

这对于低维度(很少特征)的特征空间可以很好地工作,尽管随着特征数量的增加,它会变得不那么可靠,这被称为维度的诅咒。

局部离群因子,简称 LOF,是一种试图利用最近邻概念进行异常值检测的技术。每个例子都被分配了一个分数,根据其局部邻域的大小来衡量孤立的程度或异常值出现的可能性。得分最高的例子更有可能是异常值。

我们为数据集中的每个对象引入一个局部离群值(LOF),指示其离群程度。

——LOF:识别基于密度的局部异常值,2000 年。

Sklearn 库在localhoutlierfactor 类中提供了这种方法的实现。

该模型提供“污染”参数,即数据集中异常值的预期百分比,被指示并默认为 0.1。

...
# identify outliers in the training dataset
lof = LocalOutlierFactor()
yhat = lof.fit_predict(X_train)

将这些联系在一起,下面列出了使用局部异常因子方法从住房数据集中识别和移除异常值的完整示例。

# evaluate model performance with outliers removed using local outlier factor
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import LocalOutlierFactor
from sklearn.metrics import mean_absolute_error
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the shape of the training dataset
print(X_train.shape, y_train.shape)
# identify outliers in the training dataset
lof = LocalOutlierFactor()
yhat = lof.fit_predict(X_train)
# select all rows that are not outliers
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]
# summarize the shape of the updated training dataset
print(X_train.shape, y_train.shape)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)

运行该示例适合并评估模型,然后报告 MAE。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到局部离群因子方法识别并移除了 34 个离群值,与隔离林的数量相同,导致 MAE 从基线的 3.417 下降到 3.356。更好,但不如隔离森林,这表明发现并移除了一组不同的异常值。

(339, 13) (339,)
(305, 13) (305,)
MAE: 3.356

一等 SVM

最初为二进制分类开发的支持向量机或 SVM 算法可用于单类分类。

当对一个类建模时,该算法捕获多数类的密度,并将密度函数极值上的例子分类为异常值。SVM 的这种修改被称为一级 SVM。

…一种计算二进制函数的算法,该二进制函数应该捕获输入空间中概率密度所在的区域(它的支持),也就是说,一个函数使得大部分数据将位于该函数非零的区域。

——估计高维分布的支持,2001。

虽然 SVM 是一种分类算法,而一类 SVM 也是一种分类算法,但它可以用于发现回归和类别数据集的输入数据中的异常值。

Sklearn 库在 OneClassSVM 类中提供了一个一类 SVM 的实现。

该类提供了“ nu ”参数,该参数指定了数据集中异常值的近似比率,默认为 0.1。在这种情况下,我们将它设置为 0.01,稍微试错一下就发现了。

...
# identify outliers in the training dataset
ee = OneClassSVM(nu=0.01)
yhat = ee.fit_predict(X_train)

将这些联系在一起,下面列出了使用一类 SVM 方法从住房数据集中识别和移除异常值的完整示例。

# evaluate model performance with outliers removed using one class SVM
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.svm import OneClassSVM
from sklearn.metrics import mean_absolute_error
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
# retrieve the array
data = df.values
# split into input and output elements
X, y = data[:, :-1], data[:, -1]
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize the shape of the training dataset
print(X_train.shape, y_train.shape)
# identify outliers in the training dataset
ee = OneClassSVM(nu=0.01)
yhat = ee.fit_predict(X_train)
# select all rows that are not outliers
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]
# summarize the shape of the updated training dataset
print(X_train.shape, y_train.shape)
# fit the model
model = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)

运行该示例适合并评估模型,然后报告 MAE。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到只有三个异常值被识别和移除,并且模型实现了大约 3.431 的 MAE,这并不比实现 3.417 的基线模型更好。也许通过更多的调整可以获得更好的表现。

(339, 13) (339,)
(336, 13) (336,)
MAE: 3.431

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

相关教程

报纸

蜜蜂

摘要

在本教程中,您发现了如何使用自动异常值检测和移除来提高机器学习预测建模表现。

具体来说,您了解到:

  • 自动异常值检测模型提供了一种替代统计技术的方法,该技术具有大量输入变量,这些变量具有复杂且未知的相互关系。
  • 如何正确地对训练数据集应用自动异常值检测和去除,避免数据泄露?
  • 如何评估和比较预测建模管道和从训练数据集中移除的异常值。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。