Python 绘制Q-Q图/P-P图 检验数据正态性(qqplot, ppplot)

之前讲述了Python 数据正态性检验及Python、R、SPSS正态检测方法,包括图示法、非参数的正态性检验以及峰度-偏度法。参数检验的可靠性最强,但在实际中发现好多变量不满足正态性检验。即使是进行取对数处理之后,仍然不满足。因此退而求其次,采用图示法进行分析。图示法是采用样本分布与理论分布的散点图的贴近程度进行对比,其中,Q-Q图是基于分位数的,P-P图是基于累积分布的。

在Python中,可采用statsmodels包进行实现,具体用到的函数包括statsmodels.api.ProbPlot.qqplotstatsmodels.api.ProbPlot.ppplot,二者是class(类)statsmodels.api.ProbPlot的具体函数实现。

1. 类 statsmodels.api.ProbPlot 介绍

类:statsmodels.api.ProbPlot(data, dist=<scipy.stats._continuous_distns.norm_gen object>, fit=False, distargs=(), a=0, loc=0, scale=1)
简介:便于构造Q-Q, P-P和概率图的类。可以指定dist的参数或自动适合它们。(参见kwargs下面的fit)
参数:

  • data:一维数组,需要输入的数据。
  • dist:一个scipy.stats 或者 statsmodels 的分布,是data需要对比的分布。默认是标准的正态分布scipy.stats.distributions.norm。
  • distargs:tuple类型,传递给dist的参数元组,以便完全指定它调用dist.ppf。
  • loc:float类型,dist的位置参数。
  • a:float类型,期望顺序统计量的绘图位置的偏移量。没遇到过,不是太懂。
  • scale:loat类型,dist的标度参数。
  • fit:布尔型,如果fit是False,loc, scale和distargs参数被传递给分布。如果fit为True,那么dist的参数将使用dist.fit自动匹配。分位数是由标准化数据减去拟合的loc并除以拟合的scale形成的。

该类对应的ProbPlot 对象包含的方法实现:


ProbPlot对象包含的方法

三个主要函数的对比如下:

  • ppplot : Probability-Probability plot. Compares the sample and theoretical probabilities (percentiles).
  • qqplot : Quantile-Quantile plot. Compares the sample and theoretical quantiles.
  • probplot : Probability plot. Same as a Q-Q plot, however probabilities are shown in the scale of the theoretical distribution (x-axis) and the y-axis contains unscaled quantiles of the sample data.

函数主要参数解释:
ProbPlot.ppplot(xlabel=None, ylabel=None, line=None, other=None, ax=None, **plotkwargs)
可以看出,主要设置在line参数,设置参考线。

  • “45”: 45-degree 线
  • “s”: 标准线,期望顺序统计量按给定样本的标准差进行缩放,并将平均值加到其中。
  • “r”: 拟合的回归线
  • “q”: 通过分位数的的直线
  • None: 默认不添加任何参考线

2. Python官方代码实现Q-Q图和P-P图

对官方文档的代码进行解读:

import statsmodels.api as sm
from matplotlib import pyplot as plt

# 样例1
data = sm.datasets.longley.load()
data.exog = sm.add_constant(data.exog)
model = sm.OLS(data.endog, data.exog)
mod_fit = model.fit()
res = mod_fit.resid # 获取了构造的模型的残差,获取了数据
# 主要调用方法
probplot = sm.ProbPlot(res) # 实例probplot
probplot.qqplot(line='s') # 调用函数
Out[10]: <Figure size 640x480 with 1 Axes>
plt.show()
Figure_1.png

以下是指定参数的方法调用,

# 案例2:指定分布类型、自由度
import scipy.stats as stats
probplot = sm.ProbPlot(res, stats.t, distargs=(4,))
fig = probplot.qqplot()
plt.show()

# 案例3:指定标准差和均值
probplot = sm.ProbPlot(res, stats.t, distargs=(4,), loc=3, scale=10)
fig = probplot.qqplot()
plt.show()

# 案例4:自动确定t分布的参数,包括loc和scale
probplot = sm.ProbPlot(res, stats.t, fit=True)
fig = probplot.qqplot(line='45')
plt.show()

# 案例5:第二个ProbPlot对象可以通过使用qqplot和ppplot方法中的另一个kwarg来比较两个独立的样本集
import numpy as np
x = np.random.normal(loc=8.25, scale=2.75, size=37)
y = np.random.normal(loc=8.75, scale=3.25, size=37)
pp_x = sm.ProbPlot(x, fit=True)
pp_y = sm.ProbPlot(y, fit=True)
fig = pp_x.qqplot(line='45', other=pp_y)
plt.show()

另外两个函数的调用方式和Q-Q图的一模一样。

3. 批量简单调用

批量绘制数据的QQ图

# 绘制QQ图检验数据的正态性
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt

def plot_test_normality():
    input_path = "E:\\Data\\"
    df = pd.read_csv(input_path + 'data.csv', header=0, encoding='gbk')
    df = df.drop(['lng', 'lat'], axis=1)
    df = df.dropna(axis=0, how='any')
    for col in list(df.columns):
        figure, axs = plt.subplots(figsize=(8, 6), dpi=600)
        probplot = sm.ProbPlot(np.log10(df[col]), fit=True)
        probplot.ppplot(line='45', ax=axs)
        axs.set_title(str(col))
        plt.tight_layout()
        figure.savefig("E:\\Figures\\normality\\" + str(col) + ".png", dpi=600)

if __name__ == '__main__':
    plot_test_normality()

完结撒花~

参考资料:statsmodels.api.ProbPlot

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容