如何验证数据概率密度是否符合幂律、指数或拉伸指数分布?
验证数据分布:幂律、指数与拉伸指数分布
我需要验证自己的数据概率密度是否符合幂律(power-law)、指数分布(exponential distribution)或拉伸指数函数(stretched exponential function)。目前已经用scipy的powerlaw.fit和expon.fit实现了幂律与指数分布的拟合及检验,但不清楚如何验证拉伸指数分布,现有代码如下:
pip install powerlaw import numpy as np import scipy.stats as stats from scipy.stats import ks_2samp from scipy.stats import powerlaw, expon from scipy.stats import kstest from scipy.optimize import curve_fit from powerlaw import Fit #验证概率密度是否符合幂律或指数分布 data = [120.0, 120.0, 100.0, 25.0, 20.0, 30.0, 28.0, 60.0, 90.0, 30.0, 24.0, 30.0, 30.0] # 将数据拟合到幂律分布 params_powerlaw = powerlaw.fit(data) # 将数据拟合到指数分布 params_exponential = expon.fit(data) # 执行Kolmogorov-Smirnov检验以比较分布 D_powerlaw, p_powerlaw = kstest(data, powerlaw.cdf, args=params_powerlaw) D_exponential, p_exponential = kstest(data, expon.cdf, args=params_exponential) # 打印检验统计量和p值 print('Kolmogorov-Smirnov检验统计量:') print('幂律分布(Power-law):', D_powerlaw) print('指数分布(Exponential):', D_exponential) print('\nKolmogorov-Smirnov检验p值:') print('幂律分布(Power-law):', p_powerlaw) print('指数分布(Exponential):', p_exponential) #打印参数 print("\n幂律分布alpha =", params_powerlaw[0]) print("\n指数分布loc =", params_exponential[0], "scale =", params_exponential[1]) # 比较p值以确定哪个分布拟合效果更好 if p_powerlaw > p_exponential: print('\n数据符合幂律分布(Power-law)。') else: print('\n数据符合指数分布(Exponential)。')
拉伸指数分布的拟合与检验实现
拉伸指数分布的累积分布函数(CDF)形式为:
( F(x; \lambda, \beta) = 1 - e{-(x/\lambda)\beta} )
其中(\lambda > 0)是尺度参数,(\beta > 0)是形状参数(当(\beta=1)时退化为指数分布)。
由于scipy没有直接提供拉伸指数分布的拟合函数,我们可以用scipy.optimize.curve_fit自定义拟合逻辑,再用KS检验验证拟合效果。
修改后的完整代码
import numpy as np import scipy.stats as stats from scipy.stats import powerlaw, expon, kstest from scipy.optimize import curve_fit # 待检验数据 data = [120.0, 120.0, 100.0, 25.0, 20.0, 30.0, 28.0, 60.0, 90.0, 30.0, 24.0, 30.0, 30.0] # 对数据排序,方便后续拟合计算 sorted_data = np.sort(data) # ---------------------- 幂律分布拟合与检验 ---------------------- params_powerlaw = powerlaw.fit(data) D_powerlaw, p_powerlaw = kstest(data, powerlaw.cdf, args=params_powerlaw) # ---------------------- 指数分布拟合与检验 ---------------------- params_exponential = expon.fit(data) D_exponential, p_exponential = kstest(data, expon.cdf, args=params_exponential) # ---------------------- 拉伸指数分布拟合与检验 ---------------------- # 定义拉伸指数的CDF函数 def stretched_exponential_cdf(x, lam, beta): return 1 - np.exp(-(x / lam)**beta) # 初始参数猜测(lam取数据均值,beta初始设为1) initial_guess = [np.mean(data), 1.0] # 拟合参数,设置边界确保参数为正 params_stretched, _ = curve_fit(stretched_exponential_cdf, sorted_data, np.linspace(0, 1, len(sorted_data)), p0=initial_guess, bounds=((0, 0), (np.inf, np.inf))) lam_fit, beta_fit = params_stretched # 用KS检验验证拉伸指数拟合效果 D_stretched, p_stretched = kstest(data, stretched_exponential_cdf, args=(lam_fit, beta_fit)) # ---------------------- 结果输出 ---------------------- print('=== Kolmogorov-Smirnov检验统计量 ===') print(f'幂律分布: {D_powerlaw:.4f}') print(f'指数分布: {D_exponential:.4f}') print(f'拉伸指数分布: {D_stretched:.4f}') print('\n=== Kolmogorov-Smirnov检验p值 ===') print(f'幂律分布: {p_powerlaw:.4f}') print(f'指数分布: {p_exponential:.4f}') print(f'拉伸指数分布: {p_stretched:.4f}') print('\n=== 拟合参数 ===') print(f'幂律分布alpha = {params_powerlaw[0]:.4f}') print(f'指数分布loc = {params_exponential[0]:.4f}, scale = {params_exponential[1]:.4f}') print(f'拉伸指数分布lambda = {lam_fit:.4f}, beta = {beta_fit:.4f}') # 比较p值,p值越大说明拟合效果越好 p_values = {'幂律分布': p_powerlaw, '指数分布': p_exponential, '拉伸指数分布': p_stretched} best_dist = max(p_values, key=p_values.get) print(f'\n数据拟合效果最好的分布是: {best_dist}')
代码说明
- 自定义CDF函数:根据拉伸指数的数学定义实现累积分布函数,用于拟合和检验。
- 参数拟合:用
curve_fit拟合参数,设置初始猜测和参数边界,避免出现非正的无效参数。 - KS检验:和前两个分布逻辑一致,用
kstest对比数据的经验分布和拟合后的拉伸指数分布,得到检验统计量和p值。 - 结果比较:通过比较三个分布的p值,p值越大表示数据与该分布的拟合程度越高。
内容的提问来源于stack exchange,提问作者S C
相关产品推荐
相关产品推荐

