i有一个包含各种数据类型的表。例如,
chars = {'a'; 'bc'; 'de'};
nums = [1; 20; 300];
tbl = table(chars, nums);
我想将所有数值列转换为字符数组变量。这样,我的意思是结果应该等同于我使用:
初始化了表。nums = {'1'; '20', '300'};
tbl = table(chars, nums);
我想尽可能快地这样做,因为我有一张潜在的数百万行。
当前工作解决方案:
首先,我得到数值列,在此示例的情况下,这将是第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
您可以看到这些方法基本上是等效的,正如它们的相似性所期望的那样。
有人知道一种更快的方法将表中的所有数据转换为字符数组变量类型吗?我曾经想过通过分类,但不确定如何继续此处。
我更喜欢与R2015B兼容的解决方案。
注意:重要的是我的数据包含混合类型,因为我不能(也不想)在整个表上使用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 ( '%in', tbl.nums ), '%s', 'delimiter', 'n' );
f4 = @() textscan ( sprintf ( '%in', 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
,按照匹配的检查,它们都是相同的。
如果您的数据是非整数 ->您需要更改Sprintf语句,我将其作为整数确保确保结果证明结果相同。