如何适应对数刻度[重复]
Posted
技术标签:
【中文标题】如何适应对数刻度[重复]【英文标题】:How to fit to a log scale [duplicate] 【发布时间】:2013-12-27 20:00:39 【问题描述】:我有以下几点
0 4194304
1 497420
2 76230
3 17220
4 3595
5 1697
6 491
7 184
8 54
9 15
10 4
11 4
12 1
13 1
14 1
15 1
16 1
17 1
18 1
19 1
20 1
21 1
如果我在 y 轴上使用对数刻度绘制它们,它们看起来大致呈线性。如何将一条直线拟合到此对数刻度,以便拟合数据?
我当前的代码非常粗糙。对于我做的每一对 x,y。
xcoords.append(x)
ycoords.append(math.log(y))
最后我会这样做
plt.plot(xcoords,ycoords)
plt.show()
【问题讨论】:
IIRC,这叫做对数回归,或者类似的东西。 这可能是相关的:***.com/questions/3433486/… 【参考方案1】:您可以尝试切零(x[0:12]),从(x[0:12],log_y[0:12])生成函数插值,在相同范围内生成更大的线性空间 x 是 12 项 new_x 是50个项目在空间范围(不是项目索引)0,x[11],用f(new_x)作图,如下:
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
>>> y
[4194304, 497420, 76230, 17220, 3595, 1697, 491, 184, 54, 15, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
>>> log_y
[15.249237972318797, 13.117190018630332, 11.24151036498232, 9.753826777981722, 8.187299270155147, 7.436617265234227, 6.19644412779452, 5.214935757608986, 3.9889840465642745, 2.70805020110221, 1.3862943611198906, 1.3862943611198906, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
>>> f2=interp1d(x[0:12],log_y[0:12],kind='cubic')
>>> x_new_fit=np.linspace(0,x[11],50)
>>> plt.plot(x_new_fit,f2(x_new_fit),'-')
[<matplotlib.lines.Line2D object at 0x3a6e950>]
>>> plt.show()
尝试不同类型的插值,达到不同的平滑度
>>>
>>> f1=interp1d(x[0:12],log_y[0:12],kind='quadratic')>>> plt.plot(x[0:12],log_y[0:12],'-',x_new_fit,f2(x_new_fit),'-',x_new_fit,f1(x_new_fit),'--')
[<matplotlib.lines.Line2D object at 0x3a97dd0>, <matplotlib.lines.Line2D object at 0x3a682d0>, <matplotlib.lines.Line2D object at 0x3a687d0>]
>>> plt.show()
>>>
【讨论】:
【参考方案2】:您可以将其绘制在半对数图上,而不是更改数据。所以例如你可以这样做:
import matplotlib.pyplot as plt
xArray = range(22)
yArray = [4194304,497420,76230,17220,3595,1697,491,184,54,15,4,4,1,1,1,1,1,1,1,1,1,1]
plt.semilogy(xArray,yArray)
plt.show
至于进行代码拟合 - 请尝试以下操作:
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from numpy import square
xArray = range(22)
yArray = [4194304,497420,76230,17220,3595,1697,491,
184,54,15,4,4,1,1,1,1,1,1,1,1,1,1]
def f(x,a,b,c):
return a*(square(x))+(b*x)+c
popt, pcov = curve_fit(f, xArray, yArray)
fittedA = popt[0]
fittedB = popt[1]
fittedC = popt[1]
yFitted = f(xArray,fittedA,fittedB,fittedC)
plt.figure()
plt.semilogy(xArray,yFitted)
plt.show
你需要想出一个比我在 f() 函数中使用的二次函数更好的拟合函数来获得一个很好的拟合,但这应该可以满足你的需要。
【讨论】:
【参考方案3】:此解决方案使用来自 numpy (docs) 的最小二乘拟合方法。
此页面提供线性回归的example usage 线性数据。
因为你有对数线性数据,那么这里我们先转换数据,然后进行线性拟合。
import numpy as np
import matplotlib.pyplot as plt
d = '''
0 4194304
1 497420
... (put all the rest of the data in here)
'''
D = np.loadtxt(d.split('\n'))
x = D[:,0]
y = D[:,1]
y_ln = np.log(y)
n = D.shape[0]
A = np.array(([[x[j], 1] for j in range(n)]))
B = np.array(y_ln[0:n])
X = np.linalg.lstsq(A,B)[0]
a=X[0]; b=X[1]
# so now your fitted line is log(y) = a*x + b
# lets show it on a graph.
plt.figure()
plt.plot(x, a*x+b, '--')
plt.plot(x, y_ln, 'o')
plt.ylabel('log y')
plt.xlabel('x values')
plt.show()
# or use the original scales by transforming the data back again:
plt.figure()
plt.plot(x, np.exp(a*x+b), '--')
plt.plot(x, y, 'o')
plt.ylabel('y')
plt.xlabel('x values')
plt.yscale('log')
plt.show()
但是,您的数据似乎有两种状态,因此单个线性拟合不会 很好地捕捉数据。你可以把它描述为两种不同的制度, 这可能合适也可能不合适,具体取决于您的数据来自哪里,以及 能否解释一下这两种制度的变化点。
因此,让我们获取数据的第一部分并适合它
n = 13
A = np.array(([[x[j], 1] for j in range(n)]))
B = np.array(yl[0:n])
A = np.array(([[x[j], 1] for j in range(n)]))
B = np.array(y_ln[0:n])
X = np.linalg.lstsq(A,B)[0]
a=X[0]; b=X[1]
plt.figure()
plt.plot(x[0:n], np.exp(a*x[0:n]+b), '--')
plt.plot(x, y, 'o')
plt.ylabel('y')
plt.xlabel('x values')
plt.yscale('log')
plt.show()
这更适合数据的第一部分(但它可能不是特别有意义——这取决于生成数据点的过程)。
【讨论】:
以上是关于如何适应对数刻度[重复]的主要内容,如果未能解决你的问题,请参考以下文章
python使用np.logspace函数在对数刻度上创建一个对数等距数组实战:在对数刻度上创建一个数组(指定数值个数以及是否包含末尾界值)使用不同的基数(底数)在对数刻度上构建等距数组可视化