Импорт файла CSV со смешанными типами данных - PullRequest
35 голосов
/ 20 января 2011

Я работаю с MATLAB несколько дней, и у меня возникают трудности с импортом CSV-файла в матрицу.

Моя проблема в том, что мой CSV-файл содержит почти только строки и некоторые целочисленные значениятак что csvread() не работает.csvread() поддерживает только целочисленные значения.

Как я могу хранить свои строки в каком-то двумерном массиве, чтобы иметь свободный доступ к каждому элементу?

Вот пример CSV длямои потребности:

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

Главное - это пустые клетки и тексты внутри клеток.Как видите, структура может отличаться.

Ответы [ 9 ]

51 голосов
/ 26 января 2011

Для случая, когда вы знаете, сколько столбцов данных будет в вашем CSV-файле, одним простым вызовом textscan подобно Амро предполагает, что будет вашим лучшим решением.

Однако, если вы не знаете априори , сколько столбцов в вашем файле, вы можете использовать более общий подход, как я сделал в следующей функции.Сначала я использовал функцию fgetl, чтобы прочитать каждую строку файла в массив ячеек.Затем я использовал функцию textscan, чтобы проанализировать каждую строку в отдельные строки, используя предопределенный разделитель полей и пока что целочисленные поля считались строками (они могут быть позже преобразованы в числовые значения).Вот результирующий код, помещенный в функцию 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 с одним полем на ячейку, где пропущенные поля представлены пустой строкой ''.Теперь вы можете получить доступ к каждой ячейке или комбинации ячеек, чтобы отформатировать их, как вам нравится.Например, если вы хотите изменить поля в первом столбце со строк на целочисленные значения, вы можете использовать функцию str2double следующим образом:

>> 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'    ''    ''

Обратите внимание, что пустойрезультаты полей в NaN значениях.

20 голосов
/ 27 января 2011

Учитывая пример, который вы разместили, этот простой код должен выполнить работу:

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)) )

Аналогично, если вы хотите преобразовать восьмой столбец из шестнадцатеричного в десятичное, вы можете использовать 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]    ''    ''
14 голосов
/ 28 октября 2013

В 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  

Здесь больше информации .

7 голосов
/ 05 сентября 2012

Используйте xlsread, он работает так же хорошо для файлов .csv, как и для файлов .xls.Укажите, что вы хотите три вывода:

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

, и он даст вам массив, содержащий только числовые данные (num), массив, содержащий только символьные данные (char), и массив, содержащий все типы данныхв том же формате, что и макет .csv (raw).

6 голосов
/ 25 января 2011

Вы пытались использовать функцию "CSVIMPORT", найденную при обмене файлами?Я не пробовал сам, но он утверждает, что обрабатывает все комбинации текста и чисел.

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

4 голосов
/ 20 января 2011

В зависимости от формата вашего файла, importdata может работать.

Вы можете хранить строки в массиве ячеек.Для получения дополнительной информации введите «ячейка документа».

2 голосов
/ 21 января 2011

Я рекомендую взглянуть на массив набора данных.

Массив набора данных - это тип данных, который поставляется вместе с Statistics Toolbox.Он специально предназначен для хранения гетерогенных данных в одном контейнере.

Демонстрационная страница Statistics Toolbox содержит пару видео, в которых показаны некоторые функции массива набора данных.Первый из них называется «Введение в массивы наборов данных».Второй называется «Введение в соединения».

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

1 голос
/ 25 января 2011

Если во входном файле есть фиксированное количество столбцов, разделенных запятыми, и вы знаете, в каких столбцах есть строки, лучше всего использовать функцию

textscan()

Обратите внимание, что вы можете указать формат, в которомВы можете прочитать до максимального количества символов в строке или до тех пор, пока не будет найден разделитель (запятая).

0 голосов
/ 31 января 2011
% 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);
...