2016-01-21 7 views
1

Supposons que j'ai une matrice N×MA. Je voudrais calculer l'histogramme pour chaque colonne de A. La manière naïve serait de faire quelque chose comme ceci:Histogramme le long d'une dimension dans MATLAB

edges = 0:5:100; 
counts = zeros(numel(edges) - 1, M); 
for i_c = 1:M 
    counts(:, i_c) = histcounts(A(:, i_c), edges); 
end 

Existe-t-il une meilleure façon (plus rapide) de faire cela?

Edit: Ajouter quelques tests de performance

OK, nous allons faire quelques tests. Première histcounts + boucle, puis une alternative en utilisant arrayfun et un vecteur d'indexation, puis btmcnellis/randomGuy solution avec cellfun, enfin obchardon solution en utilisant histc. Il semble que pour de longues colonnes, histcount est plus efficace. Mais pour les colonnes plus courtes mais beaucoup, histc gagne par une grande marge!

niter = 10; 

M = 100; 
N = 10000; 

A = rand(M, N); 
edges = 0:.05:1; 


counts1 = zeros(numel(edges) - 1, N); 
counts2 = zeros(numel(edges) - 1, N); 
counts3 = zeros(numel(edges) - 1, N); 
counts4 = zeros(numel(edges), N); 

tic; 
for i_r = 1:niter 
    for i_c = 1:N 
     counts1(:, i_c) = histcounts(A(:, i_c), edges); 
    end 
end 
toc 

tic; 
for i_r = 1:niter 
    counts2 = cell2mat(arrayfun(@(ind) histcounts(A(:, ind), edges), 1:size(A, 2), 'UniformOutput', 0)')'; 
end 
toc 

tic; 
for i_r = 1:niter 
    Acell = num2cell(A, 1); 
    counts3 = cell2mat(cellfun(@(column) histcounts(column, edges), Acell, 'UniformOutput', 0)')'; 
end 
toc 

tic; 
for i_r = 1:niter 
    counts4 = histc(A, edges, 1); 
end 
toc 

all(counts1(:) == counts2(:)) 
all(counts1(:) == counts3(:)) 
counts4 = counts4(1:numel(edges)-1, :); % histc has an extra bin 
all(counts1(:) == counts4(:)) 

essais réels:

niter = 100; 
M = 10000; 
N = 100; 

temps est écoulé 2.423785 secondes.
Le temps écoulé est 2,730303 secondes.
Le temps écoulé est de 3.774217 secondes.
Le temps écoulé est de 2.721766 secondes.

niter = 10; 
M = 100; 
N = 10000; 

temps est écoulé 5.438335 secondes. La durée écoulée est de 7,387587 secondes.
Le temps écoulé est de 7,647818 secondes.
Le temps écoulé est de 0,276491 secondes.

+0

Est-ce que '' 0 edges' être: 5: 100' dans votre cas réel aussi? – Divakar

+0

@Divakar Je ne voudrais pas exclure d'autres valeurs, mais quelle serait votre suggestion pour ce cas particulier? – zeeMonkeez

+0

Eh bien, j'essayais de passer au seuil progressif de '5' et d'utiliser ensuite accumarray dans une boucle le long des colonnes, mais il semble que ce soit plutôt lent. Donc, je suppose, aller avec le 'histc' ou' histcounts'. – Divakar

Répondre

1

Vous pouvez utiliser: histc

x = [0:5:100]; 
y = histc(A,x, dim); 

dim est la dimension sur laquelle compter.

Et puis

hist(y(:,1),x); 
hist(y(:,2),x); 
... 
+0

J'avais complètement oublié que l'utilisation de 'histc' ... Sur les [instances découragées de histc] (http://www.mathworks.com/help/matlab/creating_plots/replace-discouraged-instances-of-hist-and -histc.html) ils suggèrent réellement de remplacer 'histc' dans mon cas d'utilisation avec la boucle .. – zeeMonkeez

+0

@zeeMonkeez: Mais gardez à l'esprit que le code est plus compact mais (je suppose) plus lent. Histcount est probablement plus efficace. – obchardon

+0

Mes brefs tests montrent que 'histc' et looped' histcounts' prennent exactement le même temps ... Je mettrai à jour la question avec les résultats des tests. – zeeMonkeez

0

de Split la matrice A dans une matrice de cellules où chaque cellule est une seule colonne de la matrice:

Acell = [mat2cell(A',ones(1,M))]'; 

Appliquer la fonction en utilisant cellfun à chaque cellule de la matrice de cellules Acell

counts = cellfun(@(x)histcounts(x,edges),Acell); 

nombre sera un tableau de cellules avec chaque cellule contenant des comptes d'histogramme de la colonne respective de A.

0

Vous pouvez utiliser num2cell et cellfun, bien que je ne sais pas comment cela se compare à la méthode naïve en termes de performances. Par défaut, prend une matrice et la convertit en un tableau de cellules où chaque cellule contient un élément de la matrice, mais en passant un deuxième argument vous permet de le faire le long d'une dimension particulière. Donc, pour la matrice 2x3 A, num2cell(A, 1) renvoie une matrice de cellules de 1x3 où chaque cellule contient un 2-en-1 de la colonne A.

cellfun applique une fonction à chaque élément d'une cellule.Donc, dans ce cas, vous pouvez prendre une matrice de cellules C sortie de num2cell comme ci-dessus et appliquer histcounts à chaque colonne de A comme suit:

counts = cellfun(@(column) histcounts(column, edges), C); 

counts devrait alors être un tableau 3 éléments, où l'élément i-ème contient le résultat histcounts pour la i-ème colonne de A.

(Notez que la syntaxe @() est au-dessus d'un anonymous function.)