将数值 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
函数...
arrayfun
for ii = 1:numel(colnames)
% This arrayfun is *slow* for large tables
tbl.(colnames{ii}) = arrayfun( @num2str, tbl.(colnames{ii}), 'uniformoutput', 0 );
end
num2cell
和 cellfun
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 验证结果相同。
我有一个 table,其中包含各种数据类型。例如,
chars = {'a'; 'bc'; 'de'};
nums = [1; 20; 300];
tbl = table(chars, nums);
我想将所有数字列转换为字符数组变量。通过这个,我的意思是结果应该等同于如果我使用
初始化了 tablenums = {'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
函数...
arrayfun
for ii = 1:numel(colnames) % This arrayfun is *slow* for large tables tbl.(colnames{ii}) = arrayfun( @num2str, tbl.(colnames{ii}), 'uniformoutput', 0 ); end
num2cell
和cellfun
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 验证结果相同。