拟合回归模型以记录分布式数据

机器算法验证 回归 数据转换
2022-03-20 00:43:09

我正在分析算法在对输入变量的小扰动下的性能。我包含了一些 python 代码来帮助使我的问题更具体,但原则上这是一个关于回归分析中变量转换的问题。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from numpy.polynomial.polynomial import polyfit
from scipy.optimize import curve_fit

df = pd.read_csv("https://tinyurl.com/qulhd3w")

x = df.eps
y = df.dist

plt.loglog(x, y, 'x', label='Distance to Solution')

# Try for example, a linear model
func = lambda t, alpha, beta: alpha * t + beta

popt, pcov = curve_fit(func, x, y)
poly = np.poly1d(popt)

yfit = lambda x: poly(x)

plt.plot(x, yfit(x))
plt.show()

由上面的代码生成的图

我的 x 变量似乎有一个对数分布,我的 y 变量也是如此。loglog 图中的关联似乎有点 sigmoid,但对于我的大部分域来说是线性的,所以我想我会从尝试添加线性回归线开始。

我意识到数据相当嘈杂,所以我天真地尝试从仅对均值执行回归开始。

means = df.groupby('eps').mean()
[x, y] = [means.index, means.dist]
plt.loglog(x, y)

func = lambda t, a, b, c, d: a * t**3 + b * t**2 + c * t + d 

popt, pcov = curve_fit(func, 10**x, 10**y)
poly = np.poly1d(popt)

yfit = lambda x: np.log10(poly(10**x))

plt.plot(x, yfit(x))

指数变换下均值的 Polyfit

结果对于指数变换线性回归也不是很好。回归似乎对接近 0 的值不够敏感。我应该尝试加权最小二乘之类的方法吗?

为了在这个日志空间中执行回归,我需要如何转换我的变量?我试图通过采取10x10y使它们近似线性,但没有得到很好的结果。理想情况下,我可能想要拟合类似逻辑趋势模型的东西,这可以通过将“func”行替换为

func = lambda t, alpha, beta, gamma: alpha / (1 + beta * np.exp(-gamma * t))

1个回答

两点:

  1. 您的数据是对数对数比例的。那你为什么不记录他们的日志呢?
  2. 既然您期望数据背后有一个 sigmoid 函数,为什么不尝试将其拟合到数据中呢?

下面,我将您的对数转换数据建模为两个 softplus 函数的(缩放)差异,y=log(1+ex),加上一个常数项:

y=log(1+eα1+βx)log(1+eα2+βx)+C

这是一个 sigmoid 函数,其线性上升部分可以根据需要制作: Sigmoid 函数

这是我的代码:

# first, log-convert the data:
x = np.log10(df.eps)
y = np.log10(df.dist)

plt.plot(x, y, 'x', label='log-distance to Solution')

# the function to fit:
# the difference of two scaled softplus, plus a constant term:
func = lambda t, alpha1, alpha2, beta, C : \
  np.log(1+np.exp(alpha1 + beta*t)) -      \
  np.log(1+np.exp(alpha2 + beta*t)) + C

# the initial guess for the function parameters:
p0 = [12, 6, 2, -4]
plt.plot(x, func(x, *p0))

popt, pcov = curve_fit(func, x, y, p0)

yfit = func(x, *popt)
plt.plot(x, yfit, 'r-')
plt.show()

以及拟合曲线(红色)和初始猜测(橙色):

曲线拟合

当然,您可以自由地尝试其他 sigmoid 函数,尤其是当您有理论上的理由假设某种特定形式时。在这种情况下,我使用的函数似乎很合适,因为中间的线性部分很长。

编辑:

而且,当然,将拟合曲线转换回原始(未转换)比例是微不足道的:

yfit_exp = 10**(func(np.log10(df.eps), *popt))
plt.loglog(df.eps, df.dist, 'x')
plt.loglog(df.eps, yfit_exp, 'r-')
plt.show()

曲线拟合原始比例