如何使用 Python 中的 Matplotlib 绘制带有数据列表的直方图?

如何使用 matplotlib.pyplot.hist绘制直方图?

我有一个对应于条形高度的 y 值列表和一个 x 值字符串列表。

相关阅读: matplotlib.pyplot.bar

646807 次浏览

如果你想要一个直方图,你不需要在 x 值上附加任何“名字”,因为:

  • x轴上有数据仓
  • y轴计数(默认)或频率(density=True)
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline


np.random.seed(42)
x = np.random.normal(size=1000)


plt.hist(x, density=True, bins=30)  # density=False would make counts
plt.ylabel('Probability')
plt.xlabel('Data');


enter image description here

注意,bins=30的数量是任意选择的,在选择“正确的”容器宽度时,有一个更科学的 Freedman-Diaconis规则:

![enter image description here,其中 IQR四分差n是要绘制的数据点总数

因此,根据这条规则,我们可以计算出 bins的数目:

q25, q75 = np.percentile(x, [25, 75])
bin_width = 2 * (q75 - q25) * len(x) ** (-1/3)
bins = round((x.max() - x.min()) / bin_width)
print("Freedman–Diaconis number of bins:", bins)
plt.hist(x, bins=bins);

Freedman–Diaconis number of bins: 82

enter image description here

最后,你可以用 PDF线、标题和图例使你的直方图看起来更精致一些:

import scipy.stats as st


plt.hist(x, density=True, bins=82, label="Data")
mn, mx = plt.xlim()
plt.xlim(mn, mx)
kde_xs = np.linspace(mn, mx, 300)
kde = st.gaussian_kde(x)
plt.plot(kde_xs, kde.pdf(kde_xs), label="PDF")
plt.legend(loc="upper left")
plt.ylabel("Probability")
plt.xlabel("Data")
plt.title("Histogram");

enter image description here

如果你愿意探索其他的机会,seaborn有一条捷径:

# !pip install seaborn
import seaborn as sns
sns.displot(x, bins=82, kde=True);

enter image description here

现在回到指挥所。

如果您的数据点数量有限,条形图将更有意义地表示您的数据。然后你可以在 x 轴上贴上标签:

x = np.arange(3)
plt.bar(x, height=[1,2,3])
plt.xticks(x, ['a','b','c']);

enter image description here

这是一个非常迂回的方法,但是如果你想制作一个你已经知道 bin 值但是没有源数据的直方图,你可以使用 np.random.randint函数在每个 bin 的范围内为 hist 函数生成正确的数值,例如:

import numpy as np
import matplotlib.pyplot as plt


data = [np.random.randint(0, 9, *desired y value*), np.random.randint(10, 19, *desired y value*), etc..]
plt.hist(data, histtype='stepfilled', bins=[0, 10, etc..])

至于标签,你可以把 x 的标签和垃圾桶对齐,得到这样的东西:

#The following will align labels to the center of each bar with bin intervals of 10
plt.xticks([5, 15, etc.. ], ['Label 1', 'Label 2', etc.. ])

如果您还没有安装 matplotlib,请尝试下面的命令。

> pip install matplotlib

图书馆导入

import matplotlib.pyplot as plot

柱状图数据:

plot.hist(weightList,density=1, bins=20)
plot.axis([50, 110, 0, 0.06])
#axis([xmin,xmax,ymin,ymax])
plot.xlabel('Weight')
plot.ylabel('Probability')

显示直方图

plot.show()

输出是这样的:

enter image description here

虽然这个问题似乎要求使用 matplotlib.hist()函数绘制直方图,但是可以说,使用后半部分的问题要求使用给定的概率作为条形图的 y 值,使用给定的名称(字符串)作为 x 值,这是不可能完成的。

我假设一个名字的样本列表对应给定的概率绘制的图。对于给定的问题,这里使用一个简单的条形图。可使用以下代码:

import matplotlib.pyplot as plt
probability = [0.3602150537634409, 0.42028985507246375,
0.373117033603708, 0.36813186813186816, 0.32517482517482516,
0.4175257731958763, 0.41025641025641024, 0.39408866995073893,
0.4143222506393862, 0.34, 0.391025641025641, 0.3130841121495327,
0.35398230088495575]
names = ['name1', 'name2', 'name3', 'name4', 'name5', 'name6', 'name7', 'name8', 'name9',
'name10', 'name11', 'name12', 'name13'] #sample names
plt.bar(names, probability)
plt.xticks(names)
plt.yticks(probability) #This may be included or excluded as per need
plt.xlabel('Names')
plt.ylabel('Probability')

这是一个古老的问题,但以前的答案都没有涉及到真正的问题,也就是说,问题在于问题本身。

首先,如果概率已经计算出来了,即直方图聚合数据以规范化的方式可用,那么概率加起来应该是1。他们显然没有,这意味着这里有问题,无论是术语或数据或问题的方式。

其次,标签被提供的事实(而不是间隔)通常意味着概率是分类响应变量——使用条形图绘制直方图是最好的(或者一些黑客的 pyplot 的 hist 方法) ,Shayan Shafiq 的答案提供了代码。

然而,参见问题1,这些概率是不正确的,在这种情况下使用柱状图作为“直方图”将是错误的,因为它没有告诉单变量分布的故事,出于某种原因(也许类是重叠的,观察值被计算多次在这种情况下,这样的图不应该称为直方图。

根据定义,直方图是单变量分布的图形表示(参见 直方图 | NIST/SEMATECH 电子统计方法手册直方图 | 维基百科) ,通过绘制代表感兴趣变量的选定类别中的观察计数或观察频率的大小条形来创建。如果变量是在一个连续的尺度上度量的,那么这些类就是箱(间隔)。直方图创建过程的重要部分是选择如何对分类变量的响应类别进行分组(或不进行分组) ,或者如何将连续类型变量的可能值域分割为区间(在哪里放置 bin 边界)。所有的观察都应该被表示出来,而且每个观察只能在情节中表示一次。这意味着条形尺寸的总和应该等于观察的总数(或者在宽度可变的情况下它们的面积,这是一种不太常见的方法)。或者,如果直方图是标准化的,那么所有的概率必须加起来为1。

如果数据本身是一个“概率”列表作为一个响应,即观察值是每个研究对象的概率值,那么最好的答案是简单的 plt.hist(probability)可能装箱选项,使用 x 标签已经是可疑的。

条形图不应该用作直方图,而应该用作简单的直方图

import matplotlib.pyplot as plt
probability = [0.3602150537634409, 0.42028985507246375,
0.373117033603708, 0.36813186813186816, 0.32517482517482516,
0.4175257731958763, 0.41025641025641024, 0.39408866995073893,
0.4143222506393862, 0.34, 0.391025641025641, 0.3130841121495327,
0.35398230088495575]
plt.hist(probability)
plt.show()

结果

enter image description here

在这种情况下,matplotlib 默认带有以下直方图值

(array([1., 1., 1., 1., 1., 2., 0., 2., 0., 4.]),
array([0.31308411, 0.32380469, 0.33452526, 0.34524584, 0.35596641,
0.36668698, 0.37740756, 0.38812813, 0.39884871, 0.40956928,
0.42028986]),
<a list of 10 Patch objects>)

结果是一个数组元组,第一个数组包含观测计数,即什么将显示对图的 y 轴(他们加起来为13,观测总数)和第二个数组是 x 轴的区间边界。

我们可以检查它们的间距是否相等,

x = plt.hist(probability)[1]
for left, right in zip(x[:-1], x[1:]):
print(left, right, right-left)

enter image description here

或者,例如对于3个箱子(我的判断需要13个观察值) ,一个可以得到这个直方图

plt.hist(probability, bins=3)

enter image description here

“监狱后面”的情节数据

enter image description here

这个问题的作者需要澄清“概率”值列表的含义——“概率”只是响应变量的名称(那么为什么有 x 标签准备直方图,它是没有意义的) ,或者列表值是从数据计算出来的概率(然后事实上他们没有加起来1是没有意义的)。