Python: поиск тенденции в наборе чисел
У меня есть список чисел в Python, например:
x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
Какой лучший способ найти тренд в этих числах? Мне не интересно предсказать, каким будет следующий номер, я просто хочу вывести тренд для многих наборов чисел, чтобы я мог сравнивать тренды.
Изменить: По тренду, я имею в виду, что мне бы хотелось, чтобы числовое представление о том, увеличиваются или уменьшаются числа, и с какой скоростью. Я не массово математичен, поэтому, возможно, для этого есть правильное название!
Изменить 2: Похоже, что я действительно хочу, чтобы коэф. линейки наилучшим образом соответствовали. Какой лучший способ получить это в Python?
Ответы
Ответ 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