35 votes

Importer un fichier CSV avec des types de données mixtes

Je travaille avec MATLAB depuis quelques jours et j'ai des difficultés à importer un fichier CSV dans une matrice.

Mon problème est que mon fichier CSV ne contient pratiquement que des chaînes de caractères et quelques valeurs entières, de sorte que csvread() ne fonctionne pas. csvread() ne s'entend qu'avec des valeurs entières.

Comment puis-je stocker mes chaînes de caractères dans une sorte de tableau à deux dimensions pour avoir un accès libre à chaque élément ?

Voici un exemple de CSV pour mes besoins :

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

L'essentiel, ce sont les cellules vides et les textes à l'intérieur des cellules. Comme vous le voyez, la structure peut varier.

3 votes

Jetez un coup d'œil à textscan > mathworks.com/help/techdoc/ref/textscan.html

2 votes

Vous devriez poster quelques lignes de votre fichier CSV afin que nous puissions nous faire une idée de la structure du fichier (les chaînes de caractères sont-elles citées avec le symbole ' ou " contiennent-ils des virgules à l'intérieur des citations, les valeurs entières sont-elles également citées, y a-t-il des délimiteurs échappés tels que "this is \"an example\"" etc...)

0 votes

C'est fait :) J'espère que cela vous aidera un peu

51voto

gnovice Points 70970

Dans le cas où vous savez combien de colonnes de données il y aura dans votre fichier CSV, un simple appel à textscan comme Amro suggère sera votre meilleure solution.

Cependant, si vous ne savez pas a priori combien de colonnes il y a dans votre fichier, vous pouvez utiliser une approche plus générale comme je l'ai fait dans la fonction suivante. J'ai d'abord utilisé la fonction fgetl pour lire chaque ligne du fichier dans un tableau de cellules. Ensuite, j'ai utilisé la fonction textscan pour analyser chaque ligne en chaînes de caractères séparées en utilisant un délimiteur de champ prédéfini et en traitant les champs entiers comme des chaînes de caractères pour le moment (ils peuvent être convertis en valeurs numériques plus tard). Voici le code résultant, placé dans une fonction 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

L'exécution de cette fonction sur le contenu du fichier échantillon de la question donne ce résultat :

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

Le résultat est un tableau de 3 cellules sur 10, avec un champ par cellule, les champs manquants étant représentés par la chaîne vide. '' . Vous pouvez maintenant accéder à chaque cellule ou à une combinaison de cellules pour les formater comme vous le souhaitez. Par exemple, si vous souhaitez transformer les champs de la première colonne, qui sont des chaînes de caractères, en valeurs entières, vous pouvez utiliser la fonction str2double comme suit :

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

Notez que les champs vides donnent lieu à NaN valeurs.

1 votes

Voir également la solution de @AndyCampbell ci-dessous pour les versions plus récentes de Matlab : stackoverflow.com/a/19642332/232610

0 votes

Joli. Cependant, Textscan n'aime pas les entrées vides. Si le fichier csv scanné contient des lignes vides, la procédure échoue. Je conseillerais de remplacer lineArray = lineArray(1:lineIndex-1); par ind = all(cellfun(@isempty,lineArray),2); lineArray = lineArray(~ind);

0 votes

Vous pouvez également utiliser strsplit() avec le CollapseDelimiters paramètre réglé sur false pour tokeniser chaque ligne du fichier csv. Matlab, par défaut, fusionne les délimiteurs consécutifs. Avec la valeur false, le résultat est le suivant : {'' '' '' '' '' 'Test' 'text' '0xFF' '' ''} pour la commande strsplit(';;;;;Test;text;0xFF;;', ';', 'CollapseDelimiters', false)

20voto

Amro Points 72743

Compte tenu de l'échantillon que vous avez posté, ce code simple devrait faire l'affaire :

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

Ensuite, vous pouvez formater les colonnes en fonction de leur type. Par exemple, si la première colonne est constituée de tous les nombres entiers, nous pouvons la formater comme suit :

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

De même, si vous souhaitez convertir la 8e colonne de l'hexagone en décimales, vous pouvez utiliser HEX2DEC :

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

Le tableau de cellules qui en résulte se présente comme suit :

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

14voto

Andy Campbell Points 713

Dans la version R2013b ou ultérieure, vous pouvez utiliser un tableau :

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

Voici plus d'infos .

7voto

Blue Points 41

Utilisez xlsread, qui fonctionne aussi bien sur les fichiers .csv que sur les fichiers .xls. Spécifiez que vous voulez trois sorties :

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

et vous obtiendrez un tableau contenant uniquement les données numériques (num), un tableau contenant uniquement les données de type caractère (char) et un tableau contenant tous les types de données dans le même format que la présentation .csv (raw).

6voto

Ghaul Points 2871

Avez-vous essayé d'utiliser la fonction "CSVIMPORT" qui se trouve dans l'échange de fichiers ? Je ne l'ai pas essayée moi-même, mais elle prétend traiter toutes les combinaisons de texte et de chiffres.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X