Gráfico quantil-quantil usando SciPy

87

Como você criaria um qq-plot usando Python?

Supondo que você tenha um grande conjunto de medidas e esteja usando alguma função de plotagem que recebe valores XY como entrada. A função deve plotar os quantis das medições contra os quantis correspondentes de alguma distribuição (normal, uniforme ...).

O gráfico resultante nos permite então avaliar em nossa medição segue a distribuição assumida ou não.

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

Tanto R quanto Matlab fornecem funções prontas para isso, mas estou me perguntando qual seria o método mais limpo para implementação em Python.

John
fonte
2
Você já olhou probplot? docs.scipy.org/doc/scipy/reference/generated/…
Geoff
1
qqplot e probplots com várias opções: statsmodels.sourceforge.net/devel/…
Josef

Respostas:

105

Eu acho que scipy.stats.probplotvai fazer o que você quiser. Veja a documentação para mais detalhes.

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

Resultado

insira a descrição da imagem aqui

Geoff
fonte
Às vezes, tenho visto algumas linhas de confiança pontilhadas que se estreitam no meio e são como uma trombeta nas pontas. Você pode adicionar essas "linhas de orientação" ao gráfico?
Norfeldt
21
Ok, mas este é um gráfico de probabilidade (uma amostra vs uma distribuição teórica). Um gráfico qq compara duas amostras. itl.nist.gov/div898/handbook/eda/section3/qqplot.htm itl.nist.gov/div898/handbook/eda/section3/probplot.htm
Ricky Robinson
7
@RickyRobinson Parece que muitas fontes (incluindo a wikipedia) contradizem o manual do NIST. Praticamente qualquer outra fonte afirma que um gráfico QQ tem quantis teóricos no eixo horizontal e quantis de dados verticalmente. Em qualquer caso, a distinção é acadêmica: traçar uma amostra é essencialmente o mesmo que usar a função de distribuição empírica. De qualquer maneira, você está plotando os quantis de uma distribuição contra outra.
Peter
1
Eu concordo com @RickyRobinson, esta não é a resposta correta para esta pergunta. Os gráficos QQ e os prob são diferentes, embora ambos os quantis de uma distribuição sejam comparados com outra.
Florent
49

O uso qqplotde statsmodels.apié outra opção:

Exemplo muito básico:

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

Resultado:

insira a descrição da imagem aqui

A documentação e mais exemplos estão aqui

Akavall
fonte
1
@ tommy.carstensen foi deliberadamente separado de scipyparastatsmodels
SARose
5
Apenas uma nota. Seu exemplo traça a linha para a distribuição normal padrão. Para obter uma linha padronizada (dimensionada pelo desvio padrão da amostra dada e ter a média adicionada) como no exemplo de @Geoff, você precisa definir line = 's' em vez de line = '45 '
Mike
1 para esta resposta. Acho que é importante concentrar mais recursos em um único pacote de estatísticas. statsmodelsseria uma boa escolha.
Ken T
20

Se você precisar fazer um gráfico QQ de uma amostra em relação a outra, os modelos de estatísticas incluem qqplot_2samples (). Como Ricky Robinson em um comentário acima, isso é o que considero um gráfico QQ versus um gráfico de probabilidade que é uma amostra contra uma distribuição teórica.

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

ccap
fonte
11
Esta implementação de qqplot não parece lidar com amostras com tamanhos diferentes, o que é engraçado porque uma das grandes vantagens de um gráfico QQ é que se pode comparar amostras com tamanhos diferentes ...
Robert Muil
5

Eu vim com isso. Talvez você possa melhorá-lo. Especialmente o método de geração dos quantis da distribuição parece complicado para mim.

Você pode substituir np.random.normalpor qualquer outra distribuição de np.randompara comparar os dados com outras distribuições.

#!/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)
John
fonte
2

Para aumentar a confusão em torno de gráficos QQ e gráficos de probabilidade nos mundos Python e R, isto é o que o manual do SciPy diz:

probplotgera um gráfico de probabilidade, que não deve ser confundido com um gráfico QQ ou PP.

Se você tentar scipy.stats.probplot, verá que de fato compara um conjunto de dados a uma distribuição teórica. Os gráficos QQ, OTOH, comparam dois conjuntos de dados (amostras).

R tem funções qqnorm, qqplote qqline. Da ajuda do R (versão 3.6.3):

qqnormé uma função genérica cujo método padrão produz um gráfico QQ normal dos valores em y. qqlineadiciona uma linha a um gráfico “teórico”, por padrão normal, quantil-quantil que passa pelos quantis probs, por padrão o primeiro e o terceiro quartis.

qqplot produz um gráfico QQ de dois conjuntos de dados.

Resumindo, o R's qqnormoferece a mesma funcionalidade que scipy.stats.probplota configuração padrão dist=norm. Mas o fato de que eles o chamaram qqnorme que ele deveria "produzir um gráfico QQ normal" pode facilmente confundir os usuários.

Finalmente, uma palavra de advertência. Esses gráficos não substituem os testes estatísticos adequados e devem ser usados ​​apenas para fins ilustrativos.

Laryx Decidua
fonte
1

Você pode usar bokeh

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

Aqui o probplot desenha as medidas do gráfico vs distribuição normal que especifique em dist = "norma"

Ravi
fonte
0

Qual é o tamanho da sua amostra? Aqui está outra opção para testar seus dados em qualquer distribuição usando a biblioteca OpenTURNS . No exemplo abaixo, eu gerei uma amostra x de 1.000.000 de números a partir de uma distribuição Uniforme e testo-a contra uma distribuição Normal. Você pode substituir x por seus dados se você reformulá-lo comox= [[x1], [x2], .., [xn]]

import openturns as ot

x = ot.Uniform().getSample(1000000)
g = ot.VisualTest.DrawQQplot(x, ot.Normal())
g

No meu Jupyter Notebook, vejo: insira a descrição da imagem aqui

Se você estiver escrevendo um script, poderá fazê-lo de maneira mais adequada

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