Подтвердить что ты не робот

Python: поиск тенденции в наборе чисел

У меня есть список чисел в Python, например:

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

Какой лучший способ найти тренд в этих числах? Мне не интересно предсказать, каким будет следующий номер, я просто хочу вывести тренд для многих наборов чисел, чтобы я мог сравнивать тренды.

Изменить: По тренду, я имею в виду, что мне бы хотелось, чтобы числовое представление о том, увеличиваются или уменьшаются числа, и с какой скоростью. Я не массово математичен, поэтому, возможно, для этого есть правильное название!

Изменить 2: Похоже, что я действительно хочу, чтобы коэф. линейки наилучшим образом соответствовали. Какой лучший способ получить это в Python?

4b9b3361

Ответ 1

Возможно, вы имеете в виду, что хотите нарисовать эти числа на графике и найти прямую линию, через которую минимизируется общее расстояние между линией и цифрами? Это называется линейной регрессией

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

Ответ 2

Ссылка, предоставленная Кейтом или, возможно, ответ от 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
>>> 

Ответ 3

Вы можете сделать наименьшие квадраты подгонки данных.

Используя формулу из этой страницы:

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)

Что печатает начальное значение и дельта наилучшей линии соответствия.

Ответ 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] будет увеличение от x[1] до x[2] и т.д. Отрицательные значения в trend означает, что значение в x уменьшилось с одного индекса на следующий.

Ответ 5

Я согласен с Кейтом, я думаю, что вы, вероятно, ищете линейную привязку наименьших квадратов (если все, что вы хотите знать, это если цифры, как правило, увеличиваются или уменьшаются, и с какой скоростью). Наклон подгонки скажет вам, с какой скоростью они растут. Если вы хотите визуальное представление линейной привязки наименьших квадратов, попробуйте 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.

Попробуйте написать алгоритм самостоятельно, и если у вас есть проблемы, вы должны открыть другой вопрос.

Ответ 6

Коэффициент OLS можно найти с помощью 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)

Результаты:

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

Так как коэффициент на трендовой переменной положителен, наблюдения в вашей переменной со временем увеличиваются.

Ответ 7

Вычислить бета-коэффициент.

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