scipy 使用numpy/python外推数据

yrwegjxp  于 2023-01-26  发布在  Python
关注(0)|答案(6)|浏览(152)

假设我有一个简单的数据集,它可能是字典形式的,如下所示:
{1:5, 2:10, 3:15, 4:20, 5:25}
(the我想做的是从逻辑上找出数据的下一个点最有可能是什么,例如,在本例中,它将是{6: 30}
做这件事最好的办法是什么?

evrscar2

evrscar21#

你也可以使用numpy的polyfit

data = np.array([[1,5], [2,10], [3,15], [4,20], [5,25]])
fit = np.polyfit(data[:,0], data[:,1] ,1) #The use of 1 signifies a linear fit.

fit
[  5.00000000e+00   1.58882186e-15]  #y = 5x + 0

line = np.poly1d(fit)
new_points = np.arange(5)+6

new_points
[ 6, 7, 8, 9, 10]

line(new_points)
[ 30.  35.  40.  45.  50.]

这使您可以很容易地更改多项式拟合的次数,因为函数polyfit采用以下参数np.polyfit(x data, y data, degree)。显示的是一个线性拟合,其中返回的数组对于任何次数n都类似于fit[0]*x^n + fit[1]*x^(n-1) + ... + fit[n-1]*x^0poly1d函数允许您将此数组转换为一个函数,该函数返回多项式在任何给定值x处的值。
一般来说,没有一个很好理解的模型外推最多只能得到零星的结果。
指数curve fitting

from scipy.optimize import curve_fit

def func(x, a, b, c):
    return a * np.exp(-b * x) + c

x = np.linspace(0,4,5)
y = func(x, 2.5, 1.3, 0.5)
yn = y + 0.2*np.random.normal(size=len(x))

fit ,cov = curve_fit(func, x, yn)
fit
[ 2.67217435  1.21470107  0.52942728]         #Variables

y
[ 3.          1.18132948  0.68568395  0.55060478  0.51379141]  #Original data

func(x,*fit)
[ 3.20160163  1.32252521  0.76481773  0.59929086  0.5501627 ]  #Fit to original + noise
bf1o4zei

bf1o4zei2#

在Python聊天中和你讨论过之后--你将你的数据拟合成指数。这应该给予一个相对较好的指标,因为你不需要长期的外推。

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

def exponential_fit(x, a, b, c):
    return a*np.exp(-b*x) + c

if __name__ == "__main__":
    x = np.array([0, 1, 2, 3, 4, 5])
    y = np.array([30, 50, 80, 160, 300, 580])
    fitting_parameters, covariance = curve_fit(exponential_fit, x, y)
    a, b, c = fitting_parameters
    
    next_x = 6
    next_y = exponential_fit(next_x, a, b, c)
    
    plt.plot(y)
    plt.plot(np.append(y, next_y), 'ro')
    plt.show()

最右侧轴中的红点显示下一个“预测”点。

az31mfrm

az31mfrm3#

正如本文answer对一个相关问题所指出的,在scipy的0.17.0版本中,scipy.interpolate.interp1d中有一个选项允许线性外推。

>>> import numpy as np
>>> from scipy import interpolate

>>> x = [1, 2, 3, 4, 5]
>>> y = [5, 10, 15, 20, 25]
>>> f = interpolate.interp1d(x, y, fill_value = "extrapolate")
>>> print(f(6))
30.0
dphi5xsq

dphi5xsq4#

由于数据近似为线性,因此可以使用linear regression,然后使用y = w[0]*x + w[1](保留链接示例中 y = mx + B 的符号),使用回归结果计算下一个点。
如果你的数据不是近似线性的,并且你没有其他的回归理论形式,那么一般的外推(比如多项式或样条)就不太可靠,因为它们可能会超出已知的数据点而变得有点疯狂。例如,请参见公认的答案here

khbbv19g

khbbv19g5#

使用scipy.interpolate.splrep

>>> from scipy.interpolate import splrep, splev
>>> d = {1:5, 2:10, 3:15, 4:20, 5:25}
>>> x, y = zip(*d.items())
>>> spl = splrep(x, y, k=1, s=0)
>>> splev(6, spl)
array(30.0)
>>> splev(7, spl)
array(35.0)
>>> int(splev(7, spl))
35
>>> splev(10000000000, spl)
array(50000000000.0)
>>> int(splev(10000000000, spl))
50000000000L

参见How to make scipy.interpolate give an extrapolated result beyond the input range?

tp5buhyn

tp5buhyn6#

如果您不想依赖scipy,下面是使用***only***numpy的一个有趣示例:

from numpy.polynomial.polynomial import polyfit, polyval
from numpy import interp, ndarray, piecewise

def interp1d(x: ndarray, xp, fp):
    """1D piecewise linear interpolation with linear extrapolation."""
    return piecewise(
        x,
        [x < xp[0], (x >= xp[0]) & (x <= xp[-1]), x > xp[-1]],
        [
            lambda xi: polyval(xi, polyfit(xp[:2], fp[:2], 1)),
            lambda xi: interp(xi, xp, fp),
            lambda xi: polyval(xi, polyfit(xp[-2:], fp[-2:], 1)),
        ],
    )

它使用普通的numpy.interp进行插值,恢复为线性polynomial fit以外推超出边界的值,并使用numpy.piecewise将它们串在一起。
除了polyval(..., polyfit(...)),您还可以自己编写线性外推函数,例如:

lambda xi: fp[0] + np.diff(fp[:2]) / np.diff(xp[:2]) * (xi - xp[0])

等等。

相关问题