我正在尝试创建一个平滑的函数来表示我正在使用的一些数据。问题是数据非常嘈杂,简单地使用最小二乘法来创建最佳拟合的多项式线效果并不好。
polynomial = np.polyfit(df.x,df.y)
进行一些挖掘,显然对于这类事情,有些人首先将输入数据转换为其自然对数,这会产生更好的曲线。
df['y']=np.log(df['y'])
lop_polynomial = np.polyfit(df.x,df.y)
你瞧,这似乎有效。当我将这个多项式转换成一个函数并绘制一堆点的图形(仅通过输出的 e^x )时,它看起来就是我想要的那种东西;
log_polynomial =np.poly1d(put_log_polynomial)
x_values = np.arange(0, 100,.01)
plt.plot(
x_values,
np.exp(log_polynomial (x_values ))
但是,这需要我将输入数据转换为日志数据,然后找到一个最佳拟合多项式,然后将该多项式转换为一个函数,然后将该函数转换为一堆离散点,然后制作另一个最佳拟合多项式这些点。因为这是我要运行很多次的事情,所以需要很多额外的步骤。
有没有一种方法可以采用我使用对数输入得到的多项式并将其转换回非对数空间,而无需手动对所有输入进行指数以获得离散点,然后尝试为这些点创建一条最适合的线在非日志空间?
编辑* 这是我的用例的更多背景信息。我有一组形成曲线的离散点。该曲线的二阶导数包含我想要干净地提取的重要信息,但如果我在不修改的情况下获取二阶导数,它最终会变得非常嘈杂,将曲线中的小扭结过度解释为二阶导数中巨大的粗糙尖峰。
我尝试了各种方法来平滑曲线,但我尝试过的所有其他方法要么未能充分解决噪声,要么破坏了我试图隔离的固有信号。这是我迄今为止尝试过的:
非对数空间中最佳拟合的最小二乘线
polynomial = np.polyfit(df.x,df.y)
一维高斯滤波器
scipy.ndimage.gaussian_filter1d(df.y, 3)
三次样条
t,c,k=scipy.interpolate.splrep(df.x,df.y,k=3)
B 样条
spline = scipy.interpolate.BSpline(t, c, k, extrapolate=False)
我在找到最佳拟合多项式之前尝试对它进行对数变换的原因是因为我发现一些研究论文使用这种插值方法来处理我正在研究的确切用例,当我在数据上测试它时,它似乎工作顺利。
*编辑2 正如@NickODell 敏锐地指出的那样,有很多潜在的多项式无法转换回非对数空间,并且仍然以 x 的整数次方系数列表的 python 多项式格式表示它们自己。因此,据我所知,这使得将对数空间多项式直接转换回非对数空间中的多项式实际上是不可能的。
我真正想要的是输入数据的二阶导数,它没有噪声并保留所有信号。我希望我能够通过将对数空间多项式直接转换回非对数空间并直接导出它来做到这一点,但显然这是不可能的。但是,它仍然可以表示为我可以使用 np.gradient 导出的函数,这将有效地允许相同的事情。但我不太相信这实际上会显着提高程序的效率。我会尝试进行一些分析,看看是否可以了解这是一笔多大的交易。
如果我正确理解您的要求,您想要:
y
轴上应用对数变换;x
点处的值。Sklearn 是通过
Pipeline
执行此类操作的完美软件包。
首先我们创建一些多项式噪声数据:
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
np.random.seed(12345)
x = np.linspace(-1, 1, 50).reshape(-1, 1)
P = np.poly1d([6, 5, 4, 3, 2, 10])
y = P(x[:, 0])
n = 0.5 * np.random.randn(y.size)
yn = y + n
作为基线,我们创建一个管道来从数据中线性回归多项式:
pipeline_lin = Pipeline([
("transformer", PolynomialFeatures(5)),
("model", LinearRegression(fit_intercept=False))
])
并适合数据集:
pipeline_lin.fit(x, y)
pipeline_lin["model"].coef_
# array([10.0226118 , 1.51830909, 2.23638955, 2.91665499, 5.99904944, 7.88614861])
如果您希望对目标(
y
轴,确实需要正数)应用对数变换,我们可以更改管道:
pipeline_log = Pipeline([
("transformer", PolynomialFeatures(5)),
("model",
TransformedTargetRegressor(
regressor=LinearRegression(fit_intercept=False),
func=np.log,
inverse_func=np.exp
)
)
])
pipeline_log.fit(x, yn)
pipeline_log["model"].regressor_.coef_
# array([ 2.2901081 , 0.15049063, 0.46685674, 0.32678866, -0.12522207, 0.34130133])
实际上,当我们应用对数变换时,系数与原始多项式并不直接相关。
现在我们可以预测其他特征的新目标值,而无需关心前向和后向对数变换:
xlin = np.linspace(-1, 1, 200).reshape(-1, 1)
yh_lin = pipeline_lin.predict(xlin)
yh_log = pipeline_log.predict(xlin)
fig, axe = plt.subplots()
axe.scatter(x, yn, marker=".", label="Data")
axe.plot(xlin, yh_lin, label="Linear")
axe.plot(xlin, yh_log, label="Log Linear")
axe.legend()
axe.grid()