matplotlib 如何在log10尺度上正确绘制线性回归?

ykejflvf  于 2023-01-05  发布在  其他
关注(0)|答案(2)|浏览(246)

我正在绘制两个数据列表,即freqdata。Freq代表频率,data是每个频率的数值观测值。
在下一步中,我将在freqdata之间应用普通线性最小二乘回归,在对数标度上使用stats.linregress,我的目标是在双对数标度内应用线性回归,而不是在正态标度上。
在此之前,我将freqdata都转换为np.log10,因为我计划使用plt.loglog在对数标度上绘制线性回归直线。

**问题:**问题是以红色绘制的回归线与以绿色绘制的实际数据相距甚远。我假设代码中的plt.loglog存在问题,因此绿色数据和红色回归线之间存在视觉距离。如何解决此问题,以便回归线绘制在实际数据之上?

下面是我的可复制代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# Data
freq = [0.0102539, 0.0107422, 0.0112305, 0.0117188, 0.012207, 0.0126953,
        0.0131836]
data = [4.48575,  4.11893,  3.69591,  3.34766,  3.18452,  3.23554,  3.43357]

# Plot log10 of freq vs. data
plt.loglog(freq, data, c="green")

# Linear regression
log_freq = np.log10(freq)
log_data = np.log10(data)

reg = stats.linregress(log_freq, log_data)
slope = reg[0]
intercept = reg[1]

plt.plot(freq, slope*log_freq + intercept, color="red")

下面是代码结果的屏幕截图:

abithluo

abithluo1#

您可以先将数据集转换为以10为底的对数,然后进行线性回归并相应地绘制它们。
注意,在对数转换之后,log_freq中的数字将全部为负;因此x轴不能是对数标度的。

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# Data
freq = np.array([0.0102539, 0.0107422, 0.0112305, 0.0117188, 0.012207, 0.0126953,
                 0.0131836])
data = np.array([4.48575, 4.11893, 3.69591, 3.34766, 3.18452, 3.23554, 3.43357])

# transform date to log base 10
log_freq = np.log10(freq)
log_data = np.log10(data)

# Plot freq vs. data
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(log_freq, log_data, c="green", label='Original data (log 10 base)')

# Linear regression
reg = stats.linregress(log_freq, log_data)

# Plot fitted freq vs. data
ax.plot(log_freq, reg.slope * log_freq + reg.intercept, color="red",
        label='Fitted line on the original data (log 10 base)')

plt.legend()
plt.tight_layout()
plt.show()

参考文献:

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html
https://numpy.org/doc/stable/reference/generated/numpy.log10.html#

4dbbbstv

4dbbbstv2#

首先,我质疑双对数坐标轴的必要性,因为数据的范围,或者至少是你给我们看的数据的范围,在两个坐标上都是有限的。
在下面的代码中,我有

  • 计算了你的数组以10为底的对数

  • 使用线性回归公式,但使用数据的对数来获得直线方程:

                y = a + B·x

也就是说,在对数空间中
因为对数空间中的直线对应于数据空间中的幂律,y = pow(10,a)·pow(x,b),所以我画出了

  • 原始数据,以log-log表示,以及
  • 幂律,也是对数-对数,

获得双对数表示中的直线。

import matplotlib.pyplot as plt
from math import log10
freq = [.0102539, .0107422, .0112305, .0117188, .012207, .0126953, .0131836]
data = [4.48575, 4.11893, 3.69591, 3.34766, 3.18452, 3.23554, 3.43357]
n = len(freq)

# the following block of code is the unfolding of the formulas in
# https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html

# START ##############################################    
lx, ly = [[log10(V) for V in v] for v in (freq, data)]
sum_x = sum(x for x in lx)
sum_y = sum(y for y in ly)
sum_x2 = sum(x**2 for x in lx)
sum_y2 = sum(y**2 for y in ly)
sum_xy = sum(x*y for x, y in zip(lx, ly))

# coefficients of a straight line "y = a + b x" in log-log space
b = (n*sum_xy - sum_x*sum_y)/(n*sum_x2-sum_x**2)
a = (sum_y - b*sum_x)/n
A = pow(10, a)
# END  ##############################################    

plt.loglog(freq, data)
plt.loglog(freq, [A*pow(x, b) for x in freq])

相关问题