使用 SciPy 绘制分位数-分位数图

问题描述 投票:0回答:10

如何使用 Python 创建 qq-plot?

假设您有大量测量数据,并且正在使用某种以 XY 值作为输入的绘图函数。该函数应根据某些分布(正态、均匀......)的相应分位数绘制测量值的分位数。

结果图让我们可以评估我们的测量是否遵循假设的分布。

http://en.wikipedia.org/wiki/Quantile-quantile_plot

R 和 Matlab 都为此提供了现成的函数,但我想知道在 Python 中实现的最干净的方法是什么。

python statistics scipy
10个回答
129
投票

更新:正如人们指出的那样,这个答案是不正确。概率图与分位数-分位数图不同。在您在解释或传达您的发行版关系时犯错误之前,请先查看这些评论和其他答案。

我认为

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()

结果

enter image description here


70
投票

使用

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()

结果:

enter image description here

文档和更多示例位于此处


25
投票

如果您需要对一个样本与另一个样本进行 QQ 图,statsmodels 包含 qqplot_2samples()。就像 Ricky Robinson 在上面的评论中一样,我认为这是 QQ 图与概率图,概率图是针对理论分布的样本。

http://statsmodels.sourceforge.net/devel/ generated/statsmodels.graphics.gofplots.qqplot_2samples.html


7
投票

我想出了这个。也许你可以改进它。尤其是生成分布分位数的方法对我来说似乎很麻烦。

您可以将

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)

4
投票

为了增加 Python 和 R 世界中 Q-Q 图和概率图的混乱,这是 SciPy 手册 所说的:

"

probplot
生成概率图,不应混淆 具有 Q-Q 或 P-P 图。 Statsmodels 具有更广泛的功能 对于这种类型,请参阅 statsmodels.api.ProbPlot。”

如果您尝试

scipy.stats.probplot
,您会发现它确实将数据集与理论分布进行了比较。 Q-Q 图,OTOH,比较两个数据集(样本)。

R 具有函数

qqnorm
qqplot
qqline
。来自 R 帮助(版本 3.6.3):

qqnorm
是一个通用函数,其默认方法会生成一个 y 值的正态 QQ 图。
qqline
添加一行 “理论”,默认情况下,正常的分位数-分位数图通过 通过概率分位数,默认为第一和第三四分位数。

qqplot
生成两个数据集的 QQ 图。

简而言之,R 的

qqnorm
提供的功能与
scipy.stats.probplot
使用默认设置
dist=norm
提供的功能相同。但事实上他们称其为
qqnorm
并且它应该“产生正常的QQ情节”可能很容易让用户感到困惑。

最后,警告一句。这些图不能取代适当的统计测试,仅用于说明目的。



2
投票

您可以使用散景

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)

1
投票
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"


1
投票

您的样本有多大?这是使用 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

在我的 Jupyter Notebook 中,我看到:

如果你正在写脚本,你可以做得更恰当

from openturns.viewer import View`
import matplotlib.pyplot as plt
View(g)
plt.show()

0
投票

这是另一个解决方案

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)

与上述其他解决方案相比,该解决方案的优点是

  1. 不假设平均值为0
  2. 使用逆 CDF 的解析表达式(而不是样本)
  3. 轻松根据需要修改 matplotlib 参数
  4. 易于编辑以使用与 scipy.stats 不同的发行版
© www.soinside.com 2019 - 2024. All rights reserved.