在 Python 中拟合幂律的线性回归
Linear regression to fit a power-law in Python
我有两个数据集 index_list
和 frequency_list
,我用 plt.loglog(index_list, freq_list)
在对数对数图中绘制了它们。现在我正在尝试用线性回归拟合幂律 a*x^(-b)
。我希望曲线紧随初始曲线,但以下代码似乎输出了一条类似的曲线,但在 y 轴上进行了镜像。
我怀疑我使用 curve_fit
很糟糕。
为什么这条曲线在 x 轴上镜像,我如何才能让它正确地适合我的初始曲线?
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
f = open ("input.txt", "r")
index_list = []
freq_list = []
index = 0
for line in f:
split_line = line.split()
freq_list.append(int(split_line[1]))
index_list.append(index)
index += 1
plt.loglog(index_list, freq_list)
def power_law(x, a, b):
return a * np.power(x, -b)
popt, pcov = curve_fit(power_law, index_list, freq_list)
plt.plot(index_list, power_law(freq_list, *popt))
plt.show()
下面的代码做了如下改动:
- 要使 scipy 函数起作用,最好
index_list
和 freq_list
都是 numpy 数组,而不是 Python 列表。另外,为了 power
不会溢出太快,这些数组应该是 float
类型(而不是 int
)。
- 由于
0
负幂会导致 divide-by-zero 问题,因此 index_list
与 1
开始是有意义的。
- 由于权力,对于浮点数也可能产生溢出。因此,为
curve_fit
添加边界是有意义的。特别是 b
应该限制在 50 左右(最高值约为 power(100000, b) giving an overflow when
be.g. is
100)
。同时设置初始值有助于指导拟合过程(p0=...
).
- 用
index_list
作为 x
和 power_law(freq_list, ...)
作为 y
绘制绘图会生成非常奇怪的曲线。有必要对绘图和函数使用相同的 x
。
请注意,调用 plt.loglog()
会将绘图的两个轴更改为对数。同一轴上的所有后续图将继续使用对数刻度。
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import pandas as pd
import numpy as np
def power_law(x, a, b):
return a * np.power(x, -b)
df = pd.read_csv("https://norvig.com/google-books-common-words.txt", delim_whitespace=True, header=None)
index_list = df.index.to_numpy(dtype=float) + 1
freq_list = df[1].to_numpy(dtype=float)
plt.loglog(index_list, freq_list, label='given data')
popt, pcov = curve_fit(power_law, index_list, freq_list, p0=[1, 1], bounds=[[1e-3, 1e-3], [1e20, 50]])
plt.plot(index_list, power_law(index_list, *popt), label='power law')
plt.legend()
plt.show()
我有两个数据集 index_list
和 frequency_list
,我用 plt.loglog(index_list, freq_list)
在对数对数图中绘制了它们。现在我正在尝试用线性回归拟合幂律 a*x^(-b)
。我希望曲线紧随初始曲线,但以下代码似乎输出了一条类似的曲线,但在 y 轴上进行了镜像。
我怀疑我使用 curve_fit
很糟糕。
为什么这条曲线在 x 轴上镜像,我如何才能让它正确地适合我的初始曲线?
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
f = open ("input.txt", "r")
index_list = []
freq_list = []
index = 0
for line in f:
split_line = line.split()
freq_list.append(int(split_line[1]))
index_list.append(index)
index += 1
plt.loglog(index_list, freq_list)
def power_law(x, a, b):
return a * np.power(x, -b)
popt, pcov = curve_fit(power_law, index_list, freq_list)
plt.plot(index_list, power_law(freq_list, *popt))
plt.show()
下面的代码做了如下改动:
- 要使 scipy 函数起作用,最好
index_list
和freq_list
都是 numpy 数组,而不是 Python 列表。另外,为了power
不会溢出太快,这些数组应该是float
类型(而不是int
)。 - 由于
0
负幂会导致 divide-by-zero 问题,因此index_list
与1
开始是有意义的。 - 由于权力,对于浮点数也可能产生溢出。因此,为
curve_fit
添加边界是有意义的。特别是b
应该限制在 50 左右(最高值约为power(100000, b) giving an overflow when
be.g. is
100)
。同时设置初始值有助于指导拟合过程(p0=...
). - 用
index_list
作为x
和power_law(freq_list, ...)
作为y
绘制绘图会生成非常奇怪的曲线。有必要对绘图和函数使用相同的x
。
请注意,调用 plt.loglog()
会将绘图的两个轴更改为对数。同一轴上的所有后续图将继续使用对数刻度。
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import pandas as pd
import numpy as np
def power_law(x, a, b):
return a * np.power(x, -b)
df = pd.read_csv("https://norvig.com/google-books-common-words.txt", delim_whitespace=True, header=None)
index_list = df.index.to_numpy(dtype=float) + 1
freq_list = df[1].to_numpy(dtype=float)
plt.loglog(index_list, freq_list, label='given data')
popt, pcov = curve_fit(power_law, index_list, freq_list, p0=[1, 1], bounds=[[1e-3, 1e-3], [1e20, 50]])
plt.plot(index_list, power_law(index_list, *popt), label='power law')
plt.legend()
plt.show()