Matplotlibを使用して離散値のヒストグラムを作成する必要がある場合があります。その場合、ビニングの選択が重要になる可能性があります。10個のビンを使用してヒストグラム[0、1、2、3、4、5、6、7、8、9、10]にした場合、ビンの1つは2倍になります。他のものと同じくらい数えます。つまり、binsizeは通常、離散化サイズの倍数である必要があります。
この単純なケースは自分で比較的簡単に処理できますが、=のために離散化サイズがわずかに変化する可能性がある浮動小数点データの場合を含め、これを自動的に処理するライブラリ/関数へのポインタがありますか? FP丸め?
ありがとう。
あなたの質問のタイトルを考えると、離散化サイズは一定であると仮定します。
この離散化サイズ(または、少なくとも、厳密には、n倍のサイズを見つけることができます。データに2つの隣接するサンプルがないこと)
np.diff(np.unique(data)).min()
これにより、データ(np.unique
)内の一意の値が検出され、それらの間の差異(np.diff
)が検出されます。ゼロ値を取得しないように、一意が必要です。次に、最小の差を見つけます。これには、離散化定数が非常に小さい場合に問題が発生する可能性があります。これについては後で説明します。
次に、値をビンの中央に置きます-現在の問題は、9と10の両方が、matplotlibが自動的に提供する最後のビンの端にあるため、1つのビンで2つのサンプルを取得するためです。
だから-これを試してください:
import matplotlib.pyplot as plt
import numpy as np
data = range(11)
data = np.array(data)
d = np.diff(np.unique(data)).min()
left_of_first_bin = data.min() - float(d)/2
right_of_last_bin = data.max() + float(d)/2
plt.hist(data, np.arange(left_of_first_bin, right_of_last_bin + d, d))
plt.show()
これは与える:
テストデータセットをもう少し作成できます。
import random
data = []
for _ in range(1000):
data.append(random.randint(1,100))
data = np.array(data)
nasty_d = 1.0 / 597 #Arbitrary smallish discretization
data = data * nasty_d
次に上記の配列を実行して、コードが吐き出すd
を確認すると、
>>> print(nasty_d) 0.0016750418760469012 >>> print(d) 0.00167504187605
したがって、検出されたd
の値は、データの作成に使用されたnasty_d
の「実際の」値ではありません。ただし、ビンをd
の半分だけシフトして、中央の値を取得するトリックを使用すると、問題はありませんunless離散化が非常に小さいため、フロートの精度の限界に達しましたまたは数千のビンがあり、検出されたd
と「実際の」離散化との差は、ビンの1つがデータポイントを「見逃す」ようなポイントまで増加する可能性があります。これは知っておくべきことですが、おそらくあなたを襲うことはありません。
上記のプロット例は次のとおりです
さらに複雑なケースについては、 このブログ投稿を見つけました をご覧ください。これは、独自のベイジアンを開発する前に Sturges 'ルールとFreedmanおよびDiaconisルール などの複数の標準的な手法を参照して、(連続/準連続)データから最適なビン幅を自動的に「学習」する方法を検討します。動的プログラミング方法。
これがあなたのユースケースである場合-質問がはるかに広く、Stack Overflowでの決定的な回答には適さない可能性がありますが、リンクが役立つと思います。
おそらく J Richard Snape's よりも完全な答えではありませんが、私が最近学んだことと、直感的で簡単だと思った答えです。
import numpy as np
import matplotlib.pyplot as plt
# great seed
np.random.seed(1337)
# how many times will a fair die land on the same number out of 100 trials.
data = np.random.binomial(n=100, p=1/6, size=1000)
# the trick is to set up the bins centered on the integers, i.e.
# -0.5, 0.5, 1,5, 2.5, ... up to max(data) + 1.5. Then you substract -0.5 to
# eliminate the extra bin at the end.
bins = np.arange(0, data.max() + 1.5) - 0.5
# then you plot away
fig, ax = plt.subplots()
_ = ax.hist(data, bins)
ax.set_xticks(bins + 0.5)
約16/100スローが同じ数になることがわかります!
少量のコードで単純なケースを処理するための別のバージョン!今回は numpy.unique
および matplotlib.vlines
:
import numpy as np
import matplotlib.pyplot as plt
# same seed/data as Manuel Martinez to make plot easy to compare
np.random.seed(1337)
data = np.random.binomial(100, 1/6, 1000)
values, counts = np.unique(data, return_counts=True)
plt.vlines(values, 0, counts, color='C0', lw=4)
# optionally set y-axis up nicely
plt.ylim(0, max(counts) * 1.06)
私に与える:
非常に読みやすく見える