Python 两个不等长分布的 Q-Q 和 P-P 图

Python Q-Q and P-P plot of two distributions of unequal length

我不确定 best/most 统计上合理的方法来完成我想要的是什么,但我基本上是在尝试获取 p 值的分布并将其与更大的 p- 分布进行比较通过排列我的原始数据创建的值。我使用的是小 p 值,所以我实际上是在比较 p 值的 log10。

我一直在努力寻找一种通用的方法来比较两个具有相似值但长度不等的数组。我真正想要的是 scipy.qqplot(dataset1, dataset2) 之类的东西,但它不存在,Q-Q 图仅将您的分布与已建立的分布进行比较(这个问题也被问到 R:https://stats.stackexchange.com/questions/12392/how-to-compare-two-datasets-with-q-q-plot-using-ggplot2)。

本质上这相当于比较两个直方图。我可以使用 np.linspace 为每个分布强制使用完全相同的垃圾箱:

bins = 100
mx = max(np.max(vector1), np.max(vector2))
mn = min(np.min(vector2), np.max(vector2))
boundaries = np.linspace(mn, mx, bins, endpoint=True)
labels = [(boundaries[i]+boundaries[i+1])/2 for i in range(len(boundaries)-1)]

然后我可以轻松地使用这些边界和标签来制作两个直方图,由原始向量的长度加权。最简单的方法就是使用几个 bin 并将它们绘制为同一轴上的直方图,就像这个问题一样:

但是,我真的想要更像 Q-Q 图的东西,我想使用很多 bin,这样我就可以看到与 1 比 1 线的微小偏差。仅绘制两个直方图的问题在于它们看起来像这样:

两个地块正好重叠,我什么都看不到。

所以我想弄清楚的是,如何比较这两个直方图同时保持 bin 标签。我可以很容易地将两者绘制成散点图,但最终会被 bin 频率索引:

我真正想要的是比较两个直方图,或者绘制差异的 Q-Q 图,但我想不出一个好的统计方法来做这件事。我找不到任何方法可以让我用两个数据集而不是一个数据集和一个内置分布来制作 Q-Q 图,而且我找不到任何方法来绘制两个长度不等的分布。

作为参考,这里是创建该图的两个直方图,您可以看到它们非常相似:

我知道一定有一个很好的方法来做这件事,因为它看起来很明显,但我对这种事情很陌生,而且对 scipy、pandas 和统计模型也。

我故意没有在这里提供示例分布,因为我不确定如何制作一组最小的非正态分布的数组并捕获我正在尝试做的事情;加上要点是能够对任何两个重叠的不等长数组执行此操作。

我想知道的是 right/best 以统计合理的方式解决 python 中这个问题的方法是什么?是否有某种方法可以根据可用于统计模型或 scipy Q-Q 图的置换数据创建分布?有没有办法像这样直观地比较两个直方图?有没有我不知道的制作概率图的方法?


编辑:尝试累积和手动 Q-Q 图

感谢@user333700 的回答,我想出了如何为数据创建手动 QQ 图以及累积概率图。我使用具有重叠 min/max 但以下分布的数据创建了图:

QQ剧情:

q = np.linspace(0, 100, 101)
fig, ax = plt.subplots()
ax.scatter(np.percentile(ytest, q), np.percentile(xtest, q))

所以这对简单数据非常有效,累积图类似:

# Pick bins
x = ytest
y = xtest
boundaries = sorted(x)[::round(len(x)/bins)+1]
labels = [(boundaries[i]+boundaries[i+1])/2 for i in range(len(boundaries)-1)]

# Bin two series into equal bins
xb = pd.cut(x, bins=boundaries, labels=labels)
yb = pd.cut(y, bins=boundaries, labels=labels)

# Get value counts for each bin and sort by bin
xhist = xb.value_counts().sort_index(ascending=True)/len(xb)
yhist = yb.value_counts().sort_index(ascending=True)/len(yb)

# Make cumulative
for ser in [xhist, yhist]:
    ttl = 0
    for idx, val in ser.iteritems():
        ttl += val
        ser.loc[idx] = ttl

# Plot it
fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(xhist, yhist)
plt.show()

回到我实际的偏斜数据(除了长度之外,这两个分布在各个方面都非常相似)并添加一对一的线,我得到了这两个:

所以两者都有效,这很好,累积概率图很清楚地显示数据没有太大差异,但 Q-Q 图显示尾部差异很小。

在统计检验方面,scipy 对连续变量进行了两个样本的 Kolmogorov-Smirnov 检验。分箱直方图数据可用于卡方检验。 scipy.stats 还有一个 k 样本 Anderson-Darling 检验。

用于绘图:

两个直方图的概率图等效于绘制两个样本的累积频率,即每个轴上的累积概率对应于 bin 边界。

statsmodels 有一个用于两个样本比较的 qq-plot,但它目前假设样本大小相同。如果样本大小不同,则需要针对相同的概率计算分位数。 https://github.com/statsmodels/statsmodels/issues/2896 https://github.com/statsmodels/statsmodels/pull/3169 (我不记得这是什么状态了。)