matplotlibでバーの高さが合計1になるようにヒストグラムをプロットするにはどうすればよいですか?


85

matplotlibを使用して、ベクトルから正規化されたヒストグラムをプロットしたいと思います。私は以下を試しました:

plt.hist(myarray, normed=True)

と同様:

plt.hist(myarray, normed=1)

ただし、どちらのオプションも[0、1]からy軸を生成せず、ヒストグラムのバーの高さが合計して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()

これにより、から始まるy軸を持つ棒グラフヒストグラムが実際に生成され[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は、各バーの値の合計が1になることを意味するのではなく、バーの積分が1になることを意味することを忘れないでください。私の場合、np.sum(n)約を返しました7.2767


3
うん、それは確率密度グラフだ、彼は確率質量グラフが欲しいと思う。
NoName

200

すべてのバーの合計を1に等しくしたい場合は、各ビンに値の総数で重みを付けます。

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

スレッドはかなり古いですが、それが役立つことを願っています...

Python 2.xに関する注意:float()除算の演算子の1つにキャストを追加してください。そうしないと、整数除算のためにゼロになってしまいます。


8
素晴らしい答え。myarrayのは、Pythonであればという注意array_likenumpyの配列ではなく、あなたがキャストにする必要がありますlen(myarray)しますfloat
cmh 2013

3
また、myarrayが多次元であり、myarray [0 、:]などの1つの次元のみを使用している場合は、len(myarray)をnp.size(myarray [0 、:])と交換できます。同じ方法。(それ以外の場合は、オブジェクトを呼び出すことができないと表示されます。)
ChristineB

22

質問の日付が2010年であることを考えると、この回答は遅すぎることはわかっていますが、私自身も同様の問題に直面していたため、この質問に出くわしました。回答ですでに述べたように、normed = Trueは、ヒストグラムの下の総面積が1に等しいが、高さの合計が1に等しくないことを意味します。ただし、ヒストグラムの物理的な解釈の便宜上、1つ作成したかったのです。高さの合計が1に等しい。

次の質問でヒントを見つけました-Python :面積が1以外に正規化されたヒストグラム

しかし、バーをhistt​​ype = "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軸の最低点に触れても閉じないことに気付いた場合があります。このような場合、物乞いまたはyの終わりに要素0を追加すると、必要な結果が得られました。

私の経験を共有したいと思っただけです。ありがとうございました。


plt.histでもnormed = Trueが必要だと思います。また、Python 3では、list(zip(...))を使用する必要があります。
セバスチャンシュミッツ2014

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.