如何使用 Python 创建 qq-plot?
假设您有大量测量数据,并且正在使用某种以 XY 值作为输入的绘图函数。该函数应根据某些分布(正态、均匀......)的相应分位数绘制测量值的分位数。
结果图让我们可以评估我们的测量是否遵循假设的分布。
http://en.wikipedia.org/wiki/Quantile-quantile_plot
R 和 Matlab 都为此提供了现成的函数,但我想知道在 Python 中实现的最干净的方法是什么。
更新:正如人们指出的那样,这个答案是不正确。概率图与分位数-分位数图不同。在您在解释或传达您的发行版关系时犯错误之前,请先查看这些评论和其他答案。
我认为
scipy.stats.probplot
会做你想做的事。有关更多详细信息,请参阅文档。
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()
结果
使用
qqplot
的 statsmodels.api
是另一种选择:
非常基本的例子:
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()
结果:
文档和更多示例位于此处
如果您需要对一个样本与另一个样本进行 QQ 图,statsmodels 包含 qqplot_2samples()。就像 Ricky Robinson 在上面的评论中一样,我认为这是 QQ 图与概率图,概率图是针对理论分布的样本。
我想出了这个。也许你可以改进它。尤其是生成分布分位数的方法对我来说似乎很麻烦。
您可以将
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)
为了增加 Python 和 R 世界中 Q-Q 图和概率图的混乱,这是 SciPy 手册 所说的:
"
生成概率图,不应混淆 具有 Q-Q 或 P-P 图。 Statsmodels 具有更广泛的功能 对于这种类型,请参阅 statsmodels.api.ProbPlot。”probplot
如果您尝试
scipy.stats.probplot
,您会发现它确实将数据集与理论分布进行了比较。 Q-Q 图,OTOH,比较两个数据集(样本)。
R 具有函数
qqnorm
、qqplot
和 qqline
。来自 R 帮助(版本 3.6.3):
是一个通用函数,其默认方法会生成一个 y 值的正态 QQ 图。qqnorm
添加一行 “理论”,默认情况下,正常的分位数-分位数图通过 通过概率分位数,默认为第一和第三四分位数。qqline
生成两个数据集的 QQ 图。qqplot
简而言之,R 的
qqnorm
提供的功能与 scipy.stats.probplot
使用默认设置 dist=norm
提供的功能相同。但事实上他们称其为qqnorm
并且它应该“产生正常的QQ情节”可能很容易让用户感到困惑。
最后,警告一句。这些图不能取代适当的统计测试,仅用于说明目的。
您可以使用散景
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)
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"
您的样本有多大?这是使用 OpenTURNS 库针对任何分布测试数据的另一个选项。在下面的示例中,我从均匀分布生成 1.000.000 个数字的样本 x,并根据正态分布对其进行测试。 如果将 x 重塑为
x= [[x1], [x2], .., [xn]]
,则可以将 x 替换为您的数据
import openturns as ot
x = ot.Uniform().getSample(1000000)
g = ot.VisualTest.DrawQQplot(x, ot.Normal())
g
如果你正在写脚本,你可以做得更恰当
from openturns.viewer import View`
import matplotlib.pyplot as plt
View(g)
plt.show()
这是另一个解决方案
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
def QQ_plot(data):
# Sort as increasing
y = np.sort(data)
# Compute mean and std
mean, std = np.mean(y), np.std(y)
# Compute set of Normal quantiles
ppf = norm(loc=mean, scale=std).ppf # Inverse CDF
N = len(y)
x = [ppf( i/(N+2) ) for i in range(1,N+1)]
# Make the QQ scatter plot
plt.scatter(x, y)
# Plot diagonal line
dmin, dmax = np.min([x,y]), np.max([x,y])
diag = np.linspace(dmin, dmax, 1000)
plt.plot(diag, diag, color='red', linestyle='--')
plt.gca().set_aspect('equal')
# Add labels
plt.xlabel('Normal quantiles')
plt.ylabel('Sample quantiles')
# Make up some dummy data and test
x = np.random.normal(loc=5.0, scale=0.5, size=1000)
QQ_plot(x)
与上述其他解决方案相比,该解决方案的优点是