如何用scipy.stats.probplot绘制p值的负log10分布QQ图
解决方法
你的问题出在对probplot的使用逻辑理解上:R代码是将转换后的理论均匀分位数与转换后的样本p值做对比,而你之前的Python代码错误地将转换后的p值(服从指数分布)与原始均匀分布的分位数做了对比,自然无法得到重合的对角线。
以下是两种正确实现方式:
方法一:用probplot对接指数分布
当p值服从均匀分布时,-log10(p)服从指数分布(参数为scale=1/np.log(10))。直接用这个分布作为probplot的对比基准即可:
import numpy as np import matplotlib.pyplot as plt from scipy import stats # 生成模拟数据(替换成你的真实p值数据) p_values_data = np.random.uniform(0, 1, 1000) # 转换p值 transformed_p = -np.log10(p_values_data) # 计算指数分布的scale参数 scale_param = 1 / np.log(10) # 绘制QQ图 stats.probplot(transformed_p, dist="expon", sparams=(0, scale_param), plot=plt) plt.title("QQ Plot: -log10(p值) vs 理论指数分布") plt.show()
方法二:手动实现与R完全一致的样本vs样本QQ图
如果要完全复刻R中qqplot的逻辑(直接对比转换后的理论分位数和转换后的样本分位数),可以手动计算理论分位数后绘制:
import numpy as np import matplotlib.pyplot as plt from scipy import stats # 生成模拟数据(替换成你的真实p值数据) p_values_data = np.random.uniform(0, 1, 1000) n = len(p_values_data) # 计算理论分位数(对应R中的ppoints) theoretical_quantiles = -np.log10(stats.uniform.ppf(np.linspace(0.5/n, 1-0.5/n, n))) # 计算样本分位数 sample_quantiles = np.sort(-np.log10(p_values_data)) # 绘制QQ图 plt.scatter(theoretical_quantiles, sample_quantiles, alpha=0.6) plt.plot([min(theoretical_quantiles), max(theoretical_quantiles)], [min(theoretical_quantiles), max(theoretical_quantiles)], 'r--', label="参考对角线") plt.xlabel("理论 -log10(均匀分布) 分位数") plt.ylabel("样本 -log10(p值) 分位数") plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者Ozan.kah
相关产品推荐
相关产品推荐

