Bagaimana cara membuat plot kepadatan di matplotlib?

122

Di RI dapat membuat keluaran yang diinginkan dengan melakukan:

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

Plot kepadatan di R

Dalam python (dengan matplotlib) yang paling dekat saya dapatkan adalah dengan histogram sederhana:

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

Histogram di matplotlib

Saya juga mencoba parameter normed = True tetapi tidak bisa mendapatkan apa pun selain mencoba menyesuaikan gaussian ke histogram.

Upaya terakhir saya adalah sekitar scipy.statsdan gaussian_kde, mengikuti contoh di web, tetapi sejauh ini saya tidak berhasil.

unode
sumber
seaborn
Silakan

Jawaban:

124

Sven telah menunjukkan bagaimana menggunakan kelas gaussian_kdedari Scipy, tetapi Anda akan melihat bahwa itu tidak terlihat seperti yang Anda hasilkan dengan R. Ini karena gaussian_kdemencoba menyimpulkan bandwidth secara otomatis. Anda dapat bermain dengan bandwidth dengan cara dengan mengubah fungsi covariance_factordari gaussian_kdekelas. Pertama, inilah yang Anda dapatkan tanpa mengubah fungsi itu:

alt teks

Namun, jika saya menggunakan kode berikut:

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

saya mendapat

alt teks

yang cukup dekat dengan apa yang Anda dapatkan dari R. Apa yang telah saya lakukan? gaussian_kdemenggunakan fungsi yang dapat diubah, covariance_factoruntuk menghitung bandwidthnya. Sebelum mengubah fungsi, nilai yang dikembalikan oleh covariance_factor untuk data ini adalah sekitar 0,5. Menurunkan ini menurunkan bandwidth. Saya harus menelepon _compute_covariancesetelah mengubah fungsi itu sehingga semua faktor akan dihitung dengan benar. Ini bukan korespondensi yang tepat dengan parameter bw dari R, tetapi mudah-mudahan ini membantu Anda mendapatkan arah yang benar.

Justin Peel
sumber
6
@Justin Jawaban yang bagus (+1) dan tidak ingin memulai perang api Python v R atau apa pun, tetapi saya menyukai cara R bekerja dengan data yang jauh lebih ringkas daripada python dan bahasa lain. Saya yakin python memiliki banyak poin bagus di atas R (Saya bukan pengguna Python jadi saya sangat berseragam mungkin untuk berkomentar) dan dapat digunakan untuk lebih banyak pekerjaan daripada menganalisis data, tetapi sebagai R untuk waktu yang lama. pengguna Saya lupa betapa ringkas bahasa itu untuk tugas-tugas seperti itu sampai contoh seperti ini muncul.
Gavin Simpson
4
(masih berkelahi dengan mengedit komentar) Berikut adalah subclass dari gaussian_kde yang memungkinkan untuk mengatur bandwidth sebagai argumen dan lebih banyak contoh: mail.scipy.org/pipermail/scipy-user/2010-January/023877.html dan ada peningkatan tiket di projects.scipy.org/scipy/ticket/1092 . Catatan, gaussian_kde dirancang untuk data n-dimensi.
Josef
11
@Gavin Simpson ya R lebih ringkas karena cakupannya lebih sempit. Itu dibuat untuk komputasi statistik dan grafik. Python adalah bahasa pemrograman umum yang dapat melakukan hampir semua hal yang Anda inginkan. Karena itu, sintaksnya mungkin tidak sesingkat itu. Sebagian dari itu adalah desain yang berbeda di Numpy / Scipy, tetapi sebagian lagi hanyalah pengaturan modular pada Python. R sangat bagus jika Anda hanya perlu melakukan komputasi dan grafik, tetapi jika Anda perlu menggunakan komputasi tersebut di beberapa aplikasi brader, maka Anda mungkin menginginkan sesuatu seperti Python. Namun, Anda juga dapat menggunakan R dari Python ...
Justin Peel
10
Sebuah set_bandwidthmetode dan bw_methodargumen konstruktor ditambahkan ke gaussian_kde di scipy 0.11.0 per masalah 1619
eddygeek
1
jawaban yang ketinggalan jaman. Lihat di bawah tentang solusi Seaborn, yang lebih standar dengan Python sekarang.
LudvigH
148

Lima tahun kemudian, ketika saya Google "cara membuat plot kepadatan kernel menggunakan python", utas ini masih muncul di bagian atas!

Saat ini, cara yang jauh lebih mudah untuk melakukannya adalah dengan menggunakan seaborn , sebuah paket yang menyediakan banyak fungsi plot yang nyaman dan manajemen gaya yang baik.

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)

masukkan deskripsi gambar di sini

Xin
sumber
Terima kasih banyak .. Sudah mencari sesuatu seperti ini sejak berhari-hari .. bisakah kamu menjelaskan mengapa bw=0.5diberikan?
Sitz Blogz
4
@SitzBlogz bwParameter adalah singkatan dari bandwidth. Saya mencoba untuk mencocokkan pengaturan OP (lihat contoh kode pertama aslinya). Untuk penjelasan rinci tentang bwkontrol apa , lihat en.wikipedia.org/wiki/… . Pada dasarnya ini mengontrol seberapa mulus Anda ingin plot kepadatannya. Semakin besar BW, semakin halus jadinya.
Xin
Saya memiliki pertanyaan lain untuk menanyakan bahwa data saya bersifat diskrit dan saya mencoba memplot PDF untuk itu, setelah membaca dokumen scipy saya mengerti bahwa PMF = PDF ada saran tentang cara memplotnya?
Sitz Blogz
1
Ketika saya mencoba ini, saya mendapatkanTypeError: slice indices must be integers or None or have an __index__ method
endolith
48

Pilihan 1:

Gunakan pandasplot dataframe (dibangun di atas 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()

masukkan deskripsi gambar di sini

Pilihan 2:

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

masukkan deskripsi gambar di sini

Aziz Alto
sumber
4
Untuk menambahkan parameter bandwidth: df.plot.density (bw_method = 0,5)
Anake
3
@Aziz Tidak perlu pandas.DataFrame, bisa menggunakan pandas.Series(data).plot(kind='density')@Anake, tidak perlu menyetel df.plot.density sebagai langkah terpisah; dapat meneruskan bw_methodkwarg Anda kepd.Series(data).plot(kind='density', bw_method=0.5)
The Red Pea
45

Mungkin mencoba sesuatu seperti:

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

Anda dapat dengan mudah mengganti gaussian_kde()dengan perkiraan kepadatan kernel yang berbeda.

Sven Marnach
sumber
0

Plot kepadatan juga dapat dibuat dengan menggunakan matplotlib: Fungsi plt.hist (data) mengembalikan nilai y dan x yang diperlukan untuk plot kepadatan (lihat dokumentasi https://matplotlib.org/3.1.1/api/_as_gen/ matplotlib.pyplot.hist.html ). Hasilnya, kode berikut membuat plot kepadatan dengan menggunakan pustaka 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])      

Kode ini mengembalikan plot kepadatan berikut

masukkan deskripsi gambar di sini

tetrisforjeff
sumber