如何适应对数刻度[重复]

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

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

【讨论】:

以上是关于如何适应对数刻度[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何格式化双对数 x 轴刻度标签以显示为 10 的幂?

在R中标记对数刻度显示

Matplotlib 对数刻度刻度标签数字格式

python使用np.logspace函数在对数刻度上创建一个对数等距数组实战:在对数刻度上创建一个数组(指定数值个数以及是否包含末尾界值)使用不同的基数(底数)在对数刻度上构建等距数组可视化

Matplotlib - 如何使用对数刻度设置线图的颜色条

使用 d3 对数刻度而不是线性刻度