2012-04-06 12 views
19

tengo una lista de números en Python, así:Python: Encontrar una tendencia en un conjunto de números

x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 

¿Cuál es la mejor manera de encontrar la tendencia en estos números? No estoy interesado en predecir cuál será el próximo número, solo quiero generar la tendencia para muchos conjuntos de números para poder comparar las tendencias.

Editar: Por tendencia, quiero decir que me gustaría obtener una representación numérica de si los números están aumentando o disminuyendo ya qué velocidad. No soy masivamente matemático, ¡así que probablemente haya un nombre propio para esto!

Editar 2: Parece que lo que realmente quiero es el coeficiente del mejor ajuste lineal. ¿Cuál es la mejor manera de obtener esto en Python?

+4

¿Qué quiere decir con "tendencia"? –

+0

Lo siento David - He actualizado mi pregunta con más detalle. –

+1

Me gusta la pregunta. La respuesta debe ser una función que tome una lista y escuche un solo número, ¿no? – gseattle

Respuesta

18

Posiblemente quiere decir que quiere trazar estos números en un gráfico y encontrar una línea recta a través de ellos donde la distancia total entre la línea y los números se reduce al mínimo?Esto se llama una regresión lineal

def linreg(X, Y): 
    """ 
    return a,b in solution to y = ax + b such that root mean square distance between trend line and original points is minimized 
    """ 
    N = len(X) 
    Sx = Sy = Sxx = Syy = Sxy = 0.0 
    for x, y in zip(X, Y): 
     Sx = Sx + x 
     Sy = Sy + y 
     Sxx = Sxx + x*x 
     Syy = Syy + y*y 
     Sxy = Sxy + x*y 
    det = Sxx * N - Sx * Sx 
    return (Sxy * N - Sy * Sx)/det, (Sxx * Sy - Sx * Sxy)/det 


x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 
a,b = linreg(range(len(x)),x) //your x,y are switched from standard notation 

La línea de tendencia es poco probable que pase a través de sus puntos originales, pero será lo más cerca posible a los puntos originales que una línea recta puede conseguir. Usando los valores de gradiente y la intersección de esta línea de tendencia (a, b) que será capaz de extrapolar la línea más allá del final de la matriz:

extrapolatedtrendline=[a*index + b for index in range(20)] //replace 20 with desired trend length 
+0

Tal vez debería ser 'zip (X, Y)' en lugar de 'map (None, X, Y)' –

+0

tienes razón, zip es mejor –

+0

Ahora, no sé mucho sobre las matemáticas aquí, pero Probé esto extensamente y fue * no * correcto, no encontró el desplazamiento correcto de 'b' ni su pendiente 'a' fue remotamente correcta. [Este enlace] (http://jmduke.com/posts/basic-linear-regressions-in-python/) me dio un resultado razonable. – 2rs2ts

6

Puede hacer un least squares fit de los datos.

Utilizando la fórmula de this page:

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 
N = len(y) 
x = range(N) 
B = (sum(x[i] * y[i] for i in xrange(N)) - 1./N*sum(x)*sum(y))/(sum(x[i]**2 for i in xrange(N)) - 1./N*sum(x)**2) 
A = 1.*sum(y)/N - B * 1.*sum(x)/N 
print "%f + %f * x" % (A, B) 

que imprime el valor inicial y el delta de la línea de mejor ajuste.

+2

Hacer un ajuste requiere que conozcas la forma funcional (la "tendencia") por adelantado, sin embargo. A menos que quiera adivinar y verificar funciones aleatorias, pero el espacio de todas las funciones posibles es infinito, por lo que no hay manera de que usted sepa que lo hizo bien. –

+0

@David: seguro, pero solo está definiendo el problema de tal manera que es imposible de resolver. "tendencia" significa algo para el afiche. Probablemente solo un ajuste lineal. –

+0

Negativo. ¿Cómo podrías hacer eso con solo una variable? – luke14free

3

Aquí es una manera de obtener una/tendencia a la disminución cada vez mayor:

>>> x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 
>>> trend = [b - a for a, b in zip(x[::1], x[1::1])] 
>>> trend 
[22, -5, 9, -4, 17, -22, 5, 13, -13, 21, 39, -26, 13] 

En la lista resultante trend, trend[0] se puede interpretar como el aumento entre x[0] a x[1], trend[1] sería el aumento con respecto x[1] a x[2] etc. Los valores negativos en trend significan que el valor en x disminuyó de un índice al siguiente.

3

Estoy de acuerdo con Keith, creo que probablemente esté buscando un ajuste lineal de mínimos cuadrados (si todo lo que quiere saber es si los números en general aumentan o disminuyen, ya qué velocidad). La pendiente del ajuste te dirá a qué velocidad están aumentando. Si desea una representación visual de un lineal de mínimos cuadrados, trate de Wolfram Alpha:

http://www.wolframalpha.com/input/?i=linear+fit+%5B12%2C+34%2C+29%2C+38%2C+34%2C+51%2C+29%2C+34%2C+47%2C+34%2C+55%2C+94%2C+68%2C+81%5D

Actualización: Si desea implementar una regresión lineal en Python, yo recomiendo empezar con la explicación en Mathworld:

http://mathworld.wolfram.com/LeastSquaresFitting.html

es una explicación muy sencilla del algoritmo, y prácticamente se escribe sola. En particular, debe prestar mucha atención a las ecuaciones 16-21, 27 y 28.

Intente escribir el algoritmo usted mismo, y si tiene problemas, debe abrir otra pregunta.

+0

Enlace impresionante. Creo que lo que quiero es el coeficiente del mejor ajuste lineal de mínimos cuadrados. No me molesta demasiado el desplazamiento. ¿Hay alguna manera fácil de hacer esto en Python? –

11

el enlace proporcionado por Keith o probablemente la respuesta de Riaz podría ayudar usted para obtener el ajuste poli, pero siempre se recomienda utilizar bibliotecas, si está disponible, y para el problema en su mano, numpy proporciona una maravillosa función de ajuste polinomial llamada polyfit. Puede usar polyfit para ajustar los datos en cualquier grado de ecuación.

Aquí se muestra un ejemplo usando numpy para ajustar los datos en una ecuación lineal de la forma y = ax + b

>>> data = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 
>>> x = np.arange(0,len(data)) 
>>> y=np.array(data) 
>>> z = np.polyfit(x,y,1) 
>>> print "{0}x + {1}".format(*z) 
4.32527472527x + 17.6 
>>> 

de manera similar un ajuste cuadrático sería

>>> print "{0}x^2 + {1}x + {2}".format(*z) 
0.311126373626x^2 + 0.280631868132x + 25.6892857143 
>>> 
-1

calcular el coeficiente beta .

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 
x = range(1,len(y)+1) 

def var(X): 
    S = 0.0 
    SS = 0.0 
    for x in X: 
     S += x 
     SS += x*x 
    xbar = S/float(len(X)) 
    return (SS - len(X) * xbar * xbar)/(len(X) -1.0) 

def cov(X,Y): 
    n = len(X) 
    xbar = sum(X)/n 
    ybar = sum(Y)/n 
    return sum([(x-xbar)*(y-ybar) for x,y in zip(X,Y)])/(n-1) 


def beta(x,y): 
    return cov(x,y)/var(x) 

print beta(x,y) #4.34285714286 
1

puede encontrar el coeficiente MCO utilizando numpy:

import numpy as np 

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81] 

x = [] 
x.append(range(len(y)))     #Time variable 
x.append([1 for ele in xrange(len(y))]) #This adds the intercept 

y = np.matrix(y).T 
x = np.matrix(x).T 

betas = (x.T*x).I*x.T*y) 

Resultados:

>>> betas 
matrix([[ 4.32527473], #coefficient on the time variable 
     [ 17.6  ]]) #coefficient on the intercept 

Dado que el coeficiente de la variable de tendencia es positiva, las observaciones en la variable están aumentando con el tiempo .

Cuestiones relacionadas