Wie erstelle ich ein Dichtediagramm in matplotlib?

121

In RI können Sie die gewünschte Ausgabe erstellen, indem Sie Folgendes tun:

data = c(rep(1.5, 7), rep(2.5, 2), rep(3.5, 8),
         rep(4.5, 3), rep(5.5, 1), rep(6.5, 8))
plot(density(data, bw=0.5))

Dichtediagramm in R.

In Python (mit Matplotlib) kam ich mit einem einfachen Histogramm am nächsten:

import matplotlib.pyplot as plt
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
plt.hist(data, bins=6)
plt.show()

Histogramm in Matplotlib

Ich habe auch den Parameter normed = True ausprobiert , konnte aber nur versuchen, einen Gaußschen Wert an das Histogramm anzupassen.

Meine letzten Versuche gab es scipy.statsund gaussian_kdefolgte Beispielen im Internet, aber ich war bisher erfolglos.

unode
quelle
seaborn Werfen
johk95

Antworten:

123

Sven hat gezeigt, wie die Klasse gaussian_kdevon Scipy verwendet wird, aber Sie werden feststellen, dass sie nicht ganz so aussieht, wie Sie sie mit R generiert haben. Dies liegt daran, dass gaussian_kdeversucht wird, die Bandbreite automatisch abzuleiten . Sie können auf eine Art und Weise mit der Bandbreite spielen, indem Sie die Funktion covariance_factorder gaussian_kdeKlasse ändern . Zunächst erhalten Sie Folgendes, ohne diese Funktion zu ändern:

Alt-Text

Wenn ich jedoch den folgenden Code verwende:

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = gaussian_kde(data)
xs = np.linspace(0,8,200)
density.covariance_factor = lambda : .25
density._compute_covariance()
plt.plot(xs,density(xs))
plt.show()

Ich bekomme

Alt-Text

Das ist ziemlich nah an dem, was Sie von R bekommen. Was habe ich getan? gaussian_kdeverwendet eine veränderbare Funktion, covariance_factorum die Bandbreite zu berechnen. Vor dem Ändern der Funktion betrug der von covariance_factor für diese Daten zurückgegebene Wert etwa 0,5. Durch Verringern wurde die Bandbreite verringert. Ich musste _compute_covariancenach dem Ändern dieser Funktion aufrufen , damit alle Faktoren korrekt berechnet wurden. Es ist keine exakte Entsprechung mit dem bw-Parameter von R, aber hoffentlich hilft es Ihnen, in die richtige Richtung zu gelangen.

Justin Peel
quelle
6
@Justin Schöne Antwort (+1) und ich möchte keine Python v R-Flammenkriege oder ähnliches starten, aber ich liebe die Art und Weise, wie R mit Daten viel prägnanter arbeitet als Python und andere Sprachen. Ich bin mir sicher, dass Python viele gute Punkte gegenüber R hat (ich bin kein Python-Benutzer, daher bin ich so uniformiert, dass ich möglicherweise Kommentare abgeben kann) und für viel mehr Arbeit als die Analyse von Daten verwendet werden kann, aber als langjähriges R. Benutzer Ich vergesse, wie prägnant eine Sprache für solche Aufgaben ist, bis Beispiele wie dieses auftauchen.
Gavin Simpson
4
(kämpft immer noch mit der Bearbeitung von Kommentaren) Hier ist eine Unterklasse von gaussian_kde, mit der die Bandbreite als Argument festgelegt werden kann, und weitere Beispiele: mail.scipy.org/pipermail/scipy-user/2010-January/023877.html und es gibt eine Verbesserung Ticket unter projects.scipy.org/scipy/ticket/1092 . Beachten Sie, dass gaussian_kde für n-dimensionale Daten ausgelegt ist.
Josef
11
@ Gavin Simpson, ja, R ist prägnanter, weil es einen engeren Anwendungsbereich hat. Es dient zur statistischen Berechnung und Grafik. Python ist eine allgemeine Programmiersprache, die so ziemlich alles kann, was Sie wollen. Aus diesem Grund ist die Syntax möglicherweise nicht so prägnant. Ein Teil davon ist ein anderes Design in Numpy / Scipy, aber ein Teil davon ist nur das modulare Setup in Python. R ist großartig, wenn Sie nur Berechnungen und Grafiken durchführen müssen, aber wenn Sie diese Berechnungen in einer Brader-Anwendung verwenden müssen, möchten Sie vielleicht etwas wie Python. Sie können jedoch auch R von Python verwenden ...
Justin Peel
10
Eine set_bandwidthMethode und ein bw_methodKonstruktorargument wurden zu gaussian_kde in scipy 0.11.0 pro Ausgabe 1619
eddygeek
1
veraltete Antwort. Siehe unten zur Seaborn-Lösung, die jetzt in Python Standard ist.
LudvigH
147

Fünf Jahre später, wenn ich "wie man mit Python ein Kernel-Dichtediagramm erstellt" google, wird dieser Thread immer noch oben angezeigt!

Heutzutage ist es viel einfacher, Seaborn zu verwenden , ein Paket, das viele praktische Plotfunktionen und ein gutes Stilmanagement bietet.

import numpy as np
import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.set_style('whitegrid')
sns.kdeplot(np.array(data), bw=0.5)

Geben Sie hier die Bildbeschreibung ein

Xin
quelle
Vielen Dank. Ich suche seit Tagen nach so etwas. Kannst du uns erklären, warum das bw=0.5gegeben ist?
Sitz Blogz
4
@SitzBlogz Der bwParameter steht für Bandbreite. Ich habe versucht, die Einstellung von OP anzupassen (siehe sein ursprüngliches erstes Codebeispiel). Eine ausführliche Erläuterung der bwSteuerelemente finden Sie unter en.wikipedia.org/wiki/… . Grundsätzlich wird gesteuert, wie glatt das Dichtediagramm sein soll. Je größer das bw, desto glatter wird es.
Xin
Ich habe eine weitere Abfrage, um zu fragen, ob meine Daten diskreter Natur sind, und ich versuche, das PDF dafür zu zeichnen. Nachdem ich das scipy-Dokument gelesen hatte, verstand ich, dass PMF = PDF Vorschläge zum Plotten hat.
Sitz Blogz
1
Wenn ich das versuche ichTypeError: slice indices must be integers or None or have an __index__ method
Endolithe
48

Option 1:

Verwenden Sie ein pandasDatenrahmen-Diagramm (das darauf aufgebaut ist matplotlib):

import pandas as pd
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
pd.DataFrame(data).plot(kind='density') # or pd.Series()

Geben Sie hier die Bildbeschreibung ein

Option 2:

Verwendung distplotvon seaborn:

import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.distplot(data, hist=False)

Geben Sie hier die Bildbeschreibung ein

Aziz Alto
quelle
4
So fügen Sie den Bandbreitenparameter hinzu: df.plot.density (bw_method = 0.5)
Anake
3
@Aziz Nicht erforderlich pandas.DataFrame, kann pandas.Series(data).plot(kind='density')@Anake verwenden, muss df.plot.density nicht als separaten Schritt festlegen; kann einfach in Ihrem bw_methodkwarg inpd.Series(data).plot(kind='density', bw_method=0.5)
The Red Pea
45

Vielleicht versuchen Sie etwas wie:

import matplotlib.pyplot as plt
import numpy
from scipy import stats
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = stats.kde.gaussian_kde(data)
x = numpy.arange(0., 8, .1)
plt.plot(x, density(x))
plt.show()

Sie können leicht gaussian_kde()durch eine andere Schätzung der Kerneldichte ersetzen .

Sven Marnach
quelle
0

Das Dichtediagramm kann auch mit matplotlib erstellt werden: Die Funktion plt.hist (data) gibt die für das Dichtediagramm erforderlichen y- und x-Werte zurück (siehe Dokumentation https://matplotlib.org/3.1.1/api/_as_gen/). matplotlib.pyplot.hist.html ). Infolgedessen erstellt der folgende Code mithilfe der matplotlib-Bibliothek ein Dichtediagramm:

import matplotlib.pyplot as plt
dat=[-1,2,1,4,-5,3,6,1,2,1,2,5,6,5,6,2,2,2]
a=plt.hist(dat,density=True)
plt.close()
plt.figure()
plt.plot(a[1][1:],a[0])      

Dieser Code gibt das folgende Dichtediagramm zurück

Geben Sie hier die Bildbeschreibung ein

tetrisforjeff
quelle