使用 SciPy 的分位数-分位数图
Posted
技术标签:
【中文标题】使用 SciPy 的分位数-分位数图【英文标题】:Quantile-Quantile Plot using SciPy 【发布时间】:2012-12-01 16:22:27 【问题描述】:你会如何使用 Python 创建一个 qq-plot?
假设您有大量测量值,并且正在使用一些将 XY 值作为输入的绘图函数。该函数应根据某些分布(正态、均匀...)的相应分位数绘制测量值的分位数。
结果图让我们可以评估我们的测量是否遵循假设的分布。
http://en.wikipedia.org/wiki/Quantile-quantile_plot
R 和 Matlab 都为此提供了现成的函数,但我想知道在 Python 中实现的最简洁的方法是什么。
【问题讨论】:
你看过probplot
吗? docs.scipy.org/doc/scipy/reference/generated/…
qqplot 和 probplots 有很多选项:statsmodels.sourceforge.net/devel/…
【参考方案1】:
更新:正如人们指出的那样,这个答案不正确。概率图不同于分位数-分位数图。在解释或传达分布关系时出错之前,请先查看这些 cmets 和其他答案。
我认为scipy.stats.probplot
会做你想做的事。详情请参阅documentation。
import numpy as np
import pylab
import scipy.stats as stats
measurements = np.random.normal(loc = 20, scale = 5, size=100)
stats.probplot(measurements, dist="norm", plot=pylab)
pylab.show()
结果
【讨论】:
有时我看到一些虚线的置信线在中间变窄,在末端就像喇叭一样。您可以将这些“指导线”添加到情节中吗? 好的,但这是一个概率图(样本与理论分布)。 qq 图比较两个样本。 itl.nist.gov/div898/handbook/eda/section3/qqplot.htmitl.nist.gov/div898/handbook/eda/section3/probplot.htm @RickyRobinson 似乎许多来源(包括***)与 NIST 手册相矛盾。几乎所有其他来源都表明 QQ 图在水平轴上有理论分位数,而数据在垂直轴上有分位数。无论如何,区别是学术性的:绘制样本与使用经验分布函数基本相同。无论哪种方式,您都在绘制一个分布的分位数与另一个分布的分位数。 我同意@RickyRobinson,这不是这个问题的正确答案。 QQ 图和概率图是不同的,尽管它们都是一个分布的分位数。 来自文档:“probplot 生成概率图,不应与 Q-Q 或 P-P 图混淆。”【参考方案2】:使用statsmodels.api
中的qqplot
是另一种选择:
非常基本的例子:
import numpy as np
import statsmodels.api as sm
import pylab
test = np.random.normal(0,1, 1000)
sm.qqplot(test, line='45')
pylab.show()
结果:
文档和更多示例是here
【讨论】:
@tommy.carstensen 它被故意从scipy
分离到statsmodels
只是一个注释。您的示例为标准正态分布画了一条线。要获得像@Geoff 示例中那样的标准化线(按给定样本的标准差缩放并添加平均值),您需要设置 line='s' 而不是 line='45'
这个答案+1。我认为将更多资源集中在单个统计数据包上很重要。 statsmodels
会是个不错的选择。【参考方案3】:
如果您需要绘制一个样本与另一个样本的 QQ 图,statsmodels 包括 qqplot_2samples()。就像上面评论中的 Ricky Robinson 一样,我认为这是 QQ 图与概率图的对比,概率图是针对理论分布的样本。
http://statsmodels.sourceforge.net/devel/generated/statsmodels.graphics.gofplots.qqplot_2samples.html
【讨论】:
这个 qqplot 实现似乎不能处理不同大小的样本,这很有趣,因为 QQ 图的一大优点是可以比较不同大小的样本......【参考方案4】:我想出了这个。也许你可以改进它。特别是生成分布分位数的方法对我来说似乎很麻烦。
您可以将 np.random.normal
替换为来自 np.random
的任何其他分布,以将数据与其他分布进行比较。
#!/bin/python
import numpy as np
measurements = np.random.normal(loc = 20, scale = 5, size=100000)
def qq_plot(data, sample_size):
qq = np.ones([sample_size, 2])
np.random.shuffle(data)
qq[:, 0] = np.sort(data[0:sample_size])
qq[:, 1] = np.sort(np.random.normal(size = sample_size))
return qq
print qq_plot(measurements, 1000)
【讨论】:
【参考方案5】:它现在存在于 statsmodels 包中:
http://statsmodels.sourceforge.net/devel/generated/statsmodels.graphics.gofplots.qqplot.html
【讨论】:
【参考方案6】:你可以使用散景
from bokeh.plotting import figure, show
from scipy.stats import probplot
# pd_series is the series you want to plot
series1 = probplot(pd_series, dist="norm")
p1 = figure(title="Normal QQ-Plot", background_fill_color="#E8DDCB")
p1.scatter(series1[0][0],series1[0][1], fill_color="red")
show(p1)
【讨论】:
【参考方案7】:为了增加 Python 和 R 世界中 QQ 图和概率图的混淆,SciPy manual 是这样说的:
"
probplot
生成概率图,不要混淆 使用 Q-Q 或 P-P 图。 Statsmodels 具有更广泛的功能 这种类型的,请参见 statsmodels.api.ProbPlot。”
如果您尝试scipy.stats.probplot
,您会发现它确实将数据集与理论分布进行了比较。 QQ图,OTOH,比较两个数据集(样本)。
R 具有函数qqnorm
、qqplot
和qqline
。来自 R 帮助(版本 3.6.3):
qqnorm
是一个泛型函数,其默认方法产生一个 y 值的正态 QQ 图。qqline
将一行添加到 “理论”,默认情况下正常的分位数 - 分位数图,通过 通过概率分位数,默认为第一和第三四分位数。
qqplot
生成两个数据集的 QQ 图。
简而言之,R 的qqnorm
提供的功能与scipy.stats.probplot
在默认设置dist=norm
下提供的功能相同。但他们称它为qqnorm
并且它应该“产生一个正常的 QQ 情节”这一事实可能很容易让用户感到困惑。
最后一句警告。这些图不能代替适当的统计测试,仅用于说明目的。
【讨论】:
【参考方案8】:import numpy as np
import pylab
import scipy.stats as stats
measurements = np.random.normal(loc = 20, scale = 5, size=100)
stats.probplot(measurements, dist="norm", plot=pylab)
pylab.show()
这里 probplot 绘制图形测量值与 dist="norm" 中指定的正态分布
【讨论】:
【参考方案9】:您的样本有多大?这是使用OpenTURNS library 针对任何分布测试您的数据的另一个选项。在下面的示例中,我从均匀分布中生成了一个包含 1.000.000 个数字的样本 x,并针对正态分布对其进行了测试。
如果您将 x 重塑为 x= [[x1], [x2], .., [xn]]
import openturns as ot
x = ot.Uniform().getSample(1000000)
g = ot.VisualTest.DrawQQplot(x, ot.Normal())
g
在我的 Jupyter Notebook 中,我看到:
如果你在写脚本,你可以做得更好
from openturns.viewer import View`
import matplotlib.pyplot as plt
View(g)
plt.show()
【讨论】:
以上是关于使用 SciPy 的分位数-分位数图的主要内容,如果未能解决你的问题,请参考以下文章