Python:在一组数字中找到趋势

时间:2012-04-06 19:56:05

标签: python math

我在Python中有一个数字列表,如下所示:

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

找到这些数字趋势的最佳方法是什么?我不想预测下一个数字是什么,我只想输出多组数字的趋势,以便我可以比较趋势。

编辑:根据趋势,我的意思是我想要一个数字表示数字是增加还是减少以及以什么速度增加。我不是大量的数学,所以可能有一个合适的名字!

编辑2:看起来我真正想要的是线性最佳拟合的系数。在Python中获取此功能的最佳方法是什么?

7 个答案:

答案 0 :(得分:21)

可能你的意思是你想在图表上绘制这些数字并找到一条直线,直线与数字之间的总距离最小化?这称为线性回归

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

趋势线不太可能通过您的原始点,但它将尽可能接近直线可以得到的原始点。使用此趋势线(a,b)的渐变和截距值,您将能够推断出超出数组末尾的直线:

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

答案 1 :(得分:13)

Keith提供的链接或者Riaz的答案可能会帮助您获得多重拟合,但总是建议使用库(如果可用),并且对于您手中的问题,numpy提供了一个很好的称为polyfit的多项式拟合函数。您可以使用polyfit来拟合任何等式的数据。

这是一个使用numpy将数据拟合为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
>>> 

类似地,二次拟合将是

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

答案 2 :(得分:6)

您可以执行least squares fit数据。

使用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)

打印最佳拟合线的起始值和增量。

答案 3 :(得分:4)

以下是获得增加/减少趋势的一种方法:

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

在结果列表trend中,trend[0]可以解释为从x[0]x[1]的增加,trend[1]将从{{1}增加} x[1]x[2]中的负值表示trend中的值从一个索引减少到下一个索引。

答案 4 :(得分:3)

我同意基思,我认为你可能正在寻找一个线性最小二乘拟合(如果你想知道的是数字通常是增加还是减少,以及以什么速率)。拟合的斜率将告诉您它们正以何种速度增加。如果您想要线性最小二乘拟合的直观表示,请尝试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

更新:如果您想在Python中实现线性回归,我建议从Mathworld的解释开始:

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

这是对算法的非常直接的解释,它实际上是自己编写的。特别是,你要密切注意方程16-21,27和28。

尝试自己编写算法,如果遇到问题,就应该打开另一个问题。

答案 5 :(得分:1)

您可以使用numpy找到OLS系数:

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, use range in Python3

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

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

结果:

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

由于趋势变量的系数为正,因此变量中的观测值会随着时间的推移而增加。

答案 6 :(得分:-1)

计算β系数。

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