37

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

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

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

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

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

4

7 回答 7

30

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

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
于 2012-04-06T20:23:54.543 回答
24

Keith 提供的链接或 Riaz 提供的答案可能会帮助您获得 polyfit,但如果可用,始终建议使用库,对于您手中的问题,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
>>> 
于 2012-04-06T20:33:10.607 回答
7

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

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

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

于 2012-04-06T20:04:57.517 回答
6

您可以对数据进行最小二乘拟合

使用此页面中的公式:

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)

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

于 2012-04-06T19:59:11.890 回答
4

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

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

于 2012-04-06T20:06:02.807 回答
2

您可以使用 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

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

于 2012-04-06T22:27:04.093 回答
-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
于 2012-04-06T20:50:42.900 回答