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.