Behältergröße in Matplotlib (Histogramm)

149

Ich benutze Matplotlib, um ein Histogramm zu erstellen.

Gibt es eine Möglichkeit, die Größe der Fächer im Gegensatz zur Anzahl der Fächer manuell festzulegen?

Sam Creamer
quelle

Antworten:

270

Eigentlich ist es ganz einfach: Anstelle der Anzahl der Bins können Sie eine Liste mit den Bin-Grenzen angeben. Sie können auch ungleich verteilt sein:

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

Wenn Sie sie nur gleichmäßig verteilen möchten, können Sie einfach range verwenden:

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

Zur ursprünglichen Antwort hinzugefügt

Die obige Zeile gilt nur für dataGanzzahlen. Wie Macrocosme hervorhebt, können Sie für Schwimmer Folgendes verwenden:

import numpy as np
plt.hist(data, bins=np.arange(min(data), max(data) + binwidth, binwidth))
CodingCat
quelle
20
Ersetzen Sie den Bereich (...) durch np.arange (...), damit er mit Floats funktioniert.
Makrokosme
6
Was ist die Binwidth hier? Hast du diesen Wert schon einmal eingestellt?
UserYmY
1
Ich glaube, die Binbreite in diesem Beispiel könnte gefunden werden durch : (data.max() - data.min()) / number_of_bins_you_want. Das + binwidthkönnte geändert werden, 1um dies zu einem leicht verständlichen Beispiel zu machen.
Jarad
2
Versuchen Sie neben der oben beschriebenen hervorragenden Lösung von CodingCat für Float-Daten die folgende Optimierung, wenn die Histogrammbalken um ganzzahlige x-Ticks zentriert werden sollen, anstatt die Balkengrenzen an den x-Ticks zu haben: bins = np.arange (dmin - 0.5, dmax + 0,5 + binwidth, binwidth)
DaveW
3
Option lw = 5, color = "white"oder ähnliches fügt weiße Lücken zwischen Balken ein
PatrickT
13

Für N Fächer werden die Fachkanten durch eine Liste von N + 1-Werten angegeben, wobei das erste N die unteren Fachkanten und das +1 die obere Kante des letzten Fachs angibt.

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)

Beachten Sie, dass linspace ein Array von min_edge bis max_edge erzeugt, das in N + 1-Werte oder N Bins unterteilt ist

Alef
quelle
1
Beachten Sie, dass Bins einschließlich ihrer Untergrenze und ausschließlich ihrer Obergrenze enthalten sind, mit Ausnahme des N + 1 (letzten) Bins, der beide Grenzen enthält.
lauwitmer
4

Ich denke, der einfache Weg wäre, das Minimum und Maximum der Daten zu berechnen, die Sie haben, und dann zu berechnen L = max - min. Dann dividieren Sie Ldurch die gewünschte Behälterbreite (ich gehe davon aus, dass dies mit der Behältergröße gemeint ist) und verwenden die Obergrenze dieses Werts als Anzahl der Behälter.

Il-Bhima
quelle
Genau das hatte ich vor, danke. Ich habe mich nur gefragt, ob es einen einfacheren Weg gibt, aber das scheint danke zu finden!
Sam Creamer
Bei Verwendung runder Zahlen erhalte ich mit diesem Ansatz keine runde Behältergröße. Hat das jemand erlebt?
Brad Urani
3

Ich mag es, wenn Dinge automatisch passieren und Mülleimer auf "schöne" Werte fallen. Das Folgende scheint ganz gut zu funktionieren.

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()

Das Ergebnis sind Behälter in schönen Intervallen der Behältergröße.

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

berechnetes Bins-Histogramm

im Voraus bezahlen
quelle
Genau das, wonach ich gesucht habe! In einigen Fällen wird n_bins jedoch aufgrund der Gleitkommapräzision abgerundet. ZB fürdesired_bin_size=0.05 , min_boundary=0.850, max_boundary=2.05die Berechnung n_binswird int(23.999999999999993)die Ergebnisse in 23 anstelle von 24 und damit ein Fach zu wenig. Eine Rundung vor der Ganzzahlkonvertierung hat bei mir funktioniert:n_bins = int(round((max_boundary - min_boundary) / desired_bin_size, 0)) + 1
M. Schlenker
3

Ich benutze Quantile, um Behälter einheitlich zu machen und an die Probe anzupassen:

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')

Geben Sie hier die Bildbeschreibung ein

Wojciech Moszczyński
quelle
1
Großartige Idee. Sie können die Liste der Quantile durch np.arange(0, 1.01, 0.5)oder ersetzen np.linspace(0, 1, 21). Es gibt keine Kanten, aber ich verstehe, dass die Felder die gleiche Fläche haben, aber unterschiedliche Breite in der X-Achse?
Tomasz Gandor
2

Ich hatte das gleiche Problem wie OP (glaube ich!), Aber ich konnte es nicht so zum Laufen bringen, wie Lastalda es angegeben hatte. Ich weiß nicht, ob ich die Frage richtig interpretiert habe, aber ich habe eine andere Lösung gefunden (es ist wahrscheinlich eine wirklich schlechte Art, dies zu tun).

So habe ich es gemacht:

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

Was das schafft:

Bild zeigt Histogramm-Diagramm in Matplotlib erstellt

Der erste Parameter "initialisiert" also im Grunde den Behälter - ich erstelle speziell eine Zahl, die zwischen dem Bereich liegt, den ich im Parameter "Behälter" festgelegt habe.

Um dies zu demonstrieren, betrachten Sie das Array im ersten Parameter ([1,11,21,31,41]) und das Array 'bins' im zweiten Parameter ([0,10,20,30,40,50]). ::

  • Die Zahl 1 (aus dem ersten Array) liegt zwischen 0 und 10 (im Array "Bins").
  • Die Zahl 11 (aus dem ersten Array) liegt zwischen 11 und 20 (im Array "Bins").
  • Die Zahl 21 (aus dem ersten Array) liegt zwischen 21 und 30 (im Array "Bins") usw.

Dann benutze ich den Parameter 'weight', um die Größe jedes Behälters zu definieren. Dies ist das Array, das für den Gewichtungsparameter verwendet wird: [10,1,40,33,6].

Der Behälter 0 bis 10 erhält also den Wert 10, der Behälter 11 bis 20 den Wert 1, der Behälter 21 bis 30 den Wert 40 usw.

bluguy
quelle
3
Ich denke, Sie haben ein grundlegendes Missverständnis darüber, wie die Histogrammfunktion funktioniert. Es werden Rohdaten erwartet. In Ihrem Beispiel sollte Ihr Datenarray also 10 Werte zwischen 0 und 10, 1 Wert zwischen 10 und 20 usw. enthalten. Dann führt die Funktion die Summierung UND das Zeichnen durch. Was Sie oben tun, ist eine Problemumgehung, da Sie bereits über die Summen verfügen (die Sie dann durch Missbrauch der Option "Gewichte" in das Diagramm einfügen). Hoffe, das klärt einige Verwirrung.
CodingCat
-1

Für ein Histogramm mit ganzzahligen x-Werten habe ich letztendlich verwendet

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

Der Versatz von 0,5 zentriert die Bins auf den Werten der x-Achse. Der plt.xticksAufruf fügt für jede Ganzzahl ein Häkchen hinzu.

Adversus
quelle