Як я можу побудувати гістограму таким чином, щоб висоти стовпчиків складали 1 в matplotlib?


85

Я хотів би побудувати нормалізовану гістограму з вектора за допомогою matplotlib. Я спробував наступне:

plt.hist(myarray, normed=True)

так само, як:

plt.hist(myarray, normed=1)

але жоден варіант не створює вісь у з [0, 1] таку, що висота стовпчиків гістограми дорівнює 1. Я б хотів створити таку гістограму - як я можу це зробити?


5
Я знаю, що це старе, але для подальшого використання та будь-кого, хто відвідує цю сторінку, такий вид розподілу осі називається віссю "щільності ймовірності"!
ChristineB

Відповіді:


48

Було б більш корисно, якщо б ви подали більш повний робочий (або в даному випадку неробочий) приклад.

Я спробував наступне:

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

Це справді дасть гістограму стовпчастої діаграми з віссю у, яка йде від [0,1].

Далі, згідно з histдокументацією (тобто ax.hist?з ipython), я думаю, що і сума теж прекрасна:

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

Спробуйте це після наведених вище команд:

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

Я отримую повернене значення, 1.0як очікувалося. Пам’ятайте, що normed=Trueце не означає, що сума значення на кожному стовпчику буде одиницею, але замість інтеграла по стовпцях є одиниця. У моєму випадку np.sum(n)повернуто бл 7.2767.


3
Так, це графік щільності ймовірності, я думаю, він хоче граф маси ймовірності.
NoName

200

Якщо ви хочете, щоб сума всіх стовпчиків дорівнювала одиниці, зважте кожен бункер на загальну кількість значень:

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

Сподіваюся, це допоможе, хоча нитка досить стара ...

Примітка для Python 2.x: додайте кастинг float()для одного з операторів поділу, оскільки в іншому випадку ви отримаєте нулі через ціле ділення


8
Чудова відповідь. Зверніть увагу, що якщо myarray - це пітон, array_likeа не масив numpy, вам потрібно буде len(myarray)передати float.
cmh

3
Також якщо myarray багатовимірний, і ви використовуєте лише один вимір, наприклад myarray [0 ,:], тоді ви можете поміняти len (myarray) на np.size (myarray [0 ,:]), і це спрацює Точно так само. (В іншому випадку там сказано, що об’єкт не можна викликати.)
ChristineB

22

Я знаю, що ця відповідь занадто пізня, оскільки питання датоване 2010 роком, але я натрапив на це запитання, оскільки сам стикався з подібною проблемою. Як вже зазначалося у відповіді, normed = True означає, що загальна площа під гістограмою дорівнює 1, але сума висот не дорівнює 1. Однак я для зручності фізичної інтерпретації гістограми хотів зробити таку із сумою висот, рівною 1.

Я знайшов підказку в наступному питанні - Python: Гістограма із площею, нормалізованою до чогось іншого, ніж 1

Але я не зміг знайти спосіб зробити так, щоб бруски імітували функцію histtype = "step" hist (). Це переадресувало мене на: Matplotlib - поетапна гістограма з уже з’єднаними даними

Якщо громада вважає це прийнятним, я хотів би запропонувати рішення, яке синтезує ідеї з обох вищевказаних постів.

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.

Це чудово спрацювало для мене, хоча в деяких випадках я помітив, що самий лівий "стовпчик" або самий правий "стовпчик" гістограми не закриваються, торкаючись найнижчої точки осі Y. У такому випадку додавання елемента 0 на початку або в кінці y дало необхідний результат.

Просто думав, що поділюсь своїм досвідом. Дякую.


я думаю, вам потрібен normed = True, а також у plt.hist. Також у Python 3 ви повинні використовувати list (zip (...)).
Себастьян Шміц,

11

Ось ще одне просте рішення із використанням np.histogram()методу.

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

Ви дійсно можете перевірити, що загальна сума до 1, використовуючи:

> print sum(results*binWidth)
1.0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.