You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Log-Pearson III分布的极值分位数估计:R与Python对比

Log-Pearson III分布分位数估计:Python与R的结果差异分析

问题背景

使用Log-Pearson III分布对雪深数据进行分位数估计,流程为:读取数据→对数转换→拟合Pearson III分布→估计分位数→对数逆转换。预期Python与R的L矩法结果一致,但实际差异极大,且R结果更符合实际,需明确差异原因并找到Python端的解决方案。

代码实现

Python代码(原错误版本)

import numpy as np
import scipy.stats as stats
import lmoments3 as lm
import lmoments3.distr as ld

data=np.array([[1079],
       [ 889],
       [ 996],
       [1476],
       [1567],
       [ 897],
       [ 991],
       [1222],
       [1372],
       [1450],
       [1077],
       [1354],
       [1029],
       [1699],
       [ 965],
       [1133],
       [1951],
       [1621],
       [1069],
       [ 930],
       [1039],
       [1839]])

return_periods = np.array([2,3,5,10,20,50,100,200,1000])

log_data = np.log(data)
params = stats.pearson3.fit(log_data) #极大似然估计
quantiles = np.exp(stats.pearson3.ppf(1 - 1 / return_periods, *params))

paramsmm=ld.pe3.lmom_fit(log_data) #L矩估计
paramsmm2=(paramsmm["skew"], paramsmm['loc'], paramsmm['scale'][0])
quantilesmm = np.exp(ld.pe3.ppf(1 - 1 / return_periods, *paramsmm2))

print(quantiles)
print(quantilesmm)

R代码

library(lmom)
library(lmomco)

swe_data <- c(1079,
              889,
              996,
              1476,
              1567,
              897,
              991,
              1222,
              1372,
              1450,
              1077,
              1354,
              1029,
              1699,
              965,
              1133,
              1951,
              1621,
              1069,
              930,
              1039,
              1839)

return_periods <- c(2, 3, 5, 10, 20, 50, 100, 200, 1000)
nonexceedance_probabilities <- 1 - 1/return_periods

log_swe <- log(swe_data)
loglmoments <- lmom.ub(log_swe)
fit_LP3 <- parpe3(loglmoments)
LP3_est <- exp(quape3(nonexceedance_probabilities, fit_LP3))

print(LP3_est)

结果对比

  • MLE/scipy stats:
    参数:(2.0246, 7.1081, 0.3219) # skew, loc, scale
    分位数:[1105.86 1259.46 1484.67 1857.19 2324.18 3127.69 3916.20 4904.15 8271.24]
    
  • Lmoments/python(原错误实现):
    参数:(-2.2194, 7.1069, 0.0754) # skew, loc, scale
    分位数:[1251.31 1276.35 1291.30 1300.07 1303.59 1305.32 1305.79 1305.99 1306.11]
    
  • Lmoments/R:
    参数:(7.1069, 0.2567, 0.9365) # mu, sigma, gamma
    分位数:[1173.12 1313.85 1485.11 1721.13 1969.82 2326.81 2623.11 2945.73 3814.69]
    

差异原因分析

  1. 数据维度错误:原Python代码中data是二维数组,对数转换后仍为二维结构,lmoments3计算L矩时会按列处理,导致矩估计结果完全错误,直接引发参数偏差。
  2. 参数定义与顺序不匹配:
    • R的parpe3返回参数顺序为位置参数(mu)、尺度参数(sigma)、L矩偏度(gamma);
    • Python的lmoments3.pe3.lmom_fit返回的skew是Pearson III的形状参数,与R的gamma偏度存在数学转换关系,且原代码参数传递顺序错误,进一步放大了结果差异。
  3. 尺度参数缩放差异:lmoments3返回的scale参数与R的sigma参数并非直接对应,未做转换会导致分位数计算偏差。

Python端修正方案

调整数据维度,匹配参数定义与转换逻辑,修正后的代码如下:

import numpy as np
import lmoments3.distr as ld

data = np.array([
    1079, 889, 996, 1476, 1567, 897, 991, 1222, 1372, 1450,
    1077, 1354, 1029, 1699, 965, 1133, 1951, 1621, 1069, 930, 1039, 1839
])

return_periods = np.array([2,3,5,10,20,50,100,200,1000])
nonexceedance_probs = 1 - 1 / return_periods

# 转为一维数组,修正L矩计算的维度问题
log_data = np.log(data.flatten())

# 拟合Pearson III分布
fit_pe3 = ld.pe3.lmom_fit(log_data)

# 用正确的参数顺序调用ppf,确保参数定义匹配
quantiles_lmom_correct = np.exp(ld.pe3.ppf(nonexceedance_probs, fit_pe3['skew'], fit_pe3['loc'], fit_pe3['scale']))

print("修正后Python L矩分位数:", quantiles_lmom_correct)

修正后,Python的L矩分位数结果将与R的结果一致,符合实际业务预期。


内容的提问来源于stack exchange,提问作者Kingle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:39:55