matplotlib hist函数的density参数无效。

20
plt.histdensity参数无效。 我试图在我的图中使用plt.hist函数中的density参数来规范化股票回报率,但它没有起作用。 以下代码对我很有效,并给了我所需的概率密度函数。
import matplotlib
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(19680801)

# example data
mu = 100  # mean of distribution
sigma = 15  # standard deviation of distribution
x = mu + sigma * np.random.randn(437)

num_bins = 50

plt.hist(x, num_bins, density=1)

plt.show()

图表显示密度

但是当我使用股票数据时,它根本不起作用。结果给出了未归一化的数据。我在我的数据数组中没有发现任何异常数据。

import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
plt.hist(returns, 50,density = True)
plt.show()
# "returns" is a np array consisting of 360 days of stock returns

密度不起作用


数组([0.0188179947,-0.00467532468,0.00985850151,0.00338807856, 0.00623819607,0.0137640769,-0.00224416517,-0.0283400810, -0.0409722222,-0.00289645185,-0.0139191479,0.00435743218, 0.00348304308,-0.0115698453,0.0181123706,0.0232361128, 0.0441750444,0.00181231240,0.0392334219,0.00723494533, 0.00480665370,0.00704111798,0.0143040137,-0.00762997264]) - riversxiao
我尝试将数据类型转换为浮点型,但结果仍然相同。 - riversxiao
第二个图你还期望它是什么样子的? - Sheldore
1
@ImportanceOfBeingErnest 我想他期望在垂直轴上看到每个条形的概率值。在底部的图片中,你可以看到值从0变化到40。我猜他期望它在0和1之间变化。 - Blade
2
这个回答能解决你的问题吗?pylab.hist(data, normed=1). Normalization seems to work incorrect - Arne
显示剩余4条评论
5个回答

9

这是Matplotlib中已知的一个问题。

正如在错误报告:pyplot.hist()中的density标志未能正确工作中所述:

当 density = False 时,直方图会在 Y 轴上显示计数。但是当 density = True 时,Y 轴不表示任何有用信息。我认为更好的实现方式是,在 density = True 时将 PDF 绘制为直方图。

开发人员认为这是一项功能而非错误,因为它保持了与 numpy 的兼容性。他们已经关闭了几个关于此的错误报告,原因是它按照预期运行。更让人困惑的是,matplotlib 网站上的示例似乎展示了这项功能,并为 Y 轴分配了有意义的值。

你想在 matplotlib 中做的事情是合理的,但 matplotlib 不会以那种方式让你实现它。


2

这不是bug。 条形图的面积等于1。 数字之所以看起来奇怪,是因为你的分组大小很小。


1

由于这个问题还没有解决;基于@user14518925的回答,实际上是正确的,这将bin宽度视为一个实际有效的数字,而根据我的理解,您希望每个bin的宽度为1,以使频率总和为1。更简洁地说,您看到的是:

\sum_{i}y_{i}\times\text{bin size} =1

而您想要的是:

\sum_{i}y_{i} =1

因此,您真正需要改变的只是y轴上的刻度标签。一种方法是禁用密度选项:

density = false

然后按照总样本量进行除法运算,就像你的示例中所示:

import matplotlib
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(19680801)

# example data
mu = 0 # mean of distribution
sigma = 0.0000625  # standard deviation of distribution
x = mu + sigma * np.random.randn(437)

fig = plt.figure()
plt.hist(x, 50, density=False)
locs, _ = plt.yticks() 
print(locs)
plt.yticks(locs,np.round(locs/len(x),3))
plt.show()

1
起初,我也认为这是个问题。我认为y轴上显示的刻度值不应大于1。这意味着该区间的频率大于总频率,这根本没有任何意义。
经过一段时间的思考,我明白了实际发生的事情。我们期望返回的是概率分布函数,即(一个区间的观察频率)/(总频率)。但是Matplotlib返回的密度是(一个区间的观察频率)/(总频率 * 每个区间的长度)。如果每个区间的长度小于1,那么该区间的密度可能超过1。但是直方图下的总面积仍然为1。因为所有区间的密度*区间长度之和 = 所有频率之和 / 总频率 = 1。所以你得到的值是完全正确的,也是有意义的。
希望这个解释对你有帮助。

0

除了tvbc的方法之外,另一种方法是更改绘图中的y轴刻度。

import matplotlib.pyplot as plt
import numpy as np

steps = 10
bins = np.arange(0, 101, steps)
data = np.random.random(100000) * 100

plt.hist(data, bins=bins, density=True)
yticks = plt.gca().get_yticks()
plt.yticks(yticks, np.round(yticks * steps, 2))
plt.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接