在 matplotlib 中将直线拟合到对数对数曲线
Fitting a straight line to a log-log curve in matplotlib
我有一个图,它在两个轴上都是对数的。我有 pyplot 的 loglog
函数来执行此操作。它还为我提供了两个轴上的对数刻度。
现在,我使用 numpy 将一条直线拟合到我拥有的点集。但是,当我在图上绘制这条线时,我无法得到一条直线。我得到一条曲线。
蓝线应该是"straight line"。它没有被直接绘制。我想把这条直线拟合到红点绘制的曲线
这是我用来绘制点的代码:
import numpy
from matplotlib import pyplot as plt
import math
fp=open("word-rank.txt","r")
a=[]
b=[]
for line in fp:
string=line.strip().split()
a.append(float(string[0]))
b.append(float(string[1]))
coefficients=numpy.polyfit(b,a,1)
polynomial=numpy.poly1d(coefficients)
ys=polynomial(b)
print polynomial
plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()
您的线性拟合不是对对数对数图中显示的相同数据执行的。
像这样制作 a 和 b numpy 数组
a = numpy.asarray(a, dtype=float)
b = numpy.asarray(b, dtype=float)
现在您可以对它们进行操作了。 loglog-plot 的作用是对 a 和 b 取以 10 为底的对数。您也可以通过
logA = numpy.log10(a)
logB = numpy.log10(b)
这是对数对数图的可视化。通过将 logA 和 logB 绘制为常规图来检查这一点。对日志数据重复线性拟合,并在与 logA、logB 数据相同的图中绘制直线。
coefficients = numpy.polyfit(logB, logA, 1)
polynomial = numpy.poly1d(coefficients)
ys = polynomial(b)
plt.plot(logB, logA)
plt.plot(b, ys)
为了更好地理解这个问题,让我们首先谈谈简单的线性回归(polyfit
函数,在这种情况下,是您的线性回归算法)。
假设您有一组数据点 (x,y),如下所示:
您想要创建一个模型来预测 y
作为 x
的函数,因此您使用线性回归。使用模型:
y = mx + b
并使用一些线性代数计算最能预测您的数据的 m
和 b
的值。
接下来,您使用模型预测 y 值作为 x 的函数。为此,您可以为 x 选择一组值(想想 linspace)并计算相应的 y 值。绘制这些 (x,y) 对可以得到回归线。
现在,我们来谈谈对数回归。在这种情况下,我们仍然有两个变量,y 与 x,我们仍然对它们的关系感兴趣,即能够预测 y
给定 x
。唯一的区别是,现在 y
和 x
恰好是另外两个变量的对数,我称之为 log(F)
和 log(R)
。到目前为止,这只不过是一个简单的名称更改。
线性回归也以同样的方式工作。您仍在回归 y 与 x。线性回归算法不关心 y
和 x
实际上是 log(F)
和 log(R)
- 它对算法没有影响。
最后一步有点不同 - 这就是您在上面的情节中被绊倒的地方。你正在做的是计算
F = m R + b
但这是不正确的,因为 F
和 R
之间的关系不是线性的。 (这就是您使用双对数图的原因。)
相反,您应该计算
log(F) = m log(R) + b
如果你对此进行变换(增加 10 的双方的次方并重新排列),你会得到
F = c R^m
其中 c = 10^b
。这就是F
和R
之间的关系:是幂律关系。 (幂律关系是双对数图最擅长的。)
在您的代码中,您在调用 polyfit
时使用了 A 和 B,但您应该使用 log(A)
和 log(B)
。
其他答案提供了很好的解释和解决方案。但是,我想提出一个对我有很大帮助的解决方案,也许对您也有帮助。
另一种编写适合对数-对数刻度线的简单方法是下面代码中的函数 powerfit
。它采用原始 x
和 y
数据,并通过使用一些新的 x 点,您可以获得对数对数刻度的直线。在当前情况下,值 xnew
与 x
相同(均为 b
)。
定义新 x 坐标的优势在于,无论出于何种目的,您都可以得到尽可能多的 powerfitted 线点。
import numpy as np
from matplotlib import pyplot as plt
import math
def powerfit(x, y, xnew):
"""line fitting on log-log scale"""
k, m = np.polyfit(np.log(x), np.log(y), 1)
return np.exp(m) * xnew**(k)
fp=open("word-rank.txt","r")
a=[]
b=[]
for line in fp:
string=line.strip().split()
a.append(float(string[0]))
b.append(float(string[1]))
ys = powerfit(b, a, b)
plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()
我有一个图,它在两个轴上都是对数的。我有 pyplot 的 loglog
函数来执行此操作。它还为我提供了两个轴上的对数刻度。
现在,我使用 numpy 将一条直线拟合到我拥有的点集。但是,当我在图上绘制这条线时,我无法得到一条直线。我得到一条曲线。
蓝线应该是"straight line"。它没有被直接绘制。我想把这条直线拟合到红点绘制的曲线
这是我用来绘制点的代码:
import numpy
from matplotlib import pyplot as plt
import math
fp=open("word-rank.txt","r")
a=[]
b=[]
for line in fp:
string=line.strip().split()
a.append(float(string[0]))
b.append(float(string[1]))
coefficients=numpy.polyfit(b,a,1)
polynomial=numpy.poly1d(coefficients)
ys=polynomial(b)
print polynomial
plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()
您的线性拟合不是对对数对数图中显示的相同数据执行的。
像这样制作 a 和 b numpy 数组
a = numpy.asarray(a, dtype=float)
b = numpy.asarray(b, dtype=float)
现在您可以对它们进行操作了。 loglog-plot 的作用是对 a 和 b 取以 10 为底的对数。您也可以通过
logA = numpy.log10(a)
logB = numpy.log10(b)
这是对数对数图的可视化。通过将 logA 和 logB 绘制为常规图来检查这一点。对日志数据重复线性拟合,并在与 logA、logB 数据相同的图中绘制直线。
coefficients = numpy.polyfit(logB, logA, 1)
polynomial = numpy.poly1d(coefficients)
ys = polynomial(b)
plt.plot(logB, logA)
plt.plot(b, ys)
为了更好地理解这个问题,让我们首先谈谈简单的线性回归(polyfit
函数,在这种情况下,是您的线性回归算法)。
假设您有一组数据点 (x,y),如下所示:
您想要创建一个模型来预测 y
作为 x
的函数,因此您使用线性回归。使用模型:
y = mx + b
并使用一些线性代数计算最能预测您的数据的 m
和 b
的值。
接下来,您使用模型预测 y 值作为 x 的函数。为此,您可以为 x 选择一组值(想想 linspace)并计算相应的 y 值。绘制这些 (x,y) 对可以得到回归线。
现在,我们来谈谈对数回归。在这种情况下,我们仍然有两个变量,y 与 x,我们仍然对它们的关系感兴趣,即能够预测 y
给定 x
。唯一的区别是,现在 y
和 x
恰好是另外两个变量的对数,我称之为 log(F)
和 log(R)
。到目前为止,这只不过是一个简单的名称更改。
线性回归也以同样的方式工作。您仍在回归 y 与 x。线性回归算法不关心 y
和 x
实际上是 log(F)
和 log(R)
- 它对算法没有影响。
最后一步有点不同 - 这就是您在上面的情节中被绊倒的地方。你正在做的是计算
F = m R + b
但这是不正确的,因为 F
和 R
之间的关系不是线性的。 (这就是您使用双对数图的原因。)
相反,您应该计算
log(F) = m log(R) + b
如果你对此进行变换(增加 10 的双方的次方并重新排列),你会得到
F = c R^m
其中 c = 10^b
。这就是F
和R
之间的关系:是幂律关系。 (幂律关系是双对数图最擅长的。)
在您的代码中,您在调用 polyfit
时使用了 A 和 B,但您应该使用 log(A)
和 log(B)
。
其他答案提供了很好的解释和解决方案。但是,我想提出一个对我有很大帮助的解决方案,也许对您也有帮助。
另一种编写适合对数-对数刻度线的简单方法是下面代码中的函数 powerfit
。它采用原始 x
和 y
数据,并通过使用一些新的 x 点,您可以获得对数对数刻度的直线。在当前情况下,值 xnew
与 x
相同(均为 b
)。
定义新 x 坐标的优势在于,无论出于何种目的,您都可以得到尽可能多的 powerfitted 线点。
import numpy as np
from matplotlib import pyplot as plt
import math
def powerfit(x, y, xnew):
"""line fitting on log-log scale"""
k, m = np.polyfit(np.log(x), np.log(y), 1)
return np.exp(m) * xnew**(k)
fp=open("word-rank.txt","r")
a=[]
b=[]
for line in fp:
string=line.strip().split()
a.append(float(string[0]))
b.append(float(string[1]))
ys = powerfit(b, a, b)
plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()