之前讲述了Python 数据正态性检验及Python、R、SPSS正态检测方法,包括图示法、非参数的正态性检验以及峰度-偏度法。参数检验的可靠性最强,但在实际中发现好多变量不满足正态性检验。即使是进行取对数处理之后,仍然不满足。因此退而求其次,采用图示法进行分析。图示法是采用样本分布与理论分布的散点图的贴近程度进行对比,其中,Q-Q图是基于分位数的,P-P图是基于累积分布的。
在Python中,可采用statsmodels包进行实现,具体用到的函数包括statsmodels.api.ProbPlot.qqplot
和statsmodels.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()
完结撒花~