将数值 table 值转换为字符数组的最快方法

Fastest way to convert numerical table values to character arrays

我有一个 table,其中包含各种数据类型。例如,

chars = {'a'; 'bc'; 'de'};
nums = [1; 20; 300];
tbl = table(chars, nums);

我想将所有数字列转换为字符数组变量。通过这个,我的意思是结果应该等同于如果我使用

初始化了 table
nums = {'1'; '20', '300'};
tbl = table(chars, nums); 

我想尽快执行此操作,因为我有一个 table 可能有数百万行。

当前工作解决方案:

首先,我得到数字列,在这个例子中,这将是第 2 列...

% Get the columns numbers which are numerical. This works fine, although a bit clunky.
numcols = find(varfun(@isnumeric, tbl(1,:), 'output', 'uniform'));    
colnames = tbl.Properties.VariableNames(numcols); % Get the corresponding column names

然后,我有几种方法可以将这些数字列转换为字符数组类型,它们都涉及循环数字列并使用一些其他变相循环 ___fun 函数...

  1. arrayfun

    for ii = 1:numel(colnames)
        % This arrayfun is *slow* for large tables
        tbl.(colnames{ii}) = arrayfun( @num2str, tbl.(colnames{ii}), 'uniformoutput', 0 );
    end
    
  2. num2cellcellfun

    for ii = 1:numel(colnames)
        % num2cell is relatively quick
        tbl.(colnames{ii}) = num2cell( tbl.(colnames{ii}) ); 
        % cellfun is about as slow as arrayfun, as might be expected
        tbl.(colnames{ii}) = cellfun( @num2str, tbl.(colnames{ii}), 'uniformoutput', 0 );
    end
    

下面的速度测试,请注意我只做一列和 1e5 个元素,而实际上我想做很多列和可能多十倍的行,所以你可以清楚地看到速度问题...

% Setup
nums = (1:1e5).'; tbl = table(nums);
% Functions
f1 = @() arrayfun( @num2str, tbl.nums, 'uni', 0 );
f2 = @() cellfun( @num2str, num2cell(tbl.nums), 'uni', 0 );
% Timing
timeit(f1) % >> 5.15 sec
timeit(f2) % >> 5.16 sec

你可以看到这些方法基本上是等价的,正如它们的相似性所预料的那样。

有人知道将 table 中的所有数据转换为字符数组变量类型的更快方法吗? 我曾想通过分类,但不确定如何继续那里。

我更喜欢与 R2015b 兼容的解决方案。

注意:我的数据包含混合类型是相关的,因为我不能(也不想)在整个 table.

上使用 varfun( ... )

您可以使用 sprintf 转换为大型字符数组,然后使用 strread 读回以放入元胞数组:

% Setup
nums = (1:1e5).'; tbl = table(nums);
% Functions
f1 = @() arrayfun( @num2str, tbl.nums, 'uni', 0 );
f2 = @() cellfun( @num2str, num2cell(tbl.nums), 'uni', 0 );
f3 = @() strread ( sprintf ( '%i\n', tbl.nums ), '%s', 'delimiter', '\n' );
f4 = @() textscan ( sprintf ( '%i\n', tbl.nums ), '%s', 'delimiter', '\n' );
% Timing
timeit(f1) % 
timeit(f2) % 
timeit(f3) % 
timeit(f4) %


r1 = feval(f1);
r2 = feval(f2);
r3 = feval(f3);
r4 = feval(f4);

% check they are equal
isequal ( r1, r2 )
isequal ( r3, r1 )
isequal ( r4{1}, r1 )

在装有 R2015b 的计算机上,我得到:

f1 -> 3.78 seconds
f2 -> 3.79 seconds
f3 -> 0.10 seconds
f4 -> 0.07 seconds

并且根据 isequal 检查,它们都是相同的。

如果您的数据不是整数 -> 您需要更改 sprintf 语句,我将其设置为整数以确保 isequal 验证结果相同。