web-dev-qa-db-fra.com

Recherche d'un algorithme d'histogramme rapide / efficace (avec bacs prédéfinis)

Je ne fais pas beaucoup de codage en dehors de Matlab, mais j'ai besoin d'exporter mon code Matlab vers une autre langue, très probablement C. Mon code Matlab comprend une fonction d'histogramme, histc (), qui place mes données d'entrée (qui est double -précision, pas entier) dans un tableau de cases spécifié, pour former un histogramme.

Je suis sûr que je peux assembler quelques boucles imbriquées pour générer une fonction d'histogramme, mais j'ai besoin que cette fonction soit rapide et légère, car elle sera accessible à plusieurs reprises et souvent.

Pour éviter de réinventer la roue, quelqu'un sait-il si le langage C a des fonctions d'histogramme existantes disponibles ou si les personnes qui ont besoin d'une telle chose le créent généralement elles-mêmes?

Quelqu'un connaît un algorithme efficace pour créer un histogramme? Le pseudo-code est très bien.

Merci d'avance.

24
ggkmath

GSL (GNU Scientific Library) contient une implémentation d'histogramme.

Voici la documentation: http://www.gnu.org/software/gsl/manual/html_node/Histograms.html .

Et voici un exemple d'utilisation: http://www.gnu.org/software/gsl/manual/html_node/Example-programs-for-histograms.html .

15
Kyle Lutz

L'algorithme d'histogramme "idéal" dépendra de la plage que vous comptez capturer. Généralement, tout algorithme d'histogramme ressemblera à ceci:

const int NSAMPLES = whatever;
double samples[NSAMPLES] = { 1.0, 3.93, 1e30, ... }; // your data set
const int NBUCKETS = 10; // or whatever
int counts[NBUCKETS] = { 0 };
for (int i = 0; i != NSAMPLES; ++i) {
    counts[TRANSFER(samples[i])]++;
}

TRANSFER() est une fonction qui mappe vos entrées à un bac (le 0e ou le Nième mappage de bac à "hors de portée" des applicables).

L'implémentation exacte de TRANSFER() dépend beaucoup de la distribution attendue de votre échantillon et de l'endroit où vous vous intéressez aux détails. Quelques approches courantes que j'ai vues:

  • distribution uniforme dans la plage [a, b] (nécessite une transformation linéaire)
  • distribution logarithmique des valeurs entières non signées (mieux lorsqu'elle est combinée avec certains piratage de bits pour déterminer rapidement la puissance de deux la plus proche ou similaire).

Si vous ne connaissez pas la distribution à l'avance, vous ne pouvez vraiment pas avoir de mécanisme efficace pour les regrouper efficacement: vous devrez soit deviner (résultats biaisés ou non informatifs), soit tout stocker et le trier à la fin, regroupement dans des compartiments de taille égale (performances médiocres).

20
Tom

J'ai écrit mon propre code d'histogramme en C, car c'est assez simple pour que je ne pense même pas à chercher une bibliothèque. Normalement, il vous suffit de créer un tableau pour contenir le nombre de casiers que vous souhaitez [num_bins = (int)(val_max - val_min + 1);], et lorsque vous rencontrez chaque échantillon, vous pouvez le diviser par le nombre de casiers [bin_idx = (int)((value - val_min) / bin_width);] (où bin_width = (max-min)/num_bins) pour trouver où il appartient, puis incrémenter le compteur bin. Il s'agit d'un passage simple, rapide et simple des données. Vérifiez mon arithmétique ci-dessus pour les cas Edge.

Le problème que vous pourriez rencontrer est que le domaine de votre entrée peut ne pas être connu. Avoir 100 bacs sur toute la plage de double ne sera pas très utile si toutes vos données ne sont que dans une petite fraction de cela. La solution est de faire un premier passage sur les données pour trouver le min/max de votre plage. Il n'y a vraiment pas de solution rapide à cela et la plupart des bibliothèques demanderont le min/max à l'avance.

12
dwc