导入具有混合数据类型的CSV文件

时间:2011-01-20 13:43:34

标签: parsing matlab file-io csv import

我正在使用MATLAB几天,而且我很难将CSV文件导入矩阵。

我的问题是我的CSV文件几乎只包含字符串和一些整数值,因此csvread()不起作用。 csvread()仅与整数值相关。

如何将我的字符串存储在某种二维数组中,以便可以自由访问每个元素?

以下是符合我需求的示例CSV:

04;abc;def;ghj;klm;;;;;
;;;;;Test;text;0xFF;;
;;;;;asdfhsdf;dsafdsag;0x0F0F;;

主要是空单元格和单元格内的文本。 如您所见,结构可能会有所不同。

9 个答案:

答案 0 :(得分:51)

如果您知道CSV文件中将包含多少列数据,则只需拨打textscan Amro suggests就可以轻松调用fgetl

但是,如果您不知道先验文件中有多少列,您可以使用更常规的方法,就像我在以下函数中所做的那样。我首先使用函数textscan将文件的每一行读入单元格数组。然后我使用函数str2double使用预定义的字段分隔符将每一行解析为单独的字符串,并将整数字段视为现在的字符串(稍后可将它们转换为数值)。以下是生成的代码,放在函数read_mixed_csv中:

function lineArray = read_mixed_csv(fileName, delimiter)

  fid = fopen(fileName, 'r');         % Open the file
  lineArray = cell(100, 1);           % Preallocate a cell array (ideally slightly
                                      %   larger than is needed)
  lineIndex = 1;                      % Index of cell to place the next line in
  nextLine = fgetl(fid);              % Read the first line from the file
  while ~isequal(nextLine, -1)        % Loop while not at the end of the file
    lineArray{lineIndex} = nextLine;  % Add the line to the cell array
    lineIndex = lineIndex+1;          % Increment the line index
    nextLine = fgetl(fid);            % Read the next line from the file
  end
  fclose(fid);                        % Close the file

  lineArray = lineArray(1:lineIndex-1);              % Remove empty cells, if needed
  for iLine = 1:lineIndex-1                          % Loop over lines
    lineData = textscan(lineArray{iLine}, '%s', ...  % Read strings
                        'Delimiter', delimiter);
    lineData = lineData{1};                          % Remove cell encapsulation
    if strcmp(lineArray{iLine}(end), delimiter)      % Account for when the line
      lineData{end+1} = '';                          %   ends with a delimiter
    end
    lineArray(iLine, 1:numel(lineData)) = lineData;  % Overwrite line data
  end

end

对问题中的示例文件内容运行此函数会产生以下结果:

>> data = read_mixed_csv('myfile.csv', ';')

data = 

  Columns 1 through 7

    '04'    'abc'    'def'    'ghj'    'klm'    ''            ''        
    ''      ''       ''       ''       ''       'Test'        'text'    
    ''      ''       ''       ''       ''       'asdfhsdf'    'dsafdsag'

  Columns 8 through 10

    ''          ''    ''
    '0xFF'      ''    ''
    '0x0F0F'    ''    ''

结果是一个3乘10的单元阵列,每个单元格有一个字段,其中缺少的字段由空字符串''表示。现在,您可以访问每个单元格或单元格组合,以根据需要对其进行格式化。例如,如果要将第一列中的字段从字符串更改为整数值,可以使用函数NaN,如下所示:

>> data(:, 1) = cellfun(@(s) {str2double(s)}, data(:, 1))

data = 

  Columns 1 through 7

    [  4]    'abc'    'def'    'ghj'    'klm'    ''            ''        
    [NaN]    ''       ''       ''       ''       'Test'        'text'    
    [NaN]    ''       ''       ''       ''       'asdfhsdf'    'dsafdsag'

  Columns 8 through 10

    ''          ''    ''
    '0xFF'      ''    ''
    '0x0F0F'    ''    ''

请注意,空字段会产生{{3}}个值。

答案 1 :(得分:20)

鉴于你发布的样本,这个简单的代码应该完成这项工作:

fid = fopen('file.csv','r');
C = textscan(fid, repmat('%s',1,10), 'delimiter',';', 'CollectOutput',true);
C = C{1};
fclose(fid);

然后您可以根据类型格式化列。例如,如果第一列是全部整数,我们可以将其格式化为:

C(:,1) = num2cell( str2double(C(:,1)) )

同样,如果您希望将第8列从十六进制转换为十进制,则可以使用HEX2DEC:

C(:,8) = cellfun(@hex2dec, strrep(C(:,8),'0x',''), 'UniformOutput',false);

生成的单元格数组如下所示:

C = 
    [  4]    'abc'    'def'    'ghj'    'klm'    ''            ''                []    ''    ''
    [NaN]    ''       ''       ''       ''       'Test'        'text'        [ 255]    ''    ''
    [NaN]    ''       ''       ''       ''       'asdfhsdf'    'dsafdsag'    [3855]    ''    ''

答案 2 :(得分:14)

在R2013b或更高版本中,您可以使用表格:

>> table = readtable('myfile.txt','Delimiter',';','ReadVariableNames',false)
>> table = 

    Var1    Var2     Var3     Var4     Var5        Var6          Var7         Var8      Var9    Var10
    ____    _____    _____    _____    _____    __________    __________    ________    ____    _____

      4     'abc'    'def'    'ghj'    'klm'    ''            ''            ''          NaN     NaN  
    NaN     ''       ''       ''       ''       'Test'        'text'        '0xFF'      NaN     NaN  
    NaN     ''       ''       ''       ''       'asdfhsdf'    'dsafdsag'    '0x0F0F'    NaN     NaN  

这是more info

答案 3 :(得分:7)

使用xlsread,它在.csv文件上的效果与在.xls文件上的效果一样。指定您想要三个输出:

[num char raw] = xlsread('your_filename.csv')

它将为您提供仅包含数字数据(num)的数组,仅包含字符数据(char)的数组以及包含与.csv布局(原始)格式相同的所有数据类型的数组。

答案 4 :(得分:6)

您是否尝试过使用文件交换中的“CSVIMPORT”功能?我自己没有尝试过,但它声称要处理文本和数字的所有组合。

http://www.mathworks.com/matlabcentral/fileexchange/23573-csvimport

答案 5 :(得分:4)

根据文件的格式, importdata 可能有效。

您可以将字符串存储在单元格数组中。输入“doc cell”以获取更多信息。

答案 6 :(得分:2)

我建议查看数据集数组。

数据集数组是Statistics Toolbox附带的数据类型。 它专门用于将异构数据存储在单个容器中。

Statistics Toolbox演示页面包含几个显示一些数据集阵列功能的视频。第一个标题为“数据集阵列简介”。第二个标题是“加入简介”。

http://www.mathworks.com/products/statistics/demos.html

答案 7 :(得分:1)

如果您的输入文件具有以逗号分隔的固定数量的列,并且您知道哪些列是字符串,则最好使用该函数

textscan()

请注意,您可以指定一种格式,在该格式中,您可以读取字符串中的最大字符数,或者直到找到分隔符(逗号)。

答案 8 :(得分:0)

% Assuming that the dataset is ";"-delimited and each line ends with ";"
fid = fopen('sampledata.csv');
tline = fgetl(fid);
u=sprintf('%c',tline); c=length(u);
id=findstr(u,';'); n=length(id);
data=cell(1,n);
for I=1:n
    if I==1
        data{1,I}=u(1:id(I)-1);
    else
        data{1,I}=u(id(I-1)+1:id(I)-1);
    end
end
ct=1;
while ischar(tline)
    ct=ct+1;
    tline = fgetl(fid);
    u=sprintf('%c',tline);
    id=findstr(u,';');
    if~isempty(id)
        for I=1:n
            if I==1
                data{ct,I}=u(1:id(I)-1);
            else
                data{ct,I}=u(id(I-1)+1:id(I)-1);
            end
        end
    end
end
fclose(fid);