如何适应对数刻度

时间:2013-12-10 10:37:52

标签: python matplotlib

我有以下几点

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()

3 个答案:

答案 0 :(得分:1)

此解决方案使用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()

fitting all the data

但是,您的数据似乎有两个制度,因此单个线性拟合不会 很好地捕获数据。你可以把它描述为两个不同的政权, 根据您的数据来源和来源,这可能适合也可能不适合 你是否可以解释两种制度发生变化的点。

因此,让我们来看看数据的第一部分,然后再适合

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()

fitting part of the data

这更适合数据的第一部分(但可能没有特别意义 - 这取决于生成数据点的过程)。

答案 1 :(得分:1)

您可以将其绘制在半对数图上,而不是更改数据。例如,您可以这样做:

    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()函数中使用的二次函数得到一个很好的拟合,但这应该做你需要的。

答案 2 :(得分:0)

您可以尝试剪切零(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()
>>>