Matplotlib 直方图未正确计算每个 bin 中值的数量
Matplotlib histogram not counting correctly the number of values in each bin
我正在尝试用 matplotlib.pyplot.hist 制作一个非常简单的直方图,它似乎没有正确计算每个 bin 中值的数量。这是我的代码:
import numpy as np
import matplotlib.pyplot as plt
plt.hist([.2,.3,.5,.6],bins=np.arange(0,1.1,.1))
我将区间 [0,1] 分成宽度为 .1 的箱子,因此我应该得到四个高度为 1 的条。但是输出图形仅包含两个高度为 2 的条:它正在计算 . 3 值作为 [.2,.3) bin 的一部分,类似地,它将 .6 值计为 [.5,.6) bin 的一部分。我在 Spyder 和 Google Colab 上都试过了。任何人都知道发生了什么事?谢谢!
来自the docs:
If bins is a sequence, it defines the bin edges, including the left edge of the first bin and the right edge of the last bin; in this case, bins may be unequally spaced. All but the last (righthand-most) bin is half-open. In other words, if bins is:
[1, 2, 3, 4]
then the first bin is [1, 2) (including 1, but excluding 2) and the second [2, 3). The last bin, however, is [3, 4], which includes 4.
因为区间是闭合的 - 打开的,所以 .2 和 .3 都落在同一个 bin 中,而 .5 和 .6 落在另一个 bin 中。
您应该通过稍微移动边界来固定 bin,以避免数字落在边缘上。
问题是这些值正好落在 bin 的边界上。 Floating point rounding 可以将它们放入上一个或下一个容器中。您需要很好地 in-between 数据点边界。请注意,matplotlib 的直方图主要用于浮点舍入没有这么大影响的连续分布。
下面是一些代码来说明两种情况下发生的情况:
import numpy as np
import matplotlib.pyplot as plt
data = [.2, .3, .5, .6]
fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
for ax in axes:
if ax == axes[0]:
bins = np.arange(0, 1.1, .1)
ax.set_title('data on bin boundaries')
else:
bins = np.arange(-0.05, 1.1, .1)
ax.set_title('data between bin boundaries')
values, bin_bounds, bars = ax.hist(data, bins=bins, alpha=0.3)
ax.vlines(bin_bounds, 0, max(values), color='crimson', ls=':')
ax.scatter(data, np.full_like(data, 0.5), color='lime', s=30)
ax.set_ylim(0, 2.2)
ax.set_yticks(range(3))
plt.show()
另一种解决此问题的方法似乎是对输入数据使用与直方图在内部用于将数字分配给 bin 相同的浮点精度。
通常 Python 使用 64 位浮点数,但是这个直方图实现似乎在将它们转换为 32 位精度后分配 bins。
因此,显式插入32位浮点数似乎可以达到预期的效果:
import numpy as np
import matplotlib.pyplot as plt
data = np.array([.2,.3,.5,.6], dtype=np.float32)
plt.hist(data, bins=np.arange(0.0, 1.1, 0.1))
我正在尝试用 matplotlib.pyplot.hist 制作一个非常简单的直方图,它似乎没有正确计算每个 bin 中值的数量。这是我的代码:
import numpy as np
import matplotlib.pyplot as plt
plt.hist([.2,.3,.5,.6],bins=np.arange(0,1.1,.1))
我将区间 [0,1] 分成宽度为 .1 的箱子,因此我应该得到四个高度为 1 的条。但是输出图形仅包含两个高度为 2 的条:它正在计算 . 3 值作为 [.2,.3) bin 的一部分,类似地,它将 .6 值计为 [.5,.6) bin 的一部分。我在 Spyder 和 Google Colab 上都试过了。任何人都知道发生了什么事?谢谢!
来自the docs:
If bins is a sequence, it defines the bin edges, including the left edge of the first bin and the right edge of the last bin; in this case, bins may be unequally spaced. All but the last (righthand-most) bin is half-open. In other words, if bins is:
[1, 2, 3, 4]
then the first bin is [1, 2) (including 1, but excluding 2) and the second [2, 3). The last bin, however, is [3, 4], which includes 4.
因为区间是闭合的 - 打开的,所以 .2 和 .3 都落在同一个 bin 中,而 .5 和 .6 落在另一个 bin 中。
您应该通过稍微移动边界来固定 bin,以避免数字落在边缘上。
问题是这些值正好落在 bin 的边界上。 Floating point rounding 可以将它们放入上一个或下一个容器中。您需要很好地 in-between 数据点边界。请注意,matplotlib 的直方图主要用于浮点舍入没有这么大影响的连续分布。
下面是一些代码来说明两种情况下发生的情况:
import numpy as np
import matplotlib.pyplot as plt
data = [.2, .3, .5, .6]
fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
for ax in axes:
if ax == axes[0]:
bins = np.arange(0, 1.1, .1)
ax.set_title('data on bin boundaries')
else:
bins = np.arange(-0.05, 1.1, .1)
ax.set_title('data between bin boundaries')
values, bin_bounds, bars = ax.hist(data, bins=bins, alpha=0.3)
ax.vlines(bin_bounds, 0, max(values), color='crimson', ls=':')
ax.scatter(data, np.full_like(data, 0.5), color='lime', s=30)
ax.set_ylim(0, 2.2)
ax.set_yticks(range(3))
plt.show()
另一种解决此问题的方法似乎是对输入数据使用与直方图在内部用于将数字分配给 bin 相同的浮点精度。
通常 Python 使用 64 位浮点数,但是这个直方图实现似乎在将它们转换为 32 位精度后分配 bins。
因此,显式插入32位浮点数似乎可以达到预期的效果:
import numpy as np
import matplotlib.pyplot as plt
data = np.array([.2,.3,.5,.6], dtype=np.float32)
plt.hist(data, bins=np.arange(0.0, 1.1, 0.1))