将一条直线拟合到一个对数-对数曲线上

6
我手头有一个在两个轴上都是对数的图表。我使用pyplot的loglog函数来实现这一点。它还给我提供了两个轴上的对数刻度。
现在,使用numpy,我对我拥有的点集进行直线拟合。然而,当我将这条直线绘制在图表上时,我无法得到一条直线。我得到的是一条弯曲的线。 蓝线是所谓的“直线”。它没有被绘制成直线。我想将一条直线拟合到由红点绘制的曲线上

蓝线是所谓的“直线”。它没有被绘制成直线。我想将这条直线拟合到由红点绘制的曲线上。
以下是我用于绘制这些点的代码:
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()

你只是在对数刻度上绘制直线,不是吗? - Andrzej Pronobis
是的,没错。但是我该如何使用matplotlib绘制它,使其完美地覆盖在线上? - Rohit Shinde
3个回答

10
为了更好地理解这个问题,首先让我们谈谈普通的线性回归(在这种情况下,“polyfit”函数是您的线性回归算法)。
假设您有一组数据点(x,y),如下所示:
您想创建一个模型,它将y预测为x的函数,因此您使用线性回归。这使用模型:y = mx + b,并使用一些线性代数计算出最佳预测数据的m和b值。
接下来,您使用模型根据x预测y的值。您可以通过选择一组x值(比如linspace)并计算对应的y值来完成这项工作。绘制(x,y)对可以给出回归线。
现在,让我们谈谈对数回归。在这种情况下,我们仍然有两个变量y和x,并且我们仍然对它们之间的关系感兴趣,即能够预测y给定x的值。唯一的区别是,现在yx恰好是另外两个变量的对数,我称之为log(F)log(R)。到目前为止,这只是一个简单的名称变更。
线性回归也是同样的。您仍然是以y为因变量,x为自变量进行回归分析。线性回归算法不在乎yx实际上是log(F)log(R) - 对算法没有影响。
最后一步有点不同-这就是您在上面的图中被绊倒的地方。您要做的是计算: F = m R + b

但这是不正确的,因为FR之间的关系不是线性的。(这就是你使用对数-对数图的原因。)

相反,您应该计算:

log(F) = m log(R) + b

如果您对此进行转换(两边取10的幂并重新排列),则会得到:

F = c R^m

其中c = 10^b。这是FR之间的关系:它是一个幂率关系。 (幂律关系是对数-对数图最擅长的领域。)

在您的代码中,调用polyfit时使用了 A 和 B,但您应该使用log(A)log(B)


5

您的线性拟合不是在对数-对数图中所示的相同数据上进行的。

请按照以下方式创建a和b的numpy数组

a = numpy.asarray(a, dtype=float)
b = numpy.asarray(b, dtype=float)

现在你可以对它们执行操作。log-log图所做的是将a和b的对数取以10为底。您可以通过以下方式执行相同的操作:
logA = numpy.log10(a)
logB = numpy.log10(b)

这是log-log图可视化的内容。通过将logA和logB作为常规图绘制来检查此内容。在log数据上重复线性拟合,并在与logA、logB数据相同的图中绘制您的线条。

coefficients = numpy.polyfit(logB, logA, 1)
polynomial = numpy.poly1d(coefficients)
ys = polynomial(b)
plt.plot(logB, logA)
plt.plot(b, ys)

应该将 ys = polynomial(logB) 吗? - Brandon Dube

3
其他答案提供了很好的解释与解决方案。然而,我想提出一个解决方案,它对我自己有很大帮助,可能也会对你有所帮助。
下面的代码中还有另一种简单的编写适合于对数-对数坐标轴上的线性拟合的方法,即函数powerfit。它接收原始的 xy 数据,并通过使用多个新的 x 值,在对数-对数坐标轴上获得一条直线。在当前情况下,值xnewx相同(它们都是b)。
定义新的 x 坐标的好处是,您可以根据需要获取功率拟合线的尽可能少或尽可能多的点。
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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接