Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

使用 tall 数组处理无法放入内存的数据

tall 数组用于处理由 datastore 支持的无法放入内存的数据。数据存储允许以单个放入内存的小块形式处理大型数据集,而不是一次将整个数据集加载到内存中。tall 数组扩展了此功能,允许使用公共函数处理无法放入内存的数据。

什么是 tall 数组?

由于数据不是一次加载到内存中,因此 tall 数组在第一维中可以是任意大的(即可以具有任意数量的行)。tall 数组允许您以一种直观方式处理大型数据集,这与处理内存 MATLAB® 数组的方式类似;您不必为超大的数据量而专门编写特殊的代码(例如使用 MapReduce 之类的技术)。许多核心运算符和函数能够像处理内存数组一样处理 tall 数组。MATLAB 一次只处理一小块数据,而在后台执行所有的数据分块和处理,因此可以对大型数据集应用常见的运算表达式,如 A+B

tall 数组的好处

与内存数组不同,tall 数组通常不执行计算,直到您使用 gather 函数请求执行计算后才会真正计算。这种延迟计算可快速处理大型数据集。当使用 gather 最终请求输出时,MATLAB 尽可能合并排队的计算,并执行最少次数的数据遍历操作。遍历数据的次数会极大地影响执行时间,因此建议仅在必要时才请求输出。

注意

由于 gather 将结果作为内存 MATLAB 数组返回,因此遵循标准内存考量即可。如果 gather 返回的结果太大,MATLAB 可能会耗尽内存。

创建 tall 表

除了可以包含任意数量的行以外,tall 表与内存 MATLAB 常规表并无不同。要基于大型数据集创建 tall 表,首先需要为数据创建数据存储。如果数据存储 ds 包含表格数据,则 tall(ds) 返回包含这些数据的 tall 表或 tall 时间表。有关创建数据存储的详细信息,请参阅数据存储

创建指向航空公司航班数据表格文件的电子表格数据存储。对于包含文件集合的文件夹,可以指定整个文件夹位置,或使用通配符 '*.csv' 来包括数据存储中具有相同文件扩展名的多个文件。通过将 'NA' 值视为缺失数据来清理数据,以便 tabularTextDatastoreNaN 值替换它们。另外,将几个文本变量的格式设置为 %s,以便 tabularTextDatastore 将它们作为字符向量的元胞数组读取。

ds = tabularTextDatastore('airlinesmall.csv');
ds.TreatAsMissing = 'NA';
ds.SelectedFormats{strcmp(ds.SelectedVariableNames,'TailNum')} = '%s';
ds.SelectedFormats{strcmp(ds.SelectedVariableNames,'CancellationCode')} = '%s';

基于数据存储创建 tall 表。当对此 tall 表执行计算时,基础数据存储读取数据块并将其传递给 tall 表进行处理。数据存储和 tall 表都不保留任何基础数据。

tt = tall(ds)
tt =

  M×29 tall table 

    Year    Month    DayofMonth    DayOfWeek    DepTime    CRSDepTime    ArrTime    CRSArrTime    UniqueCarrier    FlightNum    TailNum    ActualElapsedTime    CRSElapsedTime    AirTime    ArrDelay    DepDelay    Origin    Dest     Distance    TaxiIn    TaxiOut    Cancelled    CancellationCode    Diverted    CarrierDelay    WeatherDelay    NASDelay    SecurityDelay    LateAircraftDelay
    ____    _____    __________    _________    _______    __________    _______    __________    _____________    _________    _______    _________________    ______________    _______    ________    ________    ______    _____    ________    ______    _______    _________    ________________    ________    ____________    ____________    ________    _____________    _________________

    1987    10       21            3             642        630           735        727          'PS'             1503         'NA'        53                   57               NaN         8          12          'LAX'     'SJC'    308         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       26            1            1021       1020          1124       1116          'PS'             1550         'NA'        63                   56               NaN         8           1          'SJC'     'BUR'    296         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       23            5            2055       2035          2218       2157          'PS'             1589         'NA'        83                   82               NaN        21          20          'SAN'     'SMF'    480         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       23            5            1332       1320          1431       1418          'PS'             1655         'NA'        59                   58               NaN        13          12          'BUR'     'SJC'    296         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       22            4             629        630           746        742          'PS'             1702         'NA'        77                   72               NaN         4          -1          'SMF'     'LAX'    373         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       28            3            1446       1343          1547       1448          'PS'             1729         'NA'        61                   65               NaN        59          63          'LAX'     'SJC'    308         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10        8            4             928        930          1052       1049          'PS'             1763         'NA'        84                   79               NaN         3          -2          'SAN'     'SFO'    447         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    1987    10       10            6             859        900          1134       1123          'PS'             1800         'NA'       155                  143               NaN        11          -1          'SEA'     'LAX'    954         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    :       :        :             :            :          :             :          :             :                :            :          :                    :                 :          :           :           :         :        :           :         :          :            :                   :           :               :               :           :                :
    :       :        :             :            :          :             :          :             :                :            :          :                    :                 :          :           :           :         :        :           :         :          :            :                   :           :               :               :           :                :

上面显示的结果指示行数 M 当前未知。MATLAB 显示了一些行,垂直省略号 : 则表示 tall 表中还存在许多当前未显示的行。

创建 tall 时间表

如果正在处理的数据有与每一行数据相关联的时间,则您可以使用 tall 时间表来处理这些数据。有关创建 tall 时间表的信息,请参阅扩展功能 (timetable)

在本例中,tall 表 tt 具有与每一行相关联的时间,但这些时间分解为几个表变量,例如 YearMonthDayofMonth 等。将所有这些日期时间信息组合为一个基于出发时间 DepTime 的新 tall 日期时间变量 Dates。然后,使用 Dates 作为行时间创建 tall 时间表。由于 Dates 是表中唯一的日期时间变量,因此 table2timetable 函数自动将其用于行时间。

hrs = (tt.DepTime - mod(tt.DepTime,100))/100;
mins = mod(tt.DepTime,100);
tt.Dates = datetime(tt.Year, tt.Month, tt.DayofMonth, hrs, mins, 0);
tt(:,1:8) = [];
TT = table2timetable(tt)
TT =

  M×21 tall timetable

            Dates           UniqueCarrier    FlightNum    TailNum    ActualElapsedTime    CRSElapsedTime    AirTime    ArrDelay    DepDelay    Origin    Dest     Distance    TaxiIn    TaxiOut    Cancelled    CancellationCode    Diverted    CarrierDelay    WeatherDelay    NASDelay    SecurityDelay    LateAircraftDelay
    ____________________    _____________    _________    _______    _________________    ______________    _______    ________    ________    ______    _____    ________    ______    _______    _________    ________________    ________    ____________    ____________    ________    _____________    _________________

    21-Oct-1987 06:42:00    'PS'             1503         'NA'        53                   57               NaN         8          12          'LAX'     'SJC'    308         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    26-Oct-1987 10:21:00    'PS'             1550         'NA'        63                   56               NaN         8           1          'SJC'     'BUR'    296         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    23-Oct-1987 20:55:00    'PS'             1589         'NA'        83                   82               NaN        21          20          'SAN'     'SMF'    480         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    23-Oct-1987 13:32:00    'PS'             1655         'NA'        59                   58               NaN        13          12          'BUR'     'SJC'    296         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    22-Oct-1987 06:29:00    'PS'             1702         'NA'        77                   72               NaN         4          -1          'SMF'     'LAX'    373         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    28-Oct-1987 14:46:00    'PS'             1729         'NA'        61                   65               NaN        59          63          'LAX'     'SJC'    308         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    08-Oct-1987 09:28:00    'PS'             1763         'NA'        84                   79               NaN         3          -2          'SAN'     'SFO'    447         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    10-Oct-1987 08:59:00    'PS'             1800         'NA'       155                  143               NaN        11          -1          'SEA'     'LAX'    954         NaN       NaN        0            'NA'                0           NaN             NaN             NaN         NaN              NaN              
    :                       :                :            :          :                    :                 :          :           :           :         :        :           :         :          :            :                   :           :               :               :           :                :
    :                       :      

创建 tall 数组

当从 tall 表或 tall 时间表中提取变量时,其结果是一个具有适当基础数据类型的 tall 数组。tall 数组可以是数字、逻辑、日期时间、持续时间、日历持续时间、分类、字符串或元胞数组。此外,可以按照 tA = tall(A) 条件将内存数组 A 转换为 tall 数组。内存数组 A 必须具有受支持的数据类型之一。

从 tall 时间表 TT 提取到港延误 ArrDelay。这将创建一个新的 tall 数组变量,其基础数据类型为 double。

a = TT.ArrDelay
a =

  M×1 tall double column vector

     8
     8
    21
    13
     4
    59
     3
    11
    :
    :

classUnderlyingisaUnderlying 函数可用于确定 tall 数组的基础数据类型。

延迟计算

tall 数组的一个重要特征是,在处理它们时大多数运算不会立即执行。这些运算看起来执行速度很快,是因为实际计算被延迟,直到特别请求时才执行计算。可以使用 gather 函数(将结果放入内存)或 write 函数(将结果写入磁盘)来启动 tall 数组的计算。这种延迟计算非常重要,因为对一个包含十亿行的 tall 数组执行一个类似 size(X) 的简单命令都是一次耗时的计算过程。

在处理 tall 数组时,MATLAB 跟踪要执行的所有操作。然后,此信息用于优化在使用 gather 函数请求输出时需要的遍历数据次数。因此,通常情况下应使用未经计算的 tall 数组,并仅在需要时请求输出。有关详细信息,请参阅 Lazy Evaluation of Tall Arrays

计算到港延误的均值和标准差。使用这些值来构建在均值的一个标准差内的延误的上限和下限阈值。请注意,每个运算的结果表示该数组尚未真正计算。

m = mean(a,'omitnan')
m =

  tall double

    ?

Preview deferred. Learn more.
s = std(a,'omitnan')
s =

  tall

    ?

Preview deferred. Learn more.
one_sigma_bounds = [m-s m m+s]
one_sigma_bounds =

  M×N×... tall array

    ?    ?    ?    ...
    ?    ?    ?    ...
    ?    ?    ?    ...
    :    :    :
    :    :    :

Preview deferred. Learn more.

gather 计算

延迟计算的好处是,当到了 MATLAB 执行计算的时间,通常可以合并多个运算,这样能最大限度地降低遍历数据的次数。因此,即使您执行大量运算,MATLAB 也仅在绝对必要时才会对数据进行额外次数的遍历。

gather 函数强制执行所有排队的运算,并将生成的输出载入内存中。因此,您可以考虑将 gather 作为 tall 数组和内存数组之间的桥梁。例如,您不能使用 tall 逻辑数组控制 ifwhile 循环,但一旦使用 gather 计算该数组后,它就成为内存逻辑数组,从而可用于上述控制目的。

由于 gather 在 MATLAB 中返回整个结果,因此应确保结果可放入内存中。

使用 gather 计算 one_sigma_bounds 并将结果放入内存中。在本例中,one_sigma_bounds 需要几个运算来计算,但 MATLAB 将这些运算合并在一次遍历数据中进行。由于此示例中的数据较小,因此 gather 可快速执行。然而,随着数据大小的增加,消除数据遍历会变得更有价值。

sig1 = gather(one_sigma_bounds)
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.5 sec
Evaluation completed in 1.8 sec

sig1 =

  -23.4572    7.1201   37.6975

如果要同时计算几个 tall 数组,可以给 gather 指定多个输入和输出。这种方法比多次调用 gather 更快。例如,计算最小和最大到港延误。如果单独计算,则计算每个值都需要遍历一次数据,总共两次。然而,同时计算两个值则仅需要一次数据遍历。

[max_delay, min_delay] = gather(max(a),min(a))
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.1 sec
Evaluation completed in 1.1 sec

max_delay =

        1014


min_delay =

   -64

这些结果表明,大多数航班平均延误约 7 分钟。但是在一个标准差之内,航班最多可能延误 37 分钟或早到 23 分钟。数据集中最快的航班大约早到一小时,而最迟的航班延误了许多小时。

保存、加载和检查 tall 数组

save 函数保存 tall 数组的状态,但不复制任何数据。生成的 .mat 文件通常很小。但是,原始数据文件必须保留在原位置,以便以后使用 load

write 函数创建数据的副本,并将副本保存为文件集合,这可能会占用大量磁盘空间。write 对 tall 数组执行所有待处理运算,以在写入前计算出值。一旦 write 完成数据复制,就与原始裸数据再无关联。因此,即使原始裸数据不再可用,也可以基于已写入的文件重新创建 tall 数组。

您可以创建一个指向文件写入位置的新数据存储,基于已写入的文件重新创建 tall 数组。此功能支持创建 tall 数组数据的检查点快照。创建检查点是保存数据预处理结果的好方法,这样数据就能以更有效的方式加载。

如果有一个 tall 数组 TA,则可以用以下命令将它写入文件夹 location

write(location,TA);

稍后,要基于写入的文件重新构造 TA,请使用命令:

ds = datastore(location);
TA = tall(ds);

此外,可以使用 write 函数触发 tall 数组的计算,并将结果写入磁盘。write 的这种用法类似于 gather,但 write 不会将任何结果写入内存中。

支持函数

大多数核心函数采用与处理内存数组相同的方法处理 tall 数组。但在某些情况下,函数处理 tall 数组的方法可能较为特殊,或存在局限性。可以通过查看函数参考页底部的扩展功能部分(例如,查看 filloutliers),判断函数是否支持 tall 数组,以及是否具有任何限制。

有关支持 tall 数组的所有 MATLAB 函数的过滤列表,请参阅函数列表(tall 数组)

有几个工具箱也支持 tall 数组,您可以使用这些工具箱完成诸如编写机器学习算法、部署独立 App 以及并行运行或在集群上运行计算之类的任务。有关详细信息,请参阅Extend Tall Arrays with Other Products

另请参阅

| | | |

相关主题