动机

部分项目的测试代码使用的还是matlab, 但是由于excel处理数据的便利, 以及对于手工输入数据的厌恶, 我研究了下如何将计算得到的保存在mat文件中的数据导出到xls或者xlsx文件里.

环境

Ubuntu 18.04, MATLAB R2018a.

方法

首先不得不说, matlab的帮助文档真的是很详细, 很全面, 尤其是最近的几个版本, 中文文档也愈发的齐全起来, 没事多查文档还是很有用的.
首先分析下我们的数据, 从我实际使用来看, 其实主要有字符串, 数字这两种类型的数据., 为了方便整合, 以及一次性写入, 我们可以使用matlab的元胞数组来构造整体表格数据.

元胞数组是一种包含名为元胞的索引数据容器的数据类型,其中的每个元胞都可以包含任意类型的数据。元胞数组通常包含不同长度的字符向量列表,或字符串数字的混合,或不同大小的数值数组。 通过将索引括在圆括号 **()** 中可以引用元胞集。使用花括号 **{}** 进行索引来访问元胞的内容

通过逐行构造数据, 我们最终可以得到一个包含了所有想要的数据的元胞数组, 这里有模型名字, 有模型结果, 也有不同指标的名字. 我们需要做的就是将这个数组写入xls或者xlsx文件中.
我们可以到文档中搜索与 excel 相关的内容.
image.png
这里推荐我们使用 writetable 函数.
为了了解该函数的用法, 我们直接看他的文档 (这里贴的是R2019a的文档, 因为可以直接在浏览器里收到, 基本内容没变)可以了解到, 他是把一个表数据写入到文件中.

writetable 根据指定扩展名确定文件格式。扩展名必须是下列格式之一:

  • .txt.dat.csv(适用于带分隔符的文本文件)
  • .xls.xlsm.xlsx(适用于 Excel® 电子表格文件)
  • .xlsb(适用于安装了 Windows® Excel 的系统上支持的 Excel 电子表格文件)

而我们现在的数据是元胞数组, 并不能直接写入, 会提示你如下错误:

  1. Undefined function 'write' for input arguments of type 'cell'.
  2. Error in writetable (line 124)
  3. write(a,filename,varargin{:})

所以我们需要将元胞数组转化为表数据. 在页面https://ww2.mathworks.cn/help/matlab/tables.html中可以看到, 这里展示了关于表数据的各种操作, 其中就有使用元胞数组创建表数据, 也就是使用函数 [cell2table](https://ww2.mathworks.cn/help/matlab/ref/cell2table.html) .
可以了解到, 表数据是以列为基准的, 所以对于每一列, 会指定对应的名字. 如果不指定, 会按照默认的格式创建. 我们因为数据的第一行实际上就可以认为是列数据的名字, 所以可以参考给出的示例里的 将列标题转换为变量名称 这一小节的代码.

将元胞数组转换为表,然后包括元胞数组的第一行作为表的变量名称。 创建一个元胞数组,其中第一行包含用于标识列标题的字符向量。

示例代码如下:

  1. Patients = {'Gender' 'Age' 'Height' 'Weight' 'Smoker';...
  2. 'M' 38 71 176 true;...
  3. 'M' 43 69 163 false;...
  4. 'M' 38 64 131 false;...
  5. 'F' 38 64 131 false;...
  6. 'F' 40 67 133 false;...
  7. 'F' 49 64 119 false}
  8. C = Patients(2:end,:);
  9. T = cell2table(C)
  10. T.Properties.VariableNames = Patients(1,:)

即先按照正常的方式转换数据, 这里把第一行排除掉了, 最后通过修改表的属性来讲第一行替换为原始的数据.由此, 我们可以得到真正可以写入表格的数据了.

代码

  1. data_name = 'DUT-OMRON';
  2. output_folder = './Results/';
  3. mat_path = [output_folder, data_name, '/'];
  4. fprintf("Dataset Name: %s\n", data_name);
  5. fprintf("Output Folder Name: %s\n", output_folder);
  6. fprintf("Mat File Path: %s\n", mat_path);
  7. if(isfolder(mat_path) && ~isempty(mat_path))
  8. mat_list = dir(mat_path);
  9. mat_list = mat_list(3:end, 1);
  10. else
  11. fprintf("%s should be a folder that has some files\n", mat_path);
  12. end
  13. num_model = length(mat_list);
  14. output_data = cell(num_model + 1, 7);
  15. output_data(1, :) = {'Model', 'MaxF', 'MeanF', 'WFm', 'Emeasure', 'Smeasure', 'MAE'};
  16. for i = 1 : num_model
  17. mat_data = load([mat_path, mat_list(i).name]);
  18. model_name = strsplit(mat_list(i).name, '.');
  19. output_data(i + 1, :) = { ...
  20. model_name{1}, ...
  21. mat_data.MaxFmeasure, ...
  22. mat_data.mean_Fmeasure(3), ...
  23. mat_data.wFmeasure, ...
  24. mat_data.Emeasure, ...
  25. mat_data.S_measure, ...
  26. mat_data.MAE
  27. };
  28. end
  29. output_data_model = output_data(2:end, :);
  30. output_table = cell2table(output_data_model);
  31. output_table.Properties.VariableNames = output_data(1, :);
  32. filename = [output_folder, 'record.xls'];
  33. % 这里针对不同的sheet使用对应的data_name作为名字
  34. writetable(output_table, filename, 'Sheet', data_name, 'Range', 'A1')

参考链接