我正在尝试以其他应用程序可以理解的格式从 Matlab 导出数据... 为此,我需要更改 NaN
、Inf
和 -Inf
字符串(Matlab 默认打印此类值)到 //m
、//inf+
和 //Inf-
.
总的来说,我确实知道如何做到这一点。我在问如何(以及是否可能)在 Matlab 中利用一个特定的东西。实际问题位于最后一段。
我尝试了两种方法(代码如下)。
- 对数据 和
strrep()
输出使用sprintf()
。这是以逐行方式完成的,以节省内存。此解决方案比简单的fprintf()
花费的时间几乎多 10 倍。优点是内存开销小。 - 与选项1. 相同,但翻译是一次性完成整个数据。此解决方案速度更快,但容易出现内存不足异常。这种方法的问题是我不想不必要地复制数据。
代码:
rows = 50000 cols = 40 data = rand(rows, cols); % generate random matrix data([1 3 8]) = NaN; % insert some NaN values data([5 6 14]) = Inf; % insert some Inf values data([4 2 12]) = -Inf; % insert some -Inf values fid = fopen('data.txt', 'w'); %output file %% 0) Write data using default fprintf format = repmat('%g ', 1, cols); tic fprintf(fid, [format '\n'], data'); toc %% 1) Using strrep, writing line by line fprintf(fid, '\n'); tic for i = 1:rows fprintf(fid, '%s\n', strrep(strrep(strrep(sprintf(format, data(i, :)), 'NaN', '//m'), '-Inf', '//inf-'), 'Inf', '//inf+')); end toc %% 2) Using strrep, writing all at once fprintf(fid, '\n'); format = [format '\n']; tic fprintf(fid, '%s\n', strrep(strrep(strrep(sprintf(format, data'), 'NaN', '//m'), '-Inf', '//inf-'), 'Inf', '//inf+')); toc
输出:
Elapsed time is 1.651089 seconds. % Regular fprintf()
Elapsed time is 11.529552 seconds. % Option 1
Elapsed time is 2.305582 seconds. % Option 2
现在问题...
与简单的 fprintf()
相比,我对使用我的解决方案的内存开销和时间损失不满意。
我的理由是 'NaN'
、'Inf'
和 '-Inf'
字符串是保存在 *printf()
或 *2str()
实现。有什么办法可以在运行时改变它们的值吗?
例如,在 C# 中,我会更改 System.Globalization.CultureInfo.NumberFormat.NaNSymbol
等,如 here 所述。 .
最佳答案
在评论中提到的有限情况下,许多(未知,根据数据集变化)列可能完全是 NaN
(或 Inf
等),但是否则没有不需要的 NaN
值,另一种可能性是检查第一行数据,组装一个直接写入 \\m
字符串的格式字符串,然后使用它 while告诉 fprintf
忽略包含 NaN
或其他不需要的值的列。
y = ~isnan(data(1,:)); % find all non-NaN
format = sprintf('%d ',y); % print a 1/0 string
format = strrep(format,'1','%g');
format = strrep(format,'0','//m');
fid = fopen('data.txt', 'w');
fprintf(fid, [format '\n'], data(:,y)'); %pass only the non-NaN data
fclose(fid);
通过我对两列 NaN
的检查,这个 fprintf
与您的“常规”fprintf
几乎相同并且比循环更快- 不考虑生成format
的初始化步骤。如果您还必须考虑 +/- Inf
,那么将其设置为自动生成格式字符串会比较麻烦,但这当然是可能的。可能还有一种更简洁的方法来生成 format
。
工作原理:
您可以传入数据的子集,也可以将您喜欢的任何文本插入到格式字符串中,因此如果每一行在同一位置都有相同的所需“文本”(在本例中为 NaN
列和我们想要的“NaN”替换项),我们可以将我们想要的文本放在那个位置,然后首先不将这些数据部分传递给 fprintf
。在命令行上尝试的更简单示例:
x = magic(5);
x(:,3)=NaN
sprintf('%d %d ihatethrees %d %d \n',x(:,[1,2,4,5])');
关于matlab - 在 Matlab 中更改 fprintf() 的默认 NaN 表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25061400/