根据 Matplotlib 中的预计数数据绘制直方图
Posted
技术标签:
【中文标题】根据 Matplotlib 中的预计数数据绘制直方图【英文标题】:Plotting a histogram from pre-counted data in Matplotlib 【发布时间】:2013-10-13 07:09:59 【问题描述】:我想使用 Matplotlib 在预先计算的数据上绘制直方图。例如,假设我有原始数据
data = [1, 2, 2, 3, 4, 5, 5, 5, 5, 6, 10]
鉴于这些数据,我可以使用
pylab.hist(data, bins=[...])
绘制直方图。
在我的例子中,数据已被预先计算并表示为字典:
counted_data = 1: 1, 2: 2, 3: 1, 4: 1, 5: 4, 6: 1, 10: 1
理想情况下,我想将这个预先计算的数据传递给一个直方图函数,让我可以控制 bin 宽度、绘图范围等,就好像我传递了原始数据一样。作为一种解决方法,我将我的计数扩展到原始数据:
data = list(chain.from_iterable(repeat(value, count)
for (value, count) in counted_data.iteritems()))
当counted_data
包含数百万个数据点的计数时,这是低效的。
有没有更简单的方法可以使用 Matplotlib 从我预先计算的数据中生成直方图?
或者,如果只对预先分箱的条形图数据进行最简单的处理,是否有一种方便的方法可以将我的每项计数“汇总”到分箱计数中?
【问题讨论】:
附注:要将计数扩展到原始数据,您还可以使用Counter
类及其elements() 方法:from collections import Counter
c = Counter(counted_data)
data = list(c.elements())
【参考方案1】:
您可以将weights
关键字参数用于np.histgram
(plt.hist
在下面调用)
val, weight = zip(*[(k, v) for k,v in counted_data.items()])
plt.hist(val, weights=weight)
假设你只有有整数作为键,你也可以直接使用bar
:
min_bin = np.min(counted_data.keys())
max_bin = np.max(counted_data.keys())
bins = np.arange(min_bin, max_bin + 1)
vals = np.zeros(max_bin - min_bin + 1)
for k,v in counted_data.items():
vals[k - min_bin] = v
plt.bar(bins, vals, ...)
其中 ... 是您想要传递给 bar
(doc) 的任何参数
如果您想重新分类您的数据,请参阅Histogram with separate list denoting frequency
【讨论】:
感谢指向weights
选项的指针;我忽略了它,但它完美地解决了我的问题(见我的回答)。
我没有建立这种联系(直接使用bar
蒙蔽了双眼)。已编辑以反映您的评论。【参考方案2】:
我使用pyplot.hist 的weights
选项按每个键的值加权,生成我想要的直方图:
pylab.hist(counted_data.keys(), weights=counted_data.values(), bins=range(50))
这让我可以依靠 hist
重新打包我的数据。
【讨论】:
你获取数据的方式比我的更有意义。如果您接受自己的答案,我可以接受。 这是我需要的线索。就我而言,我有一个计数列表和 bin 范围:plt.hist(bins, bins=len(bins), weights=counts)
是我需要的调用
警告词:我注意到如果 bin 的大小不同,并且使用 density=True
,这会给出不正确的结果。可能不是错误,而是 pdf 和 cdf 之间的数学差异。【参考方案3】:
您还可以使用 seaborn 绘制直方图:
import seaborn as sns
sns.distplot(
list(
counted_data.keys()
),
hist_kws=
"weights": list(counted_data.values())
)
【讨论】:
【参考方案4】:“bins”数组的长度应该比“counts”的长度长。以下是完全重建直方图的方法:
import numpy as np
import matplotlib.pyplot as plt
bins = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).astype(float)
counts = np.array([5, 3, 4, 5, 6, 1, 3, 7]).astype(float)
centroids = (bins[1:] + bins[:-1]) / 2
counts_, bins_, _ = plt.hist(centroids, bins=len(counts),
weights=counts, range=(min(bins), max(bins)))
plt.show()
assert np.allclose(bins_, bins)
assert np.allclose(counts_, counts)
【讨论】:
【参考方案5】:添加到 tacaswell 的评论中,plt.bar
可以比plt.hist
更有效地处理大量垃圾箱 (>1e4)。特别是对于一个拥挤的随机图,您只需要绘制最高的条,因为看到它们所需的宽度无论如何都会覆盖它们的大部分邻居。您可以选择最高的条形图并用
i, = np.where(vals > min_height)
plt.bar(i,vals[i],width=len(bins)//50)
其他统计趋势可能更喜欢每隔 100 个柱或类似的东西绘制一次。
这里的技巧是 plt.hist
想要绘制所有的 bin,而 plt.bar
会让你只绘制更稀疏的可见 bin 集。
【讨论】:
以上是关于根据 Matplotlib 中的预计数数据绘制直方图的主要内容,如果未能解决你的问题,请参考以下文章