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

使用Scipy curve_fit拟合幂律分布结果异常的问题排查

问题分析与修复方案

你的curve_fit拟合结果异常,主要是以下几个操作失误导致的:

1. Bounds参数格式完全错误

你写的bounds = ([2, 3])不符合curve_fit的要求。这个参数需要传入两个独立的数组:第一个是所有参数的下限,第二个是所有参数的上限。因为你只拟合alpha这一个参数,正确写法应该是bounds=([2], [3])。之前的写法会被解析成“第一个参数下限2,第二个参数下限3”,但你的函数只有一个参数,导致约束逻辑混乱,最终alpha被强制卡在下限2。

2. 拟合数据的权重逻辑不匹配powerlaw库

powerlaw库拟合时,会自动用每个度数的出现频次作为权重(相当于把原始度数列表里的每个节点都纳入计算),但你用curve_fit时直接传了unique_degrees和counts_pdf——这相当于把每个不同度数当成权重相同的独立点,而社交网络里小度数节点的数量远多于大度数节点,这种处理会让小度数点完全主导拟合结果,最终得到偏小的alpha值。

解决办法:要么给curve_fit传入权重(用频次的平方根作为sigma,对应泊松误差),要么直接基于原始度数数据拟合。

3. 幂律函数的形式与拟合目标不匹配

powerlaw库默认拟合的是互补累积分布函数(CCDF),或者会对离散度数的概率质量函数(PMF)做正确归一化。你自定义的函数是连续幂律的PDF,直接用来拟合离散度数的PMF会有系统偏差,尤其是大度数区域。更稳定的做法是拟合CCDF,因为它在对数坐标下更接近线性,拟合难度更低。


修正后的Curve_fit代码(匹配powerlaw逻辑)

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

# 第一步:确保数据和powerlaw拟合时一致,过滤xmin=1及以上的度数
filtered_degree = [d for d in degree if d >= 1]
unique_degrees, counts = np.unique(filtered_degree, return_counts=True)
counts_pdf = counts / len(filtered_degree)  # 归一化为PMF

# 自定义离散幂律PMF函数(xmin=1时的归一化形式)
def powerlaw_pmf(x, alpha):
    # 计算离散归一化因子(近似,当x范围大时也可以用黎曼和)
    norm_factor = np.sum(np.power(np.arange(1, max(unique_degrees)+1), -alpha))
    return np.power(x, -alpha) / norm_factor

# 正确的bounds格式
bounds = ([2], [3])
p0 = [2.5]

# 传入频次平方根作为sigma,给大度数点更高的权重(小度数计数误差小,权重低)
params, _ = curve_fit(powerlaw_pmf, unique_degrees, counts_pdf, 
                      p0=p0, bounds=bounds, sigma=np.sqrt(counts)/len(filtered_degree))

print("alpha = ", params[0])

# 绘图对比
x = np.linspace(min(unique_degrees), max(unique_degrees), 1000)
y1 = powerlaw_pmf(x, *params)

plt.loglog(unique_degrees, counts_pdf, 'o', label='Degree Distribution')
plt.loglog(x, y1, c='g', label='Fitted Power Law')
plt.legend()
plt.show()

更稳定的方案:拟合CCDF

# 计算互补累积分布函数CCDF:P(X >= x)
sorted_degrees = np.sort(filtered_degree)
ccdf = 1 - np.arange(len(sorted_degrees)) / len(sorted_degrees)
# 提取唯一度数对应的CCDF值
unique_ccdf_x = np.unique(sorted_degrees)
unique_ccdf_y = [ccdf[sorted_degrees == x][0] for x in unique_ccdf_x]

# xmin=1时的幂律CCDF形式
def powerlaw_ccdf(x, alpha):
    return np.power(x / 1, -(alpha - 1))

params, _ = curve_fit(powerlaw_ccdf, unique_ccdf_x, unique_ccdf_y, 
                      p0=p0, bounds=bounds)

print("alpha = ", params[0])

# 绘图
x = np.linspace(min(unique_ccdf_x), max(unique_ccdf_x), 1000)
y1 = powerlaw_ccdf(x, *params)

plt.loglog(unique_ccdf_x, unique_ccdf_y, 'o', label='Degree CCDF')
plt.loglog(x, y1, c='g', label='Fitted Power Law CCDF')
plt.legend()
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 13:45:22