【问题标题】:How to minimize chi squared for 3 linear fits如何最小化 3 次线性拟合的卡方
【发布时间】:2016-02-29 21:31:03
【问题描述】:
from numpy import *
import matplotlib.pyplot as plt
import numpy as np

# This is my data set
x = [15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240]
y = [1, 0.9, 0.8, 0.7, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.33, 0.31, 0.29, 0.27, 0.25, 0.23]

我想向这个数据集添加 3 个线性回归。通过用 pyplot 绘制我的数据集,我可以直观地看到扭结开始形成的位置(大约在 x = 105 和 x = 165 处)。所以我可以创建 3 个线性回归(从 x 是 0 到 105、105 到 165 和 165 到 240)。但是我该如何科学地做到这一点?换句话说,我想在我的数据中添加 3 个线性回归,以最小化卡方。有没有办法用代码来完成这个?

【问题讨论】:

  • 我没有得到你想要达到的效果。你想得到三个不同的参数集(每个线性回归一个)?
  • 我知道如何为我的数据创建 3 个单独的线性拟合并计算相应的卡方值,但我只是通过拆分我的 x,y 列表来做到这一点。我想创建一个算法来为我拆分列表,以便所有 3 个线性拟合的卡方最小化。
  • 我更新了我的答案;它现在自动拆分 x 和 y,我还在 for 循环中添加了更多细节。让我知道您是否还有其他问题!

标签: python numpy linear-regression curve-fitting chi-squared


【解决方案1】:

您可以在下面找到使用scipy.stats.linregress 的自动化程序的代码和输出;解释可以在代码下方找到。输出如下:

斜率和截距项为:

  • 曲线 1:-0.0066 * x + 1.10
  • 曲线 2:-0.0033 * x + 0.85
  • 曲线 3:-0.0013 * x + 0.55

代码如下:

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

x = np.array([15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240])
y = np.array([1, 0.9, 0.8, 0.7, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.33, 0.31, 0.29, 0.27, 0.25, 0.23])

# get slope of your data
dif = np.diff(y) / np.diff(x)

# determine the change of the slope
difdif = np.diff(dif)

# define a threshold for the allowed change of the slope
threshold = 0.001

# get indices where the diff returns value larger than a threshold
indNZ = np.where(abs(difdif) > threshold)[0]

# this makes plotting easier and avoids a couple of if clauses
indNZ += 1
indNZ = np.append(indNZ, len(x))
indNZ = np.insert(indNZ, 0, 0)

# plot the data
plt.scatter(x, y)

for indi, ind in enumerate(indNZ):

    if ind < len(x):
        slope, intercept, r_value, p_value, std_err = stats.linregress(x[ind:indNZ[indi+1]], y[ind:indNZ[indi+1]])
        plt.plot(x[ind:indNZ[indi+1]], slope * x[ind:indNZ[indi+1]] + intercept)

plt.show()

首先,可以使用np.diff 计算斜率。将np.diff 应用于坡度会为您提供坡度变化显着的点;在上面的代码中,我为此使用了一个阈值(如果您总是处理完美的线条,则可以将其设置为一个非常小的值;如果您有嘈杂的数据,则必须调整此值)。

有了斜率显着变化的指数,就可以在各个部分进行线性回归并相应地绘制结果。

更详细的for循环:

indNZ

array([ 0,  4,  9, 16])

它为您提供三行的间隔。所以蓝线对应x[0]x[3]的部分,绿线对应x[4]x[8]的部分,红线对应x[9]x[15]的部分。在 for 循环中,选择这些范围,使用 scipy.stats.linregress 完成线性拟合(如果您更喜欢,也可以将其替换为 polyfit),然后使用等式 slope * x + intercept 绘制线。 /p>

【讨论】:

  • 对不起,我的问题可能不是很清楚。我不想为我的 3 个线性拟合选择范围。我想创建一个算法来为我做这件事。例如,假设我错误地将 x 范围选择为 0 到 100、100 到 200 和 200 到 240。这个范围的卡方值会太大。我希望算法能够找到最小化卡方的 3 个范围。我有点知道如何做到这一点,但它对我来说太复杂了,无法实现。感谢您的尝试!
  • 我更新了代码。请让我知道现在是否可以解决问题或是否需要修改。
  • 我不熟悉 stats.linregress。我使用 polyfit 来创建线性拟合。你能解释一下你在for循环中做了什么吗?谢谢!
  • @PiccolMan:我又添加了一些 cmets。您可以将stats.linregress 替换为polyfit,没问题。棘手的部分是更多地确定indNZ; for循环只是选择适当的范围,进行线性拟合并绘制结果。这有帮助吗?
  • 谢谢!如果我自己无法弄清楚,我会尝试。
猜你喜欢
  • 1970-01-01
  • 2012-08-29
  • 2021-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 2014-04-06
相关资源
最近更新 更多