Taille du bac dans Matplotlib (histogramme)

149

J'utilise matplotlib pour créer un histogramme.

Existe-t-il un moyen de définir manuellement la taille des bacs par opposition au nombre de bacs?

Sam Creamer
la source

Réponses:

270

En fait, c'est assez simple: au lieu du nombre de bacs, vous pouvez donner une liste avec les limites des bacs. Ils peuvent également être inégalement répartis:

plt.hist(data, bins=[0, 10, 20, 30, 40, 50, 100])

Si vous souhaitez simplement les distribuer de manière égale, vous pouvez simplement utiliser range:

plt.hist(data, bins=range(min(data), max(data) + binwidth, binwidth))

Ajouté à la réponse d'origine

La ligne ci-dessus ne fonctionne que pour les datanombres entiers. Comme le souligne macrocosme , pour les flotteurs, vous pouvez utiliser:

import numpy as np
plt.hist(data, bins=np.arange(min(data), max(data) + binwidth, binwidth))
CodageCat
la source
20
remplacez range (...) par np.arange (...) pour le faire fonctionner avec des flotteurs.
macrocosme
6
quel est le binwidth ici? avez-vous défini cette valeur avant?
UserYmY
1
Je crois binwidth dans cet exemple se trouve par: (data.max() - data.min()) / number_of_bins_you_want. Le + binwidthpourrait être changé en juste 1pour en faire un exemple plus facile à comprendre.
Jarad
2
Suite à l'excellente solution de CodingCat ci-dessus, pour les données flottantes, si vous voulez que les barres d'histogramme soient centrées autour des x-ticks entiers au lieu d'avoir les limites des barres aux x-ticks, essayez le réglage suivant: bins = np.arange (dmin - 0.5, dmax + 0.5 + binwidth, binwidth)
DaveW
3
option lw = 5, color = "white"ou similaire insère des espaces blancs entre les barres
PatrickT
13

Pour N bacs, les bords de bac sont spécifiés par une liste de N + 1 valeurs où les N premiers donnent les bords de bac inférieurs et le +1 donne le bord supérieur du dernier bac.

Code:

from numpy import np; from pylab import *

bin_size = 0.1; min_edge = 0; max_edge = 2.5
N = (max_edge-min_edge)/bin_size; Nplus1 = N + 1
bin_list = np.linspace(min_edge, max_edge, Nplus1)

Notez que linspace produit un tableau de min_edge à max_edge divisé en N + 1 valeurs ou N bins

Alef
la source
1
Notez que les bacs incluent leur borne inférieure et excluent leur borne supérieure, à l'exception du N + 1 (dernier) bac qui comprend les deux bornes.
lukewitmer
4

Je suppose que le moyen le plus simple serait de calculer le minimum et le maximum des données dont vous disposez, puis de calculer L = max - min. Ensuite, vous divisez Lpar la largeur de bac souhaitée (je suppose que c'est ce que vous entendez par taille de bac) et utilisez le plafond de cette valeur comme nombre de bacs.

Il-Bhima
la source
c'est exactement ce que j'avais en tête, merci. Je me demandais juste s'il y avait un moyen plus simple mais cela semble trouver merci!
Sam Creamer
En utilisant des nombres ronds, je n'obtiens pas une taille de bac ronde avec cette approche. Quelqu'un a-t-il vécu cela?
Brad Urani
3

J'aime que les choses se passent automatiquement et que les bacs retombent sur de «belles» valeurs. Ce qui suit semble très bien fonctionner.

import numpy as np
import numpy.random as random
import matplotlib.pyplot as plt
def compute_histogram_bins(data, desired_bin_size):
    min_val = np.min(data)
    max_val = np.max(data)
    min_boundary = -1.0 * (min_val % desired_bin_size - min_val)
    max_boundary = max_val - max_val % desired_bin_size + desired_bin_size
    n_bins = int((max_boundary - min_boundary) / desired_bin_size) + 1
    bins = np.linspace(min_boundary, max_boundary, n_bins)
    return bins

if __name__ == '__main__':
    data = np.random.random_sample(100) * 123.34 - 67.23
    bins = compute_histogram_bins(data, 10.0)
    print(bins)
    plt.hist(data, bins=bins)
    plt.xlabel('Value')
    plt.ylabel('Counts')
    plt.title('Compute Bins Example')
    plt.grid(True)
    plt.show()

Le résultat a des bacs sur de beaux intervalles de taille de bac.

[-70. -60. -50. -40. -30. -20. -10.   0.  10.  20.  30.  40.  50.  60.]

histogramme des classes calculées

pay_it_forward
la source
Exactement ce que je cherchais! Cependant, dans certains cas, n_bins est arrondi en raison de la précision en virgule flottante. Par exemple , pour desired_bin_size=0.05, min_boundary=0.850, max_boundary=2.05le calcul de n_binsse int(23.999999999999993)qui se traduit par 23 au lieu de 24 et donc un bac trop peu. Un arrondi avant la conversion entière a fonctionné pour moi:n_bins = int(round((max_boundary - min_boundary) / desired_bin_size, 0)) + 1
M. Schlenker
3

J'utilise des quantiles pour faire des bacs uniformes et ajustés pour échantillonner:

bins=df['Generosity'].quantile([0,.05,0.1,0.15,0.20,0.25,0.3,0.35,0.40,0.45,0.5,0.55,0.6,0.65,0.70,0.75,0.80,0.85,0.90,0.95,1]).to_list()

plt.hist(df['Generosity'], bins=bins, normed=True, alpha=0.5, histtype='stepfilled', color='steelblue', edgecolor='none')

entrez la description de l'image ici

Wojciech Moszczyński
la source
1
Bonne idée. Vous pouvez remplacer la liste des quantiles par np.arange(0, 1.01, 0.5)ou np.linspace(0, 1, 21). Il n'y a pas d'arêtes, mais je comprends que les boîtes ont une surface égale, mais une largeur différente sur l'axe X?
Tomasz Gandor le
2

J'ai eu le même problème que OP (je pense!), Mais je ne pouvais pas le faire fonctionner de la manière spécifiée par Lastalda. Je ne sais pas si j'ai bien interprété la question, mais j'ai trouvé une autre solution (c'est probablement une très mauvaise façon de le faire cependant).

Voici comment je l'ai fait:

plt.hist([1,11,21,31,41], bins=[0,10,20,30,40,50], weights=[10,1,40,33,6]);

Ce qui crée ceci:

image montrant un histogramme créé dans matplotlib

Donc, le premier paramètre «initialise» fondamentalement le bac - je crée spécifiquement un nombre qui se situe entre la plage que j'ai définie dans le paramètre bins.

Pour le démontrer, regardez le tableau dans le premier paramètre ([1,11,21,31,41]) et le tableau 'bins' dans le deuxième paramètre ([0,10,20,30,40,50]) :

  • Le numéro 1 (du premier tableau) se situe entre 0 et 10 (dans le tableau 'bins')
  • Le nombre 11 (du premier tableau) se situe entre 11 et 20 (dans le tableau 'bins')
  • Le nombre 21 (du premier tableau) se situe entre 21 et 30 (dans le tableau 'bins'), etc.

Ensuite, j'utilise le paramètre «poids» pour définir la taille de chaque bac. Il s'agit du tableau utilisé pour le paramètre poids: [10,1,40,33,6].

Ainsi, le bac 0 à 10 reçoit la valeur 10, le bac 11 à 20 a la valeur 1, le bac 21 à 30 a la valeur 40, etc.

Bluguy
la source
3
Je pense que vous avez un malentendu fondamental sur le fonctionnement de la fonction d'histogramme. Il attend des données brutes. Ainsi, dans votre exemple, votre tableau de données doit contenir 10 valeurs entre 0 et 10, 1 valeur entre 10 et 20, et ainsi de suite. Ensuite, la fonction fait le résumé ET le dessin. Ce que vous faites ci-dessus est une solution de contournement car vous avez déjà les sommes (que vous insérez ensuite dans le graphique en utilisant mal l'option "poids"). J'espère que cela dissipe une certaine confusion.
CodingCat
-1

Pour un histogramme avec des valeurs x entières, j'ai fini par utiliser

plt.hist(data, np.arange(min(data)-0.5, max(data)+0.5))
plt.xticks(range(min(data), max(data)))

Le décalage de 0,5 centre les cases sur les valeurs de l'axe des x. L' plt.xticksappel ajoute une coche pour chaque entier.

Adversus
la source