2013-10-16 17 views
7

Diciamo che ho un semplice set di dati. Forse in forma dizionario, sarebbe simile a questa:estrapolando dati con numpy/python

{1:5, 2:10, 3:15, 4:20, 5:25}

(l'ordine è sempre ascendente). Quello che voglio fare è capire logicamente quale sarà il probabile punto successivo di dati. Nel caso, ad esempio, sarebbe {6: 30}

quale sarebbe il modo migliore per farlo?

+0

possibile duplicato di [Come fare scipy.interpolate dare un risultato estrapolata al di là del campo di ingresso?] (Http: // StackOverflow.com/domande/2745329/how-to-make-SciPy-interpolare-dare-an-estrapolato-risultato-là-the-input-gamma) – Yoann

+1

I dizionari sono collezioni non ordinate, così il vostro "ordine sempre ascendente" osservazione può essere un ipotesi pericolosa, dal momento che 'for key in d' itererà sui tasti, ma Python lo ritiene opportuno, non nell'ordine in cui li hai creati. – Jaime

+1

Intendevo di più in termini di dati, poiché in ogni chiave numericamente più alta ha un valore numericamente più alto – corvid

risposta

3

Dopo aver discusso con te nella chat Python, e il montaggio dei dati su un esponenziale. Questo dovrebbe dare un indicatore relativamente buono poiché non stai cercando un'estrapolazione a lungo termine.

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() 

Il punto rosso nell'asse all'estrema destra mostra il prossimo punto "previsto".

1

Dal momento che i vostri dati è approssimativamente lineare si può fare un linear regression, e quindi utilizzare i risultati di tale regressione per calcolare il punto successivo, utilizzando y = w[0]*x + w[1] (mantenendo la notazione dall'esempio collegato per y = mx + b).

Se i dati non sono approssimativamente lineari e non si dispone di qualche altra forma teorica per una regressione, le estrapolazioni generali (usando dire polinomi o spline) sono molto meno affidabili in quanto possono andare un po 'pazze oltre i dati noti punti. Ad esempio, vedere la risposta accettata here.

0

Utilizzando 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 

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

+4

Prestare attenzione all'utilizzo delle spline per estrapolare. Tendono a "overshoot" alle estremità. È molto, molto facile ottenere l'estrapolazione per stimare gli ordini di grandezza più grandi o più piccoli dei tuoi dati usando le spline. Sono ottimi per l'interpolazione, ma una scelta molto scarsa per l'estrapolazione. –

5

È inoltre possibile utilizzare di NumPy polyfit: si

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.] 

Questo permette di modificare il grado del polinomio abbastanza facilmente come la funzione polyfit prendono i seguenti argomenti np.polyfit(x data, y data, degree). Viene mostrato un adattamento lineare in cui l'array restituito assomiglia a fit[0]*x^n + fit[1]*x^(n-1) + ... + fit[n-1]*x^0 per qualsiasi grado n. La funzione poly1d consente di trasformare questo array in una funzione che restituisce il valore del polinomio a qualsiasi valore x.

In generale l'estrapolazione senza un modello ben compreso avrà risultati sporadici nella migliore delle ipotesi.


Esponenziale 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 
+0

grazie signore, ma se non ti dispiace chiederti, qual è esattamente la variabile "adatta"? Come in, cosa significa? – corvid

+1

@Crowz - È un modello lineare. Come dice il commento di Ophion, è 'y = fit [0] * x + fit [1]'. –

+0

ci sarebbe un modo per implicare un modello che segue un percorso più esponenziale? – corvid

3

Come indicato da questo answer a una domanda correlata, a partire dalla versione 0.17.0 di scipy, esiste un'opzione in scipy.interpolate.interp1d che consente l'estrapolazione lineare. Nel tuo caso, si potrebbe fare:

>>> 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