【问题标题】:Conditional text import or import by header name - MATLAB条件文本导入或按标题名称导入 - MATLAB
【发布时间】:2015-08-21 16:06:26
【问题描述】:

有没有办法在 MATLAB 中执行条件文本导入?例如使用此格式的制表符分隔的 .txt 文件:

Type    A   B   C   D   E
 A    5000  2   5   16  19
 A    5000  3   4   5   4
 A    5000  4   1   4   5
 B    500   19  8   2   7
 B    500   18  9   8   1
 B    500   2   9   13  2
 B    100   3   10  15  9
 B    5000  4   15  14  10

有没有办法只导入 A 列包含 '5000' 的那些行?

这优先于导入整个 .txt 文件并随后分离数据,因为实际上,我的文本文件相当大(每个约 200MB) - 但如果有办法快速做到这一点,那也将是一个合适的解决方案。

或者,是否有一种方法(类似于 R)可以使用 .txt 文件中包含的标头导入和处理数据?例如导入 'Type' 'A' 'B' 和 'D' 而忽略了上例中的 'C' 和 'E'。如果输入文件格式灵活,有时添加的附加列意味着它们的相对位置发生变化,则需要这样做。

【问题讨论】:

  • 如果您不告诉它有关文件结构/格式的更多详细信息,则没有内置方法可以执行这些操作。 Matlab 例程不像 R 中的例程那样自动化。您询问的两件事都可以通过textscan 直接完成,但您需要对您的文件做出一些假设和/或提供有关其构成的额外知识(例如,标题的长度、列的顺序)。否则,您需要通过创建自己的更高级别的例程来添加智能。

标签: matlab textscan


【解决方案1】:

您可以尝试逐行读取输入文件,检查该行是否包含引用列(本例中为第 2 列)中的引用值(本例中为 5000)。

如果是这样,您可以存储输入,否则,您将其丢弃。

在以下代码中,根据您的模板,您可以在代码开头定义引用值和引用列。

然后您可以将cellarray 输出转换为array

% Define the column index
col_idx=2
% Define the reference value
ref_value=5000
% Open input file
fid=fopen('in.txt');
% Read header
tline = fgetl(fid);
% Initialize conter
cnt=0;
% Initialize output variable
data=[];
% Read the file line by line
while 1
   % Read the line
   tline = fgetl(fid);
   % Check for the end of file
   if ~ischar(tline)
      break
   end
   % Get the line field
   c=textscan(tline,'%c%f%f%f%f%f')
   % If the seconf field contains the ref value, then store the inout data
   if(c{col_idx} == ref_value)
      data=[data;c]
   end
end
fclose(fid);
% Convert cell 2 array
c=data(:,2:end)
num_data=cell2mat(c)
% Convert first column to char
lab=char(data(:,1))

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    函数fgetl 用于从文本文件中读取单行,因此一种选择是编写一个循环,使用fgetl 连续读取单行并检查第一列之前是否包含“5000”决定是否将其包含在您的数据集中。

    这是 il_raffa 的回答中提出的解决方案。请注意,您实际上必须阅读整个文件,因为您使用fgetl 阅读了整行,然后在其上使用textscan!所以它肯定不会比读取整个文件然后过滤它更快(尽管它可能更节省内存)。

    您真正想要的是逐个字符地读取文件,如果您可以根据“A”列的值确定不会读取文件,则中止每一行。

    如果您正在编写 C 或其他低级语言,这可能比导入整个文件并随后对其进行过滤要快。但是,由于 MATLAB 引入的开销,几乎可以肯定的是,读取整个文件并在以后过滤它会更快、更容易。 textscan 函数在读取分隔文件方面非常好(而且速度很快),而且 200MB 真的没有那么大(例如,它可以轻松地放入任何现代计算机的内存中)。您应该确保在读取每个数据集后对其进行过滤,而不是读取所有数据集然​​后将它们全部过滤。

    关于您问题的第二部分,关于您是否可以选择性地导入列 - MATLAB 不提供执行此操作的内置方法。但是,如果您可以对文件格式做出一些假设,这并不是那么棘手。如果我们假设

    1. 文件采用逗号或制表符分隔格式
    2. 它有一个标题行

    然后您可以阅读标题行(使用fgetl),它将告诉您有多少列,以及它们的名称。然后,您可以使用该信息构建对textscan 的调用,该调用将读取分隔列,并过滤掉标题与您需要的不匹配的列。一个简单的版本可能看起来像 -

    function columns = import_columns(filename, headers)
    
      fid = fopen(filename);
      hdr = fgetl(fid);
      column_headers = regexp(hdr, '\t', 'split'); % split on tabs
    
      num_cols = length(column_headers);          
      format_str = repmat('%s', 1, num_cols); % create a string like '%s%s%s%s'
      columns = textscan(fid, format_str, 'Delimiter', '\t');
      fclose(fid);
    
      required_cols = ismember(column_headers, headers);
      columns(~required_cols) = []; % remove the columns you don't need
    
    end
    

    【讨论】:

      最近更新 更多