Matplotlib'de çubukların yüksekliklerinin toplamı 1 olacak şekilde bir histogramı nasıl çizebilirim?


86

Matplotlib kullanarak bir vektörden normalleştirilmiş bir histogram çizmek istiyorum. Aşağıdakileri denedim:

plt.hist(myarray, normed=True)

Hem de:

plt.hist(myarray, normed=1)

ancak hiçbir seçenek [0, 1] 'den bir y ekseni üretmez, öyle ki histogramın çubuk yüksekliklerinin toplamı 1'dir. Böyle bir histogram oluşturmak istiyorum - bunu nasıl yapabilirim?


6
Bunun eski olduğunu biliyorum, ancak ileride başvurmak için ve bu sayfayı ziyaret eden herkes için, bu tür eksen yayılmasına "olasılık yoğunluğu" ekseni denir!
— ChristineB

Yanıtlar:


50

Daha eksiksiz bir çalışan (veya bu durumda çalışmayan) bir örnek oluştursanız daha yararlı olacaktır.

Aşağıdakileri denedim:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(1000)

fig = plt.figure()
ax = fig.add_subplot(111)
n, bins, rectangles = ax.hist(x, 50, density=True)
fig.canvas.draw()
plt.show()

Bu aslında y ekseninden başlayan bir çubuk grafik histogramı oluşturacaktır [0,1].

Ayrıca, gereği histbelgelerinde (yani ax.hist?itibaren ipython), ben toplamı ince çok olduğunu düşünüyorum:

*normed*:
If *True*, the first element of the return tuple will
be the counts normalized to form a probability density, i.e.,
``n/(len(x)*dbin)``.  In a probability density, the integral of
the histogram should be 1; you can verify that with a
trapezoidal integration of the probability density function::

    pdf, bins, patches = ax.hist(...)
    print np.sum(pdf * np.diff(bins))

Yukarıdaki komutlardan sonra bunu bir deneyin:

np.sum(n * np.diff(bins))

1.0Beklendiği gibi bir dönüş değeri alıyorum . Bunun normed=Trueher bir çubuktaki değerin toplamının birlik olacağı anlamına gelmediğini, çubukların üzerindeki integralden ziyade birlik olacağı anlamına geldiğini unutmayın . Benim durumumda np.sum(n)yaklaşık geri döndü 7.2767.


3
Evet, bu bir olasılık yoğunluk grafiği, sanırım bir olasılık kütle grafiği istiyor.
— NoName

201

Tüm çubukların toplamının eşit bir birim olmasını istiyorsanız, her bölmeyi toplam değer sayısına göre ağırlıklandırın:

weights = np.ones_like(myarray) / len(myarray)
plt.hist(myarray, weights=weights)

Umarım yardımcı olur, konu oldukça eski olmasına rağmen ...

Python 2.x için not: Bölmenin float()operatörlerinden biri için çevrim ekleyin , aksi takdirde tamsayı bölme nedeniyle sıfırlarla sonuçlanırsınız


8
Mükemmel cevap. Myarray bir piton olması durumunda Not array_likebir numpy dizi yerine sen döküm gerekecektir len(myarray)için float.
— cmh

3
Ayrıca, dizim çok boyutluysa ve dizilim [0 ,:] gibi yalnızca bir boyut kullanıyorsanız, len (diziyi) np.size (dizim [0 ,:]) ile değiştirebilirsiniz ve bu da işe yarar aynı şekilde. (Aksi takdirde, nesnenin çağrılabilir olmadığını söylüyor.)
— ChristineB

22

Sorunun 2010 tarihli olduğunu düşünürsek bu cevabın çok geç olduğunu biliyorum ama ben de benzer bir sorunla karşılaştığım için bu soruyla karşılaştım. Cevapta daha önce belirtildiği gibi, normed = True, histogramın altındaki toplam alanın 1'e eşit olduğu, ancak yüksekliklerin toplamının 1'e eşit olmadığı anlamına gelir. 1'e eşit yüksekliklerin toplamı ile.

Aşağıdaki soruda bir ipucu buldum - Python: Alanı 1'den farklı bir şeye normalleştirilmiş histogram

Ancak, histtype = "step" özelliği hist () taklit eden çubuklar yapmanın bir yolunu bulamadım. Bu beni şuna yönlendirdi: Matplotlib - Halihazırda binlenmiş verilerle basamaklı histogram

Topluluk kabul edilebilir bulursa, yukarıdaki her iki gönderiden de fikirleri sentezleyen bir çözüm ortaya koymak isterim.

import matplotlib.pyplot as plt

# Let X be the array whose histogram needs to be plotted.
nx, xbins, ptchs = plt.hist(X, bins=20)
plt.clf() # Get rid of this histogram since not the one we want.

nx_frac = nx/float(len(nx)) # Each bin divided by total number of objects.
width = xbins[1] - xbins[0] # Width of each bin.
x = np.ravel(zip(xbins[:-1], xbins[:-1]+width))
y = np.ravel(zip(nx_frac,nx_frac))

plt.plot(x,y,linestyle="dashed",label="MyLabel")
#... Further formatting.

Bu benim için harika çalıştı, ancak bazı durumlarda histogramın en soldaki "çubuğunun" veya en sağdaki "çubuğunun" Y ekseninin en alt noktasına dokunarak kapanmadığını fark ettim. Böyle bir durumda, y'nin başında veya sonunda bir eleman 0 eklemek gerekli sonucu elde etti.

Deneyimlerimi paylaşacağımı düşündüm. Teşekkür ederim.


plt.hist'te normlu = True'ya ihtiyacınız olduğunu düşünüyorum. Ayrıca Python 3'te list (zip (...)) kullanmanız gerekir.
— Sebastian Schmitz

11

İşte np.histogram()yöntemi kullanan başka bir basit çözüm .

myarray = np.random.random(100)
results, edges = np.histogram(myarray, normed=True)
binWidth = edges[1] - edges[0]
plt.bar(edges[:-1], results*binWidth, binWidth)

Gerçekten de toplamın 1'e kadar çıktığını şu şekilde kontrol edebilirsiniz:

> print sum(results*binWidth)
1.0
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.