Matlab表/数据集类型优化

Sai*_*rus 11 matlab tuples matrix dataset data-structures

我正在为Matlab中的"观察变量"表搜索一些优化的数据类型,这些数据类型可以通过列(通过变量)和行(通过观察)快速轻松地访问.

这是现有Matlab数据类型的比较:

  1. 矩阵非常快,hovewer,它的维度没有内置的索引标签/枚举,你不能总是按列索引记住变量名.
  2. 具有非常糟糕的性能,尤其是在for循环中读取单个行/列时(我认为它运行一些慢转换方法,并且设计为更像Excel).
  3. 标量结构(列数组的结构)数据类型 - 作为向量快速逐列访问变量,但是慢慢地逐行转换为观察.
  4. 非标量结构(结构数组) - 快速逐行访问观察值作为向量,但缓慢的逐列转换为变量.

我想知道我是否可以使用一些更简单和优化的Table数据类型,如果我只想将行数和列变量索引与只有数值变量-OR-任何变量类型相结合.

测试脚本的结果:

----
TEST1 - reading individual observations
Matrix: 0.072519 sec
Table: 18.014 sec
Array of structures: 0.49896 sec
Structure of arrays: 4.3865 sec
----
TEST2 - reading individual variables
Matrix: 0.0047834 sec
Table: 0.0017972 sec
Array of structures: 2.2715 sec
Structure of arrays: 0.0010529 sec
Run Code Online (Sandbox Code Playgroud)

测试脚本:

Nobs = 1e5; % number of observations-rows
varNames = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'};
Nvar = numel(varNames); % number of variables-colums

M = randn(Nobs, Nvar); % matrix

T = array2table(M, 'VariableNames', varNames); % table

NS = struct; % nonscalar structure = array of structures
for i=1:Nobs
    for v=1:Nvar
        NS(i).(varNames{v}) = M(i,v);
    end
end

SS = struct; % scalar structure = structure of arrays
for v=1:Nvar
    SS.(varNames{v}) = M(:,v);
end

%% TEST 1 - reading individual observations (row-wise)
disp('----'); disp('TEST1 - reading individual observations');

tic; % matrix
for i=1:Nobs
   x = M(i,:); end
disp(['Matrix: ', num2str(toc()), ' sec']);

tic; % table
for i=1:Nobs
   x = T(i,:); end
disp(['Table: ', num2str(toc), ' sec']);

tic;% nonscalar structure = array of structures
for i=1:Nobs
    x = NS(i); end
disp(['Array of structures: ', num2str(toc()), ' sec']);

tic;% scalar structure = structure of arrays 
for i=1:Nobs
    for v=1:Nvar
        x.(varNames{v}) = SS.(varNames{v})(i);
    end
end
disp(['Structure of arrays: ', num2str(toc()), ' sec']);

%% TEST 2 - reading individual variables (column-wise)
disp('----'); disp('TEST2 - reading individual variables');

tic; % matrix
for v=1:Nvar
   x = M(:,v); end
disp(['Matrix: ', num2str(toc()), ' sec']);

tic; % table
for v=1:Nvar
   x = T.(varNames{v}); end
disp(['Table: ', num2str(toc()), ' sec']);

tic; % nonscalar structure = array of structures
for v=1:Nvar
    for i=1:Nobs
        x(i,1) = NS(i).(varNames{v});
    end
end
disp(['Array of structures: ', num2str(toc()), ' sec']);

tic; % scalar structure = structure of arrays
for v=1:Nvar
    x = SS.(varNames{v}); end
disp(['Structure of arrays: ', num2str(toc()), ' sec']);
Run Code Online (Sandbox Code Playgroud)

gno*_*ice 9

我会使用矩阵,因为它们是最快和最直接使用的,然后创建一组枚举列标签,以使索引列更容易.以下是一些方法:


使用containers.Map对象:

给定您的变量名称,并假设它们按照从第1列到第1列的顺序N映射,您可以创建如下映射:

varNames = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'};
col = containers.Map(varNames, 1:numel(varNames));
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用地图按变量名访问数据列.例如,如果你想获取变量列AC(即第一和第三)从矩阵中data,你可以这样做:

subData = data(:, [col('A') col('C')]);
Run Code Online (Sandbox Code Playgroud)


使用struct:

您可以创建一个结构,其中变量名称作为其字段,相应的列索引作为其值,如下所示:

enumData = [varNames; num2cell(1:numel(varNames))];
col = struct(enumData{:});
Run Code Online (Sandbox Code Playgroud)

以下是col包含的内容:

struct with fields:

  A: 1
  B: 2
  C: 3
  D: 4
  E: 5
  F: 6
  G: 7
  H: 8
  I: 9
  J: 10
  K: 11
  L: 12
  M: 13
  N: 14
  O: 15
Run Code Online (Sandbox Code Playgroud)

你会访问列A,C如下所示:

subData = data(:, [col.A col.C]);
% ...or with dynamic field names...
subData = data(:, [col.('A') col.('C')]);
Run Code Online (Sandbox Code Playgroud)


制作一堆变量:

可以在工作区中为每个列名创建一个变量,并将列索引存储在其中.这将使用更多变量污染您的工作区,但为您提供了一种访问列数据的简洁方法.这是一个简单的方法,使用备受诟病的eval:

enumData = [varNames; num2cell(1:numel(varNames))];
eval(sprintf('%s=%d;', enumData{:}));
Run Code Online (Sandbox Code Playgroud)

访问列A并且C很简单:

subData = data(:, [A C]);
Run Code Online (Sandbox Code Playgroud)


使用枚举类:

这可能是一个很好的过度杀伤剂,但如果您要对许多分析使用相同的列标签和索引映射,您可以创建一个枚举类,将其保存在MATLAB路径的某个位置,并且永远不必担心定义您的列枚举再次.例如,这是一个ColVar包含15个枚举值的类:

classdef ColVar < double
  enumeration
    A (1)
    B (2)
    C (3)
    D (4)
    E (5)
    F (6)
    G (7)
    H (8)
    I (9)
    J (10)
    K (11)
    L (12)
    M (13)
    N (14)
    O (15)
  end
end
Run Code Online (Sandbox Code Playgroud)

你会访问列A,C如下所示:

subData = data(:, [ColVar.A ColVar.C]);
Run Code Online (Sandbox Code Playgroud)