Come creare un grafico di densità in matplotlib?


122

In RI puoi creare l'output desiderato facendo:

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

Grafico densità in R

In Python (con matplotlib) il più vicino che ho ottenuto è stato con un semplice istogramma:

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

Istogramma in matplotlib

Ho anche provato il parametro normed = True ma non sono riuscito a ottenere nient'altro che provare ad adattare un gaussiano all'istogramma.

I miei ultimi tentativi erano in giro scipy.statse gaussian_kde, seguendo esempi sul web, ma finora non ho avuto successo.


Date un'occhiata a seaborn stackoverflow.com/a/32803224/1922302
johk95

Risposte:


124

Sven ha mostrato come usare la classe gaussian_kdedi Scipy, ma noterai che non assomiglia esattamente a ciò che hai generato con R. Questo perché gaussian_kdecerca di dedurre automaticamente la larghezza di banda. Puoi giocare con la larghezza di banda in un modo cambiando la funzione covariance_factordella gaussian_kdeclasse. Innanzitutto, ecco cosa ottieni senza modificare quella funzione:

testo alternativo

Tuttavia, se utilizzo il codice seguente:

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

ottengo

testo alternativo

che è abbastanza vicino a quello che ricevi da R. Cosa ho fatto? gaussian_kdeutilizza una funzione modificabile, covariance_factorper calcolare la sua larghezza di banda. Prima di modificare la funzione, il valore restituito da covariance_factor per questi dati era di circa 0,5. L'abbassamento di questo ha ridotto la larghezza di banda. Ho dovuto chiamare _compute_covariancedopo aver modificato quella funzione in modo che tutti i fattori fossero calcolati correttamente. Non è una corrispondenza esatta con il parametro bw da R, ma si spera che ti aiuti ad andare nella giusta direzione.


6
@ Justin Bella risposta (+1) e non voglio iniziare alcuna guerra di fiamme Python contro R o altro, ma adoro il modo in cui R lavora con i dati in modo molto più succinto di Python e altri linguaggi. Sono sicuro che python ha molti punti positivi su R (non sono un utente Python quindi sono così totalmente uniforme per possibilmente commentare) e può essere utilizzato per molto più lavoro rispetto all'analisi dei dati, ma come R di lunga data user Dimentico quanto sia succinto un linguaggio per tali compiti fino a quando non emergono esempi come questo.
Gavin Simpson

4
(ancora combattendo con la modifica dei commenti) Ecco una sottoclasse di gaussian_kde che consente di impostare la larghezza di banda come argomento e altri esempi: mail.scipy.org/pipermail/scipy-user/2010-January/023877.html e c'è un miglioramento ticket su projects.scipy.org/scipy/ticket/1092 . Nota, gaussian_kde è progettato per dati n-dimensionali.
Josef

11
@Gavin Simpson, sì, R è più succinto perché ha un ambito più ristretto. È fatto per il calcolo statistico e la grafica. Python è un linguaggio di programmazione generale che può fare praticamente tutto ciò che vuoi che faccia. Per questo motivo, la sintassi potrebbe non essere così succinta. Parte di questo è un design diverso in Numpy / Scipy, ma parte è solo la configurazione modulare su Python. R è ottimo se hai solo bisogno di fare calcoli e grafici, ma se hai bisogno di usare quei calcoli in qualche applicatoin brader, allora potresti volere qualcosa come Python. Tuttavia, puoi anche usare R da Python ...
Justin Peel

10
Un set_bandwidthmetodo e un bw_methodargomento del costruttore sono stati aggiunti a gaussian_kde in scipy 0.11.0 per numero 1619
eddygeek

1
risposta obsoleta. Vedi sotto sulla soluzione Seaborn, che ora è più standard in Python.
LudvigH

148

Cinque anni dopo, quando ho cercato su Google "come creare un diagramma di densità del kernel utilizzando python", questo thread si presenta ancora in alto!

Oggi, un modo molto più semplice per farlo è usare seaborn , un pacchetto che fornisce molte comode funzioni di plottaggio e una buona gestione dello stile.

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)

inserisci qui la descrizione dell'immagine


Grazie mille .. Sono alla ricerca di qualcosa di simile da giorni .. puoi spiegare perché bw=0.5è stato dato?
Sitz Blogz

4
@SitzBlogz Il bwparametro sta per larghezza di banda. Stavo cercando di abbinare l'impostazione di OP (vedi il suo primo esempio di codice originale). Per una spiegazione dettagliata di quali bwcontrolli, vedere en.wikipedia.org/wiki/… . Fondamentalmente controlla quanto liscio vuoi che sia il grafico della densità. Più grande è il bw, più liscio sarà.
Xin

Ho un'altra domanda da chiedere che i miei dati siano di natura discreta e sto cercando di tracciare il PDF per questo, dopo aver letto scipy doc ho capito che PMF = PDF qualche suggerimento su come stamparlo?
Sitz Blogz

1
Quando provo questo ottengoTypeError: slice indices must be integers or None or have an __index__ method
endolith

48

Opzione 1:

Usa il pandasgrafico del dataframe (costruito sopra 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()

inserisci qui la descrizione dell'immagine

Opzione 2:

Utilizzo distplotdi 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)

inserisci qui la descrizione dell'immagine


4
Per aggiungere il parametro della larghezza di banda: df.plot.density (bw_method = 0.5)
Anake

3
@ Aziz Non è necessario pandas.DataFrame, può usare pandas.Series(data).plot(kind='density')@Anake, non è necessario impostare df.plot.density come passaggio separato; può semplicemente passare il tuo bw_methodkwarg inpd.Series(data).plot(kind='density', bw_method=0.5)
The Red Pea

45

Forse prova qualcosa come:

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

Puoi facilmente sostituire gaussian_kde()con una stima diversa della densità del kernel.


0

Il diagramma di densità può essere creato anche utilizzando matplotlib: la funzione plt.hist (dati) restituisce i valori y e x necessari per il diagramma di densità (vedere la documentazione https://matplotlib.org/3.1.1/api/_as_gen/ matplotlib.pyplot.hist.html ). Di conseguenza, il codice seguente crea un grafico di densità utilizzando la libreria matplotlib:

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

Questo codice restituisce il seguente grafico di densità

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.