如何为Matplotlib概率轴+对数轴散点图添加线性拟合
如何给概率Y轴+对数X轴的散点图添加线性拟合?
要给这种特殊刻度的散点图加线性拟合,核心思路是在刻度变换后的空间里做线性回归——因为你的Y轴是概率刻度(本质是正态分位数变换/Probit变换),X轴是对数刻度,直接对原始数据做线性拟合是不符合视觉上的线性趋势的。下面是具体的实现步骤和完整代码:
步骤解析
- 处理极端值:原始Y数据里的
0和100会导致Probit变换出错(正态分布的分位数在0和1处是无穷大),所以我们先把它们替换成你设置的Y轴边界值0.1和99.9。 - 数据变换:
- 对X轴数据做自然对数变换(对应对数刻度的逻辑);
- 对Y轴数据先转成0-1的概率,再做Probit变换(把百分比概率转换成正态分布的Z分数)。
- 线性回归:在变换后的
log(X)和Probit(Y)空间里做线性拟合,得到斜率和截距。 - 生成拟合线:在原始X的范围内取足够多的点,用拟合参数计算出对应的拟合Y值(再转换回百分比概率),然后绘制到图上。
完整代码
import matplotlib.pyplot as plt import probscale import numpy as np from scipy.stats import linregress, norm # 原始数据 x = [0.25,0.28,0.3,0.35,0.4,0.45,0.5,0.58,0.65,0.7,0.8,1,1.3,1.6,2,2.5,3] y = [0,0.577629967,1.155259933,1.680378085,2.485559251,3.920882198,4.98862244, 10.13478033,18.32662349,23.15771048,33.81760896,47.43567303,70.13828111, 82.74111675,94.78382636,98.09207072,100] # 处理Y中的0和100,替换为轴边界值避免变换报错 y_processed = np.array(y) y_processed[y_processed == 0] = 0.1 y_processed[y_processed == 100] = 99.9 # 数据变换:X取对数,Y做Probit变换(转成0-1概率后求正态分位数) log_x = np.log(x) probit_y = norm.ppf(y_processed / 100) # 线性回归拟合,得到斜率、截距及拟合指标 slope, intercept, r_value, p_value, std_err = linregress(log_x, probit_y) # 生成拟合线的X点(覆盖原始X的完整范围) x_fit = np.linspace(0.2, 3.5, 100) # 计算拟合的Probit Y值,再转换回百分比概率 probit_y_fit = slope * np.log(x_fit) + intercept y_fit = norm.cdf(probit_y_fit) * 100 # 绘制图像 fig, ax = plt.subplots(figsize=(8, 6)) ax.set_yscale('prob') ax.set_ylim(bottom=0.1, top=99.9) ax.set_ylabel('Cumulative mass(%)') ax.set_xscale('log') ax.set_xlim(left=0.2, right=3.5) ax.set_xlabel('Diameter') # 绘制散点和拟合线,添加图例展示拟合效果 plt.scatter(x, y, label='Original data') plt.plot(x_fit, y_fit, color='red', label=f'Linear fit (R²={r_value**2:.3f})') plt.legend() plt.show()
代码说明
- 用
scipy.stats.norm.ppf实现Probit变换,和probscale概率刻度的底层逻辑一致,保证拟合线和视觉上的线性趋势完全匹配; - 图例中添加了R²值,可以直观评估拟合的好坏;
- 生成
x_fit时用了100个点,确保拟合线足够平滑。
内容的提问来源于stack exchange,提问作者xiaosu
相关产品推荐
相关产品推荐

