2013-10-10 6 views
5

Je suis nouveau à MATLAB et j'ai du mal à comprendre les subtilités entre les opérations de type array et wise. Je travaille avec un grand ensemble de données et j'ai trouvé que les méthodes les plus simples ne sont pas toujours les plus rapides. J'ai un très grand réseau de cellules de cordes, comme dans cet exemple simplifié:Sous-chaînes d'une matrice de cellules dans Matlab

% A vertical array of same-length strings 
CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'}; 

Je suis en train d'extraire un tableau de sous-chaînes, par exemple:

'a1' 
'b1' 
'c1' 
'd1' 

Je suis assez satisfait une référence élément par élément comme celui-ci:

% Simple element-wise substring operation 
MySubString = CellArrayOfStrings{2}(3:4); % Expected result is 'b1' 

Mais je ne peux pas travailler la notation pour les référencer en une seule fois, comme ceci:

% Desired result is 'a1','b1','c1','d1' 
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation! 

Je sais que Matlab est capable d'effectuer des opérations de sage de tableau très rapides, comme strcat, donc j'espérais une technique qui fonctionne à une vitesse similaire:

% An array-wise operation which works quickly 
tic 
speedTest = strcat(CellArrayOfStrings,'hello'); 
toc % About 2 seconds on my machine with >500K array elements 

Toutes les boucles for et Les fonctions qui utilisent l'itération en coulisses J'ai essayé de courir trop lentement avec mon jeu de données. Y a-t-il une notation en tableau qui ferait cela? Est-ce que quelqu'un serait capable de corriger ma compréhension des opérations élément par élément et par groupe? Merci beaucoup!

Répondre

4

Je ne peux pas travailler la notation pour les référencer en une seule fois, comme ceci:

MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!

Ceci est parce que les accolades ({}) retourne un comma-separated list, ce qui équivaut pour écrire le contenu de ces cellules de la manière suivante:

c{1}, c{2}, and so on....

Lorsque l'indice de référence seulement indice un élément, la syntaxe de Matlab permet d'utiliser des parenthèses (()) après les accolades et plus extraire un sous-réseau (une sous-chaîne dans votre cas). Cependant, cette syntaxe est interdite lorsque les listes séparées par des virgules contiennent plusieurs éléments.

Alors, quelles sont les alternatives?

  1. Utilisez un for loop:

    MyArrayOfSubStrings = char(zeros(numel(CellArrayOfStrings), 2)); 
    for k = 1:size(MyArrayOfSubStrings, 1) 
        MyArrayOfSubStrings(k, :) = CellArrayOfStrings{k}(3:4); 
    end 
    
  2. Utilisez cellfun (une légère variante de Dang Khoa's réponse):

    MyArrayOfSubStrings = cellfun(@(x){x(3:4)}, CellArrayOfStrings); 
    MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:}); 
    
  3. Si votre réseau de cellules d'origine contient des chaînes d'une longueur fixe, vous pouvez suivre la suggestion de Dan et convertir le tableau de cellules en un tableau de chaînes (une matrice de ch aracters), remodeler et extraire les colonnes souhaitées:

    MyArrayOfSubStrings =vertcat(CellArrayOfStrings{:}); 
    MyArrayOfSubStrings = MyArrayOfSubStrings(:, 3:4); 
    
  4. utilisent des méthodes plus complexes, telles que les expressions régulières:

    MyArrayOfSubStrings = regexprep(CellArrayOfStrings, '^..(..).*', '$1'); 
    MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:}); 
    

Il existe des solutions beaucoup à choisir, il suffit de choisir la celui qui vous convient le mieux :) Je pense qu'avec l'accélération JIT de MATLAB, une simple boucle suffirait dans la plupart des cas.

Notez également que dans toutes mes suggestions le tableau de cellules obtenu de la cellule de sous-chaînes est converti en un tableau de chaînes (une matrice). C'est juste pour l'amour de l'exemple; vous pouvez évidemment garder les sous-chaînes stockées dans un tableau de cellules, si vous le décidez.

+1

merci pour votre réponse complète, qui à la fois répondu à ma question et m'a aidé à comprendre. Finalement, j'ai choisi l'option 3, qui semblait la meilleure option pour mon jeu de données et ma fonction: J'ai trouvé que l'utilisation d'une boucle For dans ma fonction (option 1) était environ 4x plus lente que l'appel de cellfun (option 2). J'ai choisi l'option 3 parce que je ne voulais pas avoir à expliquer cellfun aux autres gars qui vont l'utiliser :). Merci également à Dan et Moshen qui ont fourni des réponses similaires. – fodfish

+0

Cool. Donc, depuis (1) l'accès direct à la ligne, col, sous-chaîne dans un tableau de cellules 2d produit par CellArray = textscan (fid, format) où col est une colonne de texte serait CellArray {col} {row} (3: 4). –

1

Vous pouvez le faire:

C = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'} 
t = reshape([C{:}], 6, [])' 
t(:, 3:4) 

Mais seulement si vos cordes sont de même longueur que j'ai peur.

3

cellfun fonctionne sur tous les éléments d'un réseau de cellules, de sorte que vous pouvez faire quelque chose comme ceci:

>> CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'}; 
>> MyArrayofSubstrings = cellfun(@(str) str(3:4), CellArrayOfStrings, 'UniformOutput', false) 
MyArrayofSubstrings = 
    'a1' 
    'b1' 
    'c1' 
    'd1' 

Si vous voulez une matrice de chaînes au lieu d'un réseau de cellules dont les éléments sont les cordes, utilisez char sur MyArrayOfSubstrings. Notez que ceci n'est autorisé que lorsque chaque chaîne a la même longueur.

1

Vous pouvez utiliser char pour les convertir en un tableau de caractères, faire l'indexation et la reconvertir en réseau de cellules

A = char(CellArrayOfStrings); 
B = cellstr(A(:,3:4)); 

Notez que si les chaînes sont de longueurs différentes, char eux tampons avec des espaces à la fin pour créer le tableau. Par conséquent, si vous indexez une colonne qui dépasse la longueur d'une des chaînes courtes, vous pouvez recevoir des caractères d'espace.

Questions connexes