Ebook

第 2 章

常见预处理任务


机器学习应用所需的预处理任务取决于您处理的数据类型以及您选择的算法类型。不过,其中有些任务相对常见一些。本章将探讨五种最常见的数据预处理方法,以及如何使用 MATLAB 执行这些方法。

section

统一数据格式

很多预处理任务都涉及使数据集在某一方面统一,其中包括数据格式,特别是针对带有时间戳的数据。

格式不统一可能会在不知不觉中引入重大问题,如果不能尽早处理,则难免浪费时间。这些问题不一定会引发错误,因此即便降低了模型准确性也未必有明显的可疑之处。您可以使用以下两个 MATLAB 函数轻松统一带时间戳数据的格式:

  • datetime
  • duration

时间标准化和偏移

使用带时间戳的数据时,您有必要检查一下日期和时间是否具有一致的格式。切忌轻率假设。

MATLAB 使用日期时间 (datetime) 数组表示时间点,为您省去处理时区、夏令时和闰秒的工作量。

语法

t = datetime
t = datetime(relativeDay)
t = datetime(DateStrings)
t = datetime(DateVectors)
t = datetime(Y,M,D)

持续时间

MATLAB 使用持续时间表示经过的时长。如果使用相对时间戳测量经过的时间,数据记录系统差异、起始时间差异及其他因素均可能引发问题。

使用 duration 可比较起始时间不同的任务的持续时间、设置阈值或创建一致的时长(例如,以 10 秒为间隔的信号数据)。

查看更多信息,进一步了解如何处理日期、时间和日历持续时间。

语法

D = duration(H,MI,S)
D = duration(H,MI,S,MS)
D = duration(X)

section

合并

要构建成功的机器学习模型,关键的一点是结合使用来自多个位置或数据集的数据。例如,使用天气数据增强零售数据集可大幅提高机器学习模型准确预测防晒霜销量的概率。合并数据集通常有两种方法:

  • 基于某个键值(唯一标识符,例如电子邮件地址)合并
  • 基于时间合并

要实现基于键的合并,您可以根据所需合并类型使用相应的命令 (joininnerjoin, outerjoin), 或使用“联接表”实时编辑器任务:

Merging table example

要实现基于时间的合并,您可以在 MATLAB 中使用时间表和 synchronize 命令。请注意,除非正在同步的时间表具有完全相同的时间步长,否则您需要处理特定变量在某一时间步未被测量造成的缺失问题。synchronize 命令提供了多种内置方法来解决此类问题,例如执行线性和样条插值,或者从距测量位置最近的时间步复制值。

合并时间表

% 从同一文件中加载两个样本时间表。
% 然后,将数据同步到新的行时间向量。

load smallTT

% 显示时间表。
% TT1 的行时间无序。
% TT1 和 TT2 的变量不同。

TT1
TT1=3×2 timetable
            Time            Temp
    ____________________    ____

    18-Dec-2015 12:00:00    42.3
    18-Dec-2015 08:00:00    37.3
    18-Dec-2015 10:00:00    39.1

TT2
TT2=3×2 timetable
         Time               Pressure
    ____________________    ________

    18-Dec-2015 09:00:00     30.1 
    18-Dec-2015 11:00:00    30.03 
    18-Dec-2015 13:00:00     29.9 

% 同步 TT1 与 TT2。.
% 输出时间表 TT 包含两个时间表的所有行时间(已排序)。.

% 在 TT 中,Temp 在对应 TT2 行时间处具有 NaN 值,而 Pressure 在对应 TT1 行时间处具有 NaN 值。.

TT = synchronize(TT1,TT2)
TT=6×3 timetable

    Time                    Temp    Pressure
    ____________________    ____    ________

    18-Dec-2015 08:00:00    37.3    NaN 
    18-Dec-2015 09:00:00     NaN    30.1 
    18-Dec-2015 10:00:00    39.1    NaN 
    18-Dec-2015 11:00:00     NaN    30.03 
    18-Dec-2015 12:00:00    42.3    NaN 
    18-Dec-2015 13:00:00     NaN    29.9

将以下命令复制到 MATLAB 以尝试此示例:

openExample('matlab/SynchronizeTimetablesAndInsertMissingDataIndicatorsExample')

在 MATLAB 命令行窗口中输入此命令以运行。Web 浏览器不支持 MATLAB 命令。

section

处理缺失数据

机器学习算法基于数据特征及特征之间的相互关系进行预测。当某一观测值中缺少数据时,特征之间的关系将更加难以发现。如有数据缺失,将根据观测值中的缺失变量是否缺失决定删除数据还是替换数据。

当准备机器学习数据时,您可以使用以下三种方法处理缺失数据:删除(观测值,也可能是整列);替换;或者不执行任何操作,留待模型自行处理。究竟采用哪一种方法取决于导致数据缺失的原因。

若要确定缺失数据是否是随机的,需绘制各个变量以找出模式。

缺失值在 MATLAB 中的显示方式因其数据类型而异。例如,缺失数值显示为 NaN,缺失日期时间值显示为 NaT;缺失分类值显示为 <undefined>, 缺失字符串显示为 <missing>.

以下示例在一个包含 500 条调查反馈的表 (SurveyAges) 中查找缺失数据,该表依次包含受访者 ID、年龄和资历三列。您希望查看是否存在缺失值及缺失值所在的位置。

查找缺失数据

A = SurveyAges(:,2)
Tf = ismissing(A)
G = sum(Tf)

这将生成由 1 和 0 构成的逻辑数组,其中 1 是指数据缺失。在本例中,G = 36,即缺失反馈总数。

语法

Tf = ismissing(A)
Tf = ismissing(A,indicator)

Missing data, live task

一般而言,如果数据缺失是随机的,则可以安全删除数据。但在本例中,通过数据绘图,您可以看到缺失数据在高龄段较为普遍。

如果缺失数据并非随机(例如老员工可能不希望披露年龄),则删除缺失数据可能引入偏差。在本例中,您可以使用生成的数据填充空缺。究竟使用哪一种方法填充这些值将取决于您的数据。常见方法包括均值、中位数、众数、线性回归和 K 最近邻。如果使用时序数据,则还可使用末次观测值向前结转、下次观测值向后结转和线性插值等其他方法。

MATLAB 提供多种可用于删除或填充缺失值的函数。 fillmissing 是一种通用函数,稍后将详细说明。

清理缺失数据

如果某一列缺失大部分值,或许最好从数据集中删除这一整列。

以下是在实时编辑器中使用任务的简要步骤。与其他任务一样,在“主页”工具条中选择新建实时脚本”。

New Live Script example

在“实时编辑器”选项卡下,单击“任务”,然后选择“清理缺失数据”。.

Live Task toolstrip example

用户界面随即打开。选择数据时的可用选项将取决于工作区变量。

Clean missing data dialog

使用下拉菜单选择您要搜索缺失值的数据,然后选择要对这些条目执行的操作,可能是填充,也可能是删除。

将清理方法设置为“删除缺失”。现在,工作区具有三个变量:原始表、缺失条目索引,以及清理后的数据的双精度数组。

您可以看出数据已经过清理,因为右侧的图中绘制了缺失数据,其标题指出了缺失条目个数。

单击任务窗口底部的向下箭头将显示代码,您可以查看 MATLAB 具体执行的操作。

% 删除缺失数据
[cleanedData,missingIndices] = rmmissing(offerab.Actions);

% 可视化结果
clf
plot(find(~missingIndices),cleanedData,'Color',[0 114 189]/255,'LineWidth',1.5,'DisplayName','Cleaned data')
hold on

% 绘制删除的缺失条目
x = repelem(find(missingIndices),3);
y = repmat([ylim(gca) NaN]',nnz(missingIndices),1);
plot(x,y,'Color',[145 145 145]/255,'DisplayName','Removed missing entries')
title(['Number of removed missing entries: ' num2str(nnz(missingIndices))])

hold off
legend
clear x y

您可以将此代码保存为预处理脚本的一部分。

要在实时编辑器中替换缺失数据,开头的几个步骤与删除数据相同。然后,在“指定方法”下,选择“填充缺失”,再从十种方法中选择一种:

在填充缺失条目(本例采用移动均值)所生成的代码中,您会注意到,填充只用了一行代码;其余代码用于绘制清理后的数据和填充的条目。

% 填充缺失数据
[cleanedData,missingIndices] = fillmissing(offerab.Actions,'movmean',3);
% 可视化结果
clf
plot(cleanedData,'Color',[0 114 189]/255,'LineWidth',1.5,...
'DisplayName','Cleaned data')
hold on
% 绘制填充的缺失条目
plot(find(missingIndices),cleanedData(missingIndices),'.','MarkerSize',12,...
    'Color',[217 83 25]/255,'DisplayName','Filled missing entries')
title(['Number of filled missing entries: ' num2str(nnz(missingIndices))])

hold off
legend
clear missingIndices
section

修复离群值

离群值的存在和出现频率可以在很大程度上反映数据整体质量。离群值究竟是均匀分布、集中出现还是以其他某种模式存在,会影响您处理离群值的方式。如果离群值在数据集中仅占极小比例,而且看上去就不准确,或是由于数据收集方法不当所造成,则可较为安全地将其视为不良数据加以删除。但是,首先仍要从数据中识别此类不良数据。

您可以运用多种统计模型查找数据中的离群值。部分常用方法包括:

  • Grubbs 检验
  • 中位数
  • 移动均值
  • 四分位数

无论使用哪一种方法,您都需要了解数据的最小值、最大值、均值和标准差。

MATLAB 提供多种可用于在数据中查找离群值的内置函数;File Exchange 中还提供了文件以简化这项任务,例如 识别数据序列离群值的检验

尽管删除离群值可能带来风险,但置之不理又可能使结果发生显著偏差。MATLAB 提供多种方法来处理离群值,包括使用命令行以编程方式处理,以及通过实时编辑器以交互方式处理。下面将简要介绍这两种方法。

Outlier Detection Using Qunatile Regression

命令行

MATLAB 中的 filloutliers 函数是一种识别离群值并通过某种自动方法替换离群值的便捷手段。

填充离群值的方法 包括 'previous', 'linear', 和 'spline'.

下面是一个简单示例:

Afill = filloutliers(Anoise,'next');
plot(t,Anoise,t,Afill)
axis tight
legend('Noisy Data with Outlier','Noisy Data with Filled
Outlier') 

语法

B = filloutliers(A,fillmethod)
B = filloutliers(A,fillmethod,findmethod)
B = filloutliers(A,fillmethod,'percentiles',threshold)
B = filloutliers(A,fillmethod,movmethod,window)
B = filloutliers(___,dim)
B = filloutliers(___,Name,Value)
[B,TF,L,U,C] = filloutliers(___)

鉴于填充离群值的方法众多,您有必要先以可视化方法检查结果,然后再尝试将填充后的数据用于机器学习算法。

前期数据清理越充分,后期调整算法花费的时间就越短。

Fill outlier graph

实时编辑器任务

使用实时编辑器任务清理离群数据的一个好处在于,每次选取检测方法,用户界面都将相应更新离群值个数。

下面使用三种检测方法处理同一组数据。Grubbs 检验法和均值法均返回不到 100 个离群值,而四分位数法返回了 1,103 个离群值,略超过条目总数的 1/4。

若要清理离群值,请选择一种清理方法,可用的选项与命令行中的相同。

每当您做出更改,该脚本都会运行,以便您立即查看处理效果。

您可以将需要使用的离群值清理方法添加到预处理脚本并保存脚本。

section

归一化

如果各项特征的值范围不同,但您希望对每项特征予以同等考量,则可以借助归一化方法。

假设您要创建一个预测性维护模型。为识别故障预测变量,您使用传感器记录振动频率和压强。简单而言,偏离正常范围可能表示存在问题,与正常范围的差距则可能代表问题的严重性。振动频率的正常范围可能是 10–800 Hz,而压强的正常范围则可能接近 10–30 psi。为在同一模型中使用从这些测量值中提取的特征,您需要归一化数据集,以确保数据“公平竞争”。

何时归一化数据?一般而言,当不同变量的绝对值或范围相差一个或多个数量级时,应考虑归一化数据。但是,归一化与否还取决于您在分析中是否仍要使用单位。非归一化数据在其他预处理步骤中是有用的,因为您仍然可以基于这些数据进行“推理”。归一化通常是在特征工程之前执行的最终步骤之一。

语法

N = normalize(A)
N = normalize(A,dim)
N = normalize(___,method)
N = normalize(___,method,methodtype)
N = normalize(___,'DataVariables',datavars)