web-dev-qa-db-fra.com

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 contient presque uniquement des chaînes et des valeurs entières, de sorte que csvread() ne fonctionne pas. csvread() s'entend uniquement avec des valeurs entières.

Comment puis-je stocker mes chaînes dans une sorte de tableau à 2 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 est les cellules vides et les textes dans les cellules. Comme vous le voyez, la structure peut varier.

35
poeschlorn

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 meilleur Solution.

Cependant, si vous ne savez pas a priori combien de colonnes sont 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 distinctes en utilisant un délimiteur de champ prédéfini et en traitant les champs entiers comme des chaînes pour l'instant (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 d'exemple 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 cellules de 3 sur 10 avec un champ par cellule où les champs manquants sont représentés par la chaîne vide ''. Vous pouvez maintenant accéder à chaque cellule ou à une combinaison de cellules pour les formater à votre guise. Par exemple, si vous souhaitez modifier les champs de la première colonne de chaînes 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 entraînent des valeurs NaN .

51
gnovice

Compte tenu de l'exemple que vous avez publié, ce code simple devrait faire le travail:

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 entièrement composée d'entiers, nous pouvons la formater comme telle:

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

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

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

Le tableau de cellules résultant se présente comme suit:

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

Dans R2013b ou version ultérieure, vous pouvez utiliser une table:

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

14
Andy Campbell

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

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

et il vous donnera un tableau contenant uniquement les données numériques (num), un tableau contenant uniquement les données de caractère (char) et un tableau qui contient tous les types de données dans le même format que la disposition .csv (brut).

7
Blue

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

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

6
Ghaul

Selon le format de votre fichier, importdata peut fonctionner.

Vous pouvez stocker des chaînes dans un tableau de cellules. Tapez "doc cell" pour plus d'informations.

4
William Payne

Je recommande de regarder le tableau de l'ensemble de données.

Le tableau de l'ensemble de données est un type de données fourni avec Statistics Toolbox. Il est spécialement conçu pour stocker des données hétérogènes dans un seul conteneur.

La page de démonstration de Statistics Toolbox contient quelques vidéos qui montrent certaines des fonctionnalités du tableau de jeux de données. Le premier est intitulé "Une introduction aux tableaux de jeux de données". Le second est intitulé "Une introduction aux jointures".

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

2
richard willey

Si votre fichier d'entrée contient un nombre fixe de colonnes séparées par des virgules et que vous savez dans quelles colonnes se trouvent les chaînes, il est préférable d'utiliser la fonction

textscan()

Notez que vous pouvez spécifier un format dans lequel vous lisez jusqu'à un nombre maximum de caractères dans la chaîne ou jusqu'à ce qu'un délimiteur (virgule) soit trouvé.

1
Martin
% 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);
0
Y.T.